// Contract: CUSD
// Target function: function withdrawNft(address token_, address destination_, uint256 tokenId_) external onlyOwner
tokenId` token must be owned by `from`.
    * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
    *
    * Emits a {Transfer} event.
    */
  function transferFrom(
    address from,
    address to,
    uint256 tokenId
  ) external;
}

/**
 * @dev Collection of functions related to the address type
 */
library Address {
   /**
   * @dev Returns true if `account` is a contract.
   *
   * [IMPORTANT]
   * ====
   * It is unsafe to assume that an address for which this function returns
   * false is an externally-owned account (EOA) and not a contract.
   *
   * Among others, `isContract` will return false for the following
   * types of addresses:
   *
   * - an externally-owned account
   * - a contract in construction
   * - an address where a contract will be created
   * - an address where a contract lived, but was destroyed
   * ====
   *
   * [IMPORTANT]
   * ====
   * You shouldn't rely on `isContract` to protect against flash loan attacks!
   *
   * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
   * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
   * constructor.
   * ====
   */
   function isContract(address account) internal view returns (bool) {
     // This method relies on extcodesize/address.code.length, which returns 0
     // for contracts in construction, since the code is only stored at the end
     // of the constructor execution.

     return account.code.length > 0;
   }

   /**
   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
   * `recipient`, forwarding all available gas and reverting on errors.
   *
   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
   * of certain opcodes, possibly making contracts go over the 2300 gas limit
   * imposed by `transfer`, making them unable to receive funds via
   * `transfer`. {sendValue} removes this limitation.
   *
   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
   *
   * IMPORTANT: because control is transferred to `recipient`, care must be
   * taken to not create reentrancy vulnerabilities. Consider using
   * {ReentrancyGuard} or the
   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
   */
   function sendValue(address payable recipient, uint256 amount) internal {
     require(address(this).balance >= amount, "Address: insufficient balance");

     (bool success, ) = recipient.call{value: amount}("");
     require(success, "Address: unable to send value, recipient may have reverted");
   }

   /**
   * @dev Performs a Solidity function call using a low level `call`. A
   * plain `call` is an unsafe replacement for a function call: use this
   * function instead.
   *
   * If `target` reverts with a revert reason, it is bubbled up by this
   * function (like regular Solidity function calls).
   *
   * Returns the raw returned data. To convert to the expected return value,
   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
   *
   * Requirements:
   *
   * - `target` must be a contract.
   * - calling `target` with `data` must not revert.
   *
   * _Available since v3.1._
   */
   function functionCall(address target, bytes memory data) internal returns (bytes memory) {
     return functionCall(target, data, "Address: low-level call failed");
   }

   /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
   * `errorMessage` as a fallback revert reason when `target` reverts.
   *
   * _Available since v3.1._
   */
   function functionCall(
     address target,
     bytes memory data,
     string memory errorMessage
   ) internal returns (bytes memory) {
     return functionCallWithValue(target, data, 0, errorMessage);
   }

   /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
   * but also transferring `value` wei to `target`.
   *
   * Requirements:
   *
   * - the calling contract must have an ETH balance of at least `value`.
   * - the called Solidity function must be `payable`.
   *
   * _Available since v3.1._
   */
   function functionCallWithValue(
     address target,
     bytes memory data,
     uint256 value
   ) internal returns (bytes memory) {
     return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
   }

   /**
   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
   * with `errorMessage` as a fallback revert reason when `target` reverts.
   *
   * _Available since v3.1._
   */
   function functionCallWithValue(
     address target,
     bytes memory data,
     uint256 value,
     string memory errorMessage
   ) internal returns (bytes memory) {
     require(address(this).balance >= value, "Address: insufficient balance for call");
     require(isContract(target), "Address: call to non-contract");

     (bool success, bytes memory returndata) = target.call{value: value}(data);
     return verifyCallResult(success, returndata, errorMessage);
   }

   /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
   * but performing a static call.
   *
   * _Available since v3.3._
   */
   function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
     return functionStaticCall(target, data, "Address: low-level static call failed");
   }

   /**
   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
   * but performing a static call.
   *
   * _Available since v3.3._
   */
   function functionStaticCall(
     address target,
     bytes memory data,
     string memory errorMessage
   ) internal view returns (bytes memory) {
     require(isContract(target), "Address: static call to non-contract");

     (bool success, bytes memory returndata) = target.staticcall(data);
     return verifyCallResult(success, returndata, errorMessage);
   }

   /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
   * but performing a delegate call.
   *
   * _Available since v3.4._
   */
   function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
     return functionDelegateCall(target, data, "Address: low-level delegate call failed");
   }

   /**
   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
   * but performing a delegate call.
   *
   * _Available since v3.4._
   */
   function functionDelegateCall(
     address target,
     bytes memory data,
     string memory errorMessage
   ) internal returns (bytes memory) {
     require(isContract(target), "Address: delegate call to non-contract");

     (bool success, bytes memory returndata) = target.delegatecall(data);
     return verifyCallResult(success, returndata, errorMessage);
   }

   /**
   * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
   * revert reason using the provided one.
   *
   * _Available since v4.3._
   */
   function verifyCallResult(
     bool success,
     bytes memory returndata,
     string memory errorMessage
   ) internal pure returns (bytes memory) {
     if (success) {
        return returndata;
     } else {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
           // The easiest way to bubble the revert reason is using memory via assembly

           assembly {
             let returndata_size := mload(returndata)
             revert(add(32, returndata), returndata_size)
           }
        } else {
           revert(errorMessage);
        }
     }
   }
}

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {

  using Address for address;
 
  function safeTransfer(IERC20 token, address to, uint256 value ) internal {
    _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
  }


  /**
    * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
    * on the return value: the return value is optional (but if data is returned, it must not be false).
    * @param token The token targeted by the call.
    * @param data The call data (encoded using abi.encode or one of its variants).
    */
  function _callOptionalReturn(IERC20 token, bytes memory data) private {
    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
    // the target address contains contract code and also asserts for success in the low-level call.

    bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
    if (returndata.length > 0) {
      // Return data is optional
      require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }
  }
}

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
  function _msgSender() internal view returns (address payable) {
    return payable(msg.sender);
  }

  function _msgData() internal view returns (bytes memory) {
    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
    return msg.data;
  }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
  address private _owner;
  address private _newOwner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /**
   * @dev Initializes the contract setting the deployer as the initial owner.
   */
  constructor () {
    address msgSender = _msgSender();
    _owner = msgSender;
    emit OwnershipTransferred(address(0), msgSender);
  }

  /**
   * @dev Returns the address of the current owner.
   */
  function owner() public view returns (address) {
    return _owner;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(owner() == _msgSender(), "Ownable: caller is not the owner");
    _;
  }

  /**
   * @dev Accept the ownership transfer. This is to make sure that the contract is
   * transferred to a working address
   *
   * Can only be called by the newly transfered owner.
   */
  function acceptOwnership() public {
    require(_msgSender() == _newOwner, "Ownable: only new owner can accept ownership");
    address oldOwner = _owner;
    _owner = _newOwner;
    _newOwner = address(0);
    emit OwnershipTransferred(oldOwner, _owner);
  }

  /**
   * @dev Transfers ownership of the contract to a new account (`newOwner`).
   *
   * Can only be called by the current owner.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0), "Ownable: new owner is the zero address");
    _newOwner = newOwner;
  }
}

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotFrozen` and `whenFrozen`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context, Ownable {
  /**
   * @dev Emitted when the freeze is triggered by `account`.
   */
  event Frozen(address account);

  /**
   * @dev Emitted when the freeze is lifted by `account`.
   */
  event Unfrozen(address account);

  bool private _frozen;

  /**
   * @dev Initializes the contract in unfrozen state.
   */
  constructor () {
    _frozen = false;
  }

  /**
   * @dev Returns true if the contract is frozen, and false otherwise.
   */
  function frozen() public view returns (bool) {
    return _frozen;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is not frozen.
   *
   * Requirements:
   *
   * - The contract must not be frozen.
   */
  modifier whenNotFrozen() {
    require(!frozen(), "Freezable: frozen");
    _;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is frozen.
   *
   * Requirements:
   *
   * - The contract must be frozen.
   */
  modifier whenFrozen() {
    require(frozen(), "Freezable: frozen");
    _;
  }

  /**
   * @dev Triggers stopped state.
   *
   * Requirements:
   *
   * - The contract must not be frozen.
   */
  function _freeze() internal whenNotFrozen {
    _frozen = true;
    emit Frozen(_msgSender());
  }

  /**
   * @dev Returns to normal state.
   *
   * Requirements:
   *
   * - Can only be called by the current owner.
   * - The contract must be frozen.
   */
  function _unfreeze() internal whenFrozen {
    _frozen = false;
    emit Unfrozen(_msgSender());
  }
}

/**
 * @title Blacklistable Token
 * @dev Allows accounts to be blacklisted by a "blacklister" role
 */
contract Blacklistable is Context, Ownable {

  mapping(address => bool) internal _blacklisted;

  event Blacklisted(address indexed account_);
  event UnBlacklisted(address indexed account_);
  event BlacklisterChanged(address indexed newBlacklister_);

  /**
    * @dev Throws if argument account is blacklisted
    * @param account_ The address to check
    */
  modifier notBlacklisted(address account_) {
    require(!_blacklisted[account_], "Blacklistable: account is blacklisted");
    _;
  }

  /**
    * @dev Checks if account is blacklisted
    * @param account_ The address to check
    */
  function isBlacklisted(address account_) external view returns (bool) {
    return _blacklisted[account_];
  }

  /**
    * @dev Adds account to blacklist
    * @param account_ The address to blacklist
    */
  function blacklist(address account_) external onlyOwner {
    _blacklisted[account_] = true;
    emit Blacklisted(account_);
  }

  /**
    * @dev Removes account from blacklist
    * @param account_ The address to remove from the blacklist
    */
  function unBlacklist(address account_) external onlyOwner {
    _blacklisted[account_] = false;
    emit UnBlacklisted(account_);
  }
}

/**
 * @dev Enable owner to withdraw tokens that wrongly sent to the contract
 */
contract Withdrawable is Ownable {
  using SafeERC20 for IERC20;

  /// @dev Emit `Withdrawn` when owner withdraw fund from the contract
  event Withdrawn(address indexed owner, address indexed recipient, address indexed token, uint256 value);

  /// @dev withdraw token from contract
  /// @param token_ address of the token, use address(0) to withdraw gas token
  /// @param destination_ recipient address to receive the fund
  /// @param amount_ amount of fund to withdaw
  function withdraw(address token_, address destination_, uint256 amount_) external onlyOwner {
    require(destination_ != address(0), "Withdrawable: Destination is zero address");

    uint256 availableAmount;
    if(token_ == address(0)) {
      availableAmount = address(this).balance;
    } else {
      availableAmount = IERC20(token_).balanceOf(address(this));
    }

    require(amount_ <= availableAmount, "Withdrawable: Not enough balance");

    if(token_ == address(0)) {
      destination_.call{value:amount_}("");
    } else {
      IERC20(token_).safeTransfer(destination_, amount_);
    }

    emit Withdrawn(_msgSender(), destination_, token_, amount_);
  }