Solidity Tokens – How to Transfer ERC20 via Another Smart Contract (Delegatecall)

delegatecallsoliditytokens

I want to deposit erc20 tokens to a smart contract. But when I just send it to he address, I can't handle the deposit. So I tried to use the delegatecall function to do the transfer.

Basically I thought of something like deposit(uint amount) and the contract then handles the transaction.

I used this example to test if the delegatecall works. The transferTo function should send the token from the sender to addr, but the function fails:

contract TokenInterface {
function transfer(address _to, uint _value) public returns (bool success);
}

contract New {
    TokenInterface private token;
    constructor(address tokenAddr)public{
        token = TokenInterface(tokenAddr);
    }

    // This is just for testing. address(...).call(...) works fine
    function echoBalance(address addr) public returns(uint balance){
        (bool success, bytes memory result) = address(0x92...4f).call(abi.encodeWithSignature("balanceOf(address)", addr));
        return abi.decode(result, (uint));
    }

    // but address(...).delegatecall(...) fails. Same when replaced by call
    function transferTo(address addr, uint amount) public returns(bool success){
        (bool success, bytes memory result) = address(0x92...4f).delegatecall(abi.encodeWithSignature("transfer(address,uint)", addr, amount));
        return success;
        //return token.transfer(addr, amount); // only transfers from this smart contract to addr, but not from sender
            // addr would be the smart contract itself in the deposit scenario
    }
}

The code is partially based o this post:
ERC20 token withdrawal from smart contract

I tried it in remix.ethereum.org.

When I understand it right, .call should send the token from the contracts address and .delegatecall should send it from the msg.sender address.

The best way would be to use something like token.transfer(addr, amount) but with senders address instead of the contracts address. Is this possible?
If not: how can I make the address(…).delegatecall(…) work?

Or is this scenario handled in another way?

I know that it can be done by using transferFrom but this requires an additionnal approve action by the caller, which I'd like to avoid.

EDIT:

I found out, that delegatecall does not what I thought it would.

Is is possible to use one contract from another and act like the user who called the function, at all?

If not: Is it possible to do what i want to do?

Best Answer

As far as I know its not possible. You can call another contract (B), with your contract (A) as sender, but you can't act as someone else. With delegate call, you use the function of another contact (B) in the context of the caller (A). So it is like copying the code of the function from B to A.

I guess it is impossible by design, because otherwise a simple call to a malicious contract could steal all your tokens (if you don't analize every contract you call)

Related Topic