0

Here is my code base, first I am deploying the tokenPS contract on the tesnet which generates an addr(0xaddr) and then I am deploying the caller contract. In caller contract when I am trying to execute the function with proper params it triggers the tokenPS contract but unable to trigger the transfer functn shows an error(check the txn hash and in that check internal txns-- https://ropsten.etherscan.io/tx/0xa74bde27c3ca86469ae0dc8b605aee9adb8a90a2a3cf0b2d9ff9ee517f8be8ed). What could be the issue and how to resolve this?

pragma solidity ^0.4.24;

contract Caller {
    
    event AddedValuesByDelegateCall(address from, address to, uint256 value, bool resp, bool success);
    
    function addValuesWithDelegateCall(address addr, address to, uint256 value) public payable returns (bool) {
        IERC20 x = IERC20(addr);
        (bool resp) = address(x).delegatecall(abi.encodeWithSignature("approve(address, uint256)", msg.sender, value));
        (bool success) = address(x).delegatecall(abi.encodeWithSignature("transferFrom(address, address, uint256)", msg.sender, to, value));
        emit AddedValuesByDelegateCall(msg.sender, to, value, resp, success);
        return success;
    }
    
}



// ----------------------------------------------------------------------------

interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);
    function approve(address spender, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
    function totalSupply() external view returns (uint256);
    function balanceOf(address who) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
// ------------------------------------------------------------------------
// ERC20 Token, with the addition of symbol, name and decimals supply and founder
// ------------------------------------------------------------------------
contract tokenPS is IERC20{
    string public name = "tokenPS";
    string public symbol = "TPS";
    uint8 public decimals = 6;
    uint public supply;
    address public founder;
    mapping(address => uint) public balances;
    mapping(address => mapping(address => uint)) allowed;
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint value);
    // ------------------------------------------------------------------------
    // Constructor With 10,00,000 supply, All deployed tokens sent to Main wallet
    // ------------------------------------------------------------------------
    constructor() public{
        supply = 1000000000000;
        founder = msg.sender;
        balances[founder] = supply;
    }
    // ------------------------------------------------------------------------
    // Returns the amount of tokens approved by the owner that can be
    // transferred to the spender's account
    // ------------------------------------------------------------------------
    function allowance(address owner, address spender) public view returns(uint){
        return allowed[owner][spender];
    }
    // ------------------------------------------------------------------------
    // Token owner can approve for spender to transferFrom(...) tokens
    // from the token owner's account
    // ------------------------------------------------------------------------
    function approve(address spender, uint value) public returns(bool){
        allowed[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }
    // ------------------------------------------------------------------------
    //  Transfer tokens from the 'from' account to the 'to' account
    // ------------------------------------------------------------------------
    function transferFrom(address from, address to, uint value) public returns(bool){
        require(allowed[from][msg.sender] >= value);
        require(balances[from] >= value);

        balances[from] -= value;
        balances[to] += value;
        allowed[from][msg.sender] -= value;

        emit Transfer(from, to, value);

        return true;
    }
    // ------------------------------------------------------------------------
    // Public function to return supply
    // ------------------------------------------------------------------------
    function totalSupply() public view returns (uint){
        return supply;
    }
    // ------------------------------------------------------------------------
    // Public function to return balance of tokenOwner
    // ------------------------------------------------------------------------
    function balanceOf(address tokenOwner) public view returns (uint balance){
        return balances[tokenOwner];
    }
    // ------------------------------------------------------------------------
    // Public Function to transfer tokens
    // ------------------------------------------------------------------------
    function transfer(address to, uint tokens) public returns (bool success){
        require(balances[msg.sender] >= tokens && tokens > 0);
        balances[to] += tokens;
        balances[msg.sender] -= tokens;
        emit Transfer(msg.sender, to, tokens);
        return true;
    }
    // ------------------------------------------------------------------------
    // Revert function to NOT accept ETH
    // ------------------------------------------------------------------------
    function () public payable {
        revert();
    }
}
0

You cannot call approve in a contract on behalf of a user. The first parameter of approve is the spender: the address of who or what is allowed to transfer funds for msg.sender. Specifying msg.sender as spender does not let your contract send tokens for msg.sender.

What you want to do instead is have the user send two transactions:

  1. First, an approve transaction to the token contract (as user), with the address of your contract, and an amount of tokens to approve.
  2. A transaction to your own contract, which calls transferFrom on the token contract. You don't need delegatecall for this, a regular function call will work.

There is no way to group these two transaction in a single transaction (at least with the ERC-20 standard).

| improve this answer | |
  • what do you mean by the first point? is it tokienPS(x).approve(msg.sender, amount)? – debo karmakar Sep 28 at 15:20
  • If you want to transfer tokens with your contract, you have to send a transaction with approve(contractAddress, amount) from the user's account. – Morten Sep 28 at 15:37

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.