SafeERC20, TokenTimelock, wrappers

erc20

#1

Hey everyone, I was wondering: why are there wrapper contracts such as SafeERC20 and TokenTimelock? Why aren’t these children of another contract instead?
Also… Does anyone have a working example of a SafeERC20? I just tried to create a wrapper of my token and integrate the unit tests of the ERC20, but even the most basic ERC20 function isn’t working anymore (TypeError: this.token.balanceOf is not a function)

All I did was actually to take a SafeERC20Wrapper from SafeERC20Helpers (also I removed the irrelevant parts), applying the ERC20 tests, and replacing the ERC20Mock by SafeERC20 wrapping the ERC20Mock in the tests:

		this.token = await SafeERC20.new(
			(await ERC20Mock.new(initialHolder, initialSupply)).address
		);

Thanks!


#2

Welcome @tnguyen42!

That isn’t how SafeERC20 is used. It’s often misunderstood though, so we’re going to write a guide about it.

SafeERC20 is not an ERC20 extension that you use to make your token safe (OpenZeppelin’s ERC20 is already safe :slightly_smiling_face:). It’s a helper to make safe the interaction with someone else’s ERC20 token, in your contracts.

What the helper does for you is

  1. check the boolean return values of ERC20 operations and revert the transaction if they fail,
  2. at the same time allowing you to support some non-standard ERC20 tokens that don’t have boolean return values.

It additionally provides helpers to increase or decrease an allowance, to mitigate an attack possible with vanilla approve.


As an example, let’s create a contract that needs to interact with a token. It will allow people to put tokens on sale for a fixed price, so that buyers can later come and buy from them. There are a couple of token transfers that we have to perform, so we will use SafeERC20 for those. Notice the line using SafeERC20 for IERC20, which allows us to use the safe operations on values of type IERC20, for example tradingToken.safeTransferFrom.

contract FixedPriceMarket {
    using SafeERC20 for IERC20;

    IERC20 tradingToken = 0x1234...;
    uint256 price = 128;

    mapping (address => uint256) selling;

    function sell(uint256 tokenValue) {
        tradingToken.safeTransferFrom(msg.sender, this, tokenValue);
        selling[msg.sender] = selling[msg.sender].add(tokenValue);
    }

    function buy(address seller, uint256 tokenValue) {
        require(msg.value == tokenValue.mul(price));
        selling[seller] = selling[seller].sub(tokenValue);
        tradingToken.safeTransfer(msg.sender, tokenValue);
        seller.transfer(msg.value);
    }
}

Again, welcome to the forum! Check out the intros thread and tell us a bit about you. :slight_smile: