2

I am having trouble with transfering ERC20 tokens in my smart contract. Code is below. Take a look at function hodl, I want to deposit any token to this smart contract, but although I make a transaction no tokens are transfered, I am not sure why because I do call transferFrom function. Tried with transfer as well in desperation but that's probably only for token smart contract transfers.

What I am trying to develop here is a smart contract that will accept a token deposit and hold it until a time limit defined by the user when making a transaction expires.

pragma solidity ^0.4.19;

contract ERC20Interface {
function totalSupply() public constant returns (uint);

function balanceOf(address tokenOwner) public constant returns (uint balance);

function allowance(address tokenOwner, address spender) public constant returns (uint remaining);

function transfer(address to, uint tokens) public returns (bool success);

function approve(address spender, uint tokens) public returns (bool success);

function transferFrom(address from, address to, uint tokens) public returns (bool success);

event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

contract hodlForYouContractV3 {

event Hodl(address indexed hodler, address token, uint  amount, uint timeLimit);

event PanicSell(address indexed hodler, address token, uint  amount, uint timediff);

event Withdrawal(address indexed hodler, address token, uint  amount);

struct Hodler {
    uint etherBalance;
    address hodler;
    mapping(address => Token) tokens;
}

struct Token {
    bytes32 symbol;
    uint tokenBalance;
    address tokenAddress;
    uint timeLimit;
}

mapping(address => Hodler) public hodlers;


function hodl(address token, byte tokenSymbol, uint256 amount, uint256 timeLimit) {

    hodlers[msg.sender] = Hodler(0, msg.sender);
    Hodler hodler = hodlers[msg.sender];
    hodler.tokens[token] = Token(tokenSymbol, amount, token, timeLimit);
    //        hodler.tokens[token].timeLimit = timeLimit;
    //        hodler.tokens[token].tokenBalance = amount;
    ERC20Interface(token).approve(msg.sender, amount);
    ERC20Interface(token).transfer(this, amount);
    ERC20Interface(token).transferFrom(msg.sender, this, amount);
    Hodl(msg.sender, token, amount, timeLimit);

}


function withdraw(address token) {
    Hodler hodler = hodlers[msg.sender];
    require(block.timestamp > hodler.tokens[token].timeLimit);

    uint amount = hodler.tokens[token].tokenBalance;
    hodler.tokens[token].tokenBalance = 0;
    ERC20Interface(token).approve(msg.sender, amount);
    ERC20Interface(token).transferFrom(this, msg.sender, amount);

    Withdrawal(msg.sender, token, amount);

}


function panicSell(address token) {
    //This function should have a fee for quicker withdrawing without waiting
    Hodler hodler = hodlers[msg.sender];

    uint amount = hodler.tokens[token].tokenBalance;
    hodler.tokens[token].tokenBalance = 0;
    ERC20Interface(token).approve(msg.sender, amount);
    ERC20Interface(token).transferFrom(this, msg.sender, amount);

    PanicSell(msg.sender, token, amount, hodler.tokens[token].timeLimit - block.timestamp);

}

}
  • hodlers[msg.sender] = Hodler(0, msg.sender); Your structure has 3 elements, you only give it two. Moreover, you did not implement the function for the token standard – Florian Castelain Jan 29 '18 at 2:28
  • 3 element parameter is a mapping which I handle on next line. What function for the token standard? – stevyhacker Jan 29 '18 at 2:31
  • 1
    @Andromelus Did you try it? You're allowed to initialize a struct like this. The value that's not specified just gets its default value. Also, there's no reason to implement the ERC20 token standard functions because this contract is not a token. – smarx Jan 29 '18 at 2:32
  • But he tries to use the functions without implementing them from what I understand – Florian Castelain Jan 29 '18 at 2:34
  • I am casting a token address to a token contract, functions are implemented in the tokens smart contract, at least that's what I read somewhere. – stevyhacker Jan 29 '18 at 2:37
2

This line doesn't make sense:

ERC20Interface(token).approve(msg.sender, amount);

There are two actors in an approve call: the token owner and the token spender.

The token owner calls approve(spender, amount) so that the spender can then spend those tokens.

Here, the contract is the token owner and the user who called the function is the spender.

I think what you want is for the user to call approve(contract, amount) before calling hodl, and then you want to do token.transferFrom(msg.sender, this, amount) to transfer those tokens from the user to the contract.

  • So I need to make these as two separate transactions to work properly and give permission to the contract to transfer tokens? – stevyhacker Jan 29 '18 at 2:32
  • Yes. Hopefully it's clear why this has to be the case: otherwise your contract could just steal tokens from anyone. :-) – smarx Jan 29 '18 at 2:33
  • Ok, thanks, I will test this now, implementing two functions like you suggested. I will have to worry about security of course but first to make it work at all :) – stevyhacker Jan 29 '18 at 2:35
  • 1
    The first call has to be the user calling approve on the token contract. – smarx Jan 29 '18 at 3:08
  • 2
    To clarify, the user should do tokenContract.approve(hodlContractAddress, amount) and then hodlContract.hodl(tokenContractAddress, ...). Inside the hodl function, you just call transferFrom. – smarx Jan 29 '18 at 3:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.