Hi @CryptoEatsTheWorld,
An ERC20 is primarily a list of balances for addresses, so you need to interact with each token contract to get the balance and to transfer.
You want to call balanceOf
on the token contract.
Depending on what tokens you are interacting with, you may want to use SafeERC20
wrapper.
You want to call IERC20 transfer
or SafeERC20 safeTransfer
I suggest creating a simple example to play with this. You can use the following to experiment with.
You would want to have Access Control so that only a privileged address could withdraw.
The following code has not been tested nor audited, so 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
Create a SimpleToken and MyContract.
Transfer amount of SimpleTokens to MyContract
Check balance of SimpleTokens in MyContract
Withdraw tokens from MyContract
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