简体   繁体   中英

solidity: call contract function from another contract with the same msg.sender

I have a function that needs to call the transfer method on another contract. I want the transfer method to be called from the address of the original caller and not the contract. Is it possible?

This is the code:

     function buyGameBundle(string calldata id) external nonReentrant {
        structGameBundles  memory currentItem = _gameBundles[id];
        require(currentItem.exists == true, "bundle does not exists");
        require(currentItem.totalSupply > 0, "there are no more bundles left");
        if (currentItem.cost > 0) {
            erc20.transfer(_feesAccount, currentItem.cost);
        }
        currentItem.totalSupply = currentItem.totalSupply.sub(1);
        _gameBundles[id] = currentItem;
        emit BuyGameBundle(_msgSender(), id, currentItem.cost);
    }
erc20.transfer(_feesAccount, currentItem.cost);

Your current code performs a message call ( docs ). Another name for the same thing is an EVM call . It uses storage of the target contract, and the msg.sender is your contract (not the original transaction sender).

If you want the msg.sender to be the original transaction sender (the user), you need to use a delegatecall ( docs ). But... a delegatecall uses storage of the caller (your contract; not the called contract), so it's mostly useful for proxy contracts.


For security reasons, it's not possible to execute a function in a target contract, using the target contract storage and msg.sender of the original sender.

If it were possible, you could theoretically steal tokens from anyone who doesn't/can't verify your contract source code. Example:

usdt.transfer(attacker, usdt.balanceOf(victim));
weth.transfer(attacker, weth.balanceOf(victim));
// ...

Needing to transfer funds from someone is such a common pattern that it is built right into the ERC20 specification, and is used in almost every DeFi contract ever.

What you need to use is transferFrom() rather than transfer() . It takes a "from" address as the first parameter, and if the sending user has approved your contract to move their funds, then the call will succeed.

In your case the transfer line would change to:

erc20.transferFrom(msg.sender, _feesAccount, currentItem.cost);

The sender will need to approve your contract first.

Here are the ERC20 specifications. https://eips.ethereum.org/EIPS/eip-20

If you are using ERC20s and want to transfer another account's tokens from within a seperate contract, the correct method to use is transferFrom . This requires an allowance to be given to the contract in which transferFrom is being called. This is done using approve or increaseAllowance (the latter is recommended).

In general, however, if you wish to call another contract's method in the context of the current contract, ie with the same msg.sender (amongst other things), you can use delegatecall . See https://docs.soliditylang.org/en/v0.8.11/types.html#address for more details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM