Example of withdrawing an ERC20 from another contract

The following is a simple example of withdrawing an ERC20 from a contract.

You should have Access Control so that only a privileged address could withdraw.

:warning: The following code has not been tested nor audited, so please don’t use in production.

SimpleToken.sol

// contracts/SimpleToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
 * @title SimpleToken
 * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
 * Note they can later distribute these tokens as they wish using `transfer` and other
 * `ERC20` functions.
 * Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/examples/SimpleToken.sol
 */
contract SimpleToken is ERC20 {
    /**
     * @dev Constructor that gives msg.sender all of existing tokens.
     */
    constructor(
        string memory name,
        string memory symbol,
        uint256 initialSupply
    ) public ERC20(name, symbol) {
        _mint(msg.sender, initialSupply);
    }
}

MyContract.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/GSN/Context.sol";

contract MyContract is Context, AccessControl {

    using SafeERC20 for IERC20;

    bytes32 public constant WITHDRAWER_ROLE = keccak256("WITHDRAWER_ROLE");

    constructor() public  {
        _setupRole(WITHDRAWER_ROLE, _msgSender());
    }

    function withdraw(IERC20 token, address recipient, uint256 amount) public {
        require(hasRole(WITHDRAWER_ROLE, _msgSender()), "MyContract: must have withdrawer role to withdraw");
        token.safeTransfer(recipient, amount);
    }
}

Interact

  1. Create a SimpleToken and MyContract.
  2. Transfer amount of SimpleTokens to MyContract
  3. Check balance of SimpleTokens in MyContract
  4. Withdraw tokens from MyContract
  5. Check balances
$ npx truffle develop
Truffle Develop started at http://127.0.0.1:9545/
...

truffle(develop)> token = await SimpleToken.new("Simple Token", "SIM", "100000000000000000000")
undefined
truffle(develop)> myContract = await MyContract.new()
undefined
truffle(develop)> await token.transfer(myContract.address, "100000000000000000000")
{ tx:
...
truffle(develop)> (await token.balanceOf(myContract.address)).toString()
'100000000000000000000'
truffle(develop)> await myContract.withdraw(token.address, accounts[1], "100000000000000000")
{ tx:
...
truffle(develop)> (await token.balanceOf(accounts[1])).toString()

As an aside, to use an ERC20 in a contract, please see: Example on how to use ERC20 token in another contract

7 posts were merged into an existing topic: Contracts holding tokens

5 posts were split to a new topic: How to withdraw Ether from a contract

Is this an example that a dapp could use to allow users to withdraw?