0

NOTICE: The below implementation works. It assumes that the calling addresse has approved both the spender and the contract to carry the transaction. Because they were not approved it was not working.

I am using this smart contract which is supposed to accept ERC20Tokens and it would allow me to send them to a different address. For instance, the smart contract allows users to send their erc20tokens which will be forwarded to the provided address.

I tried different ERC20Tokens that I created however the smart contract always returns a transaction failed event. When I call the transferTokens() function it fails the transaction. The smart contract:

pragma solidity ^0.4.24;
import "http://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";

contract SendableERC20{

 struct Transfer {
    address contract_;
    address to_;
    uint amount_;
    bool failed_;
 }
 mapping(address => uint[]) public transactionIndexesToSender;

 Transfer[] public transactions;
 address public owner;
 address invalidTo_; 
 mapping(string => address) tokens;
 IERC20 public IERC20Interface;
 event TransferSuccessful(address indexed from_, address indexed to_, uint256 amount_);

 event TransferFailed(address indexed from_, address indexed to_, uint256 amount_);

 constructor() public {
    owner = msg.sender;
 }
 function addNewToken(string symbol_, address address_) public onlyOwner returns(bool){
    tokens[symbol_] = address_;

    return true;
 }

 function removeToken(string symbol_) public onlyOwner returns(bool){
    require(tokens[symbol_] != 0x0);

    delete(tokens[symbol_]);

    return true;
 }
 function returnSymbol(string symbol_)public view returns(address){
    return(tokens[symbol_]);
 }
 function transferTokens(string symbol_, address to_, uint256 amount_) public {
    require(tokens[symbol_]!= 0x0);
    require(amount_ > 0);

    address contract_ = tokens[symbol_];
    address from_ = msg.sender;

    IERC20Interface = IERC20(contract_);

    uint256 transactionId = transactions.push(
        Transfer({
            contract_: contract_,
            to_: to_,
            amount_: amount_,
            failed_: true
        }));

    transactionIndexesToSender[from_].push(transactionId -1);

    if(amount_ > IERC20Interface.allowance(from_, address(this))){
        emit TransferFailed(from_, to_, amount_);
        revert();
    }

    IERC20Interface.transferFrom(from_, to_, amount_);

    transactions[transactionId -1].failed_ = false;

    emit TransferSuccessful(from_, to_, amount_);
 }
 modifier onlyOwner(){
    require(msg.sender == owner);
    _;
 }



}

Must mention information:

I tried to accomplish it on Rinkeby using this token implementation (not mine but I retain it a great implementation since it uses SafeMath).

In the main smart contract which allows users to transfer their ERC20 tokens, I considered mapping tokens as bytes32 rather than string, however for the purpose of testing I implemented it as string in the smart contract provided.

I invite you to try the smart contract accessing this link on Remix which uses the same compiler as I used. Deploy both the contract and the token using Metamask on Rinkeby network. Make sure you give allowance to your address if you use the token that I provided. Then try to use SendableERC20 contract to send tokens from your Metamask wallet to another address and you will see that it will fail. The event "TransferFailed" will always be called for no reason.

I start believing that it's a logic error that I can't find.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.