繁体   English   中英

Solidity:从另一个具有相同 msg.sender 的合约调用合约函数

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

我有一个函数需要调用另一个合约的 transfer 方法。 我希望从原始调用者的地址而不是合约调用传输方法。 是否可以?

这是代码:

     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);

您当前的代码执行消息调用( docs )。 同一事物的另一个名称是EVM 调用 它使用目标合约的存储,而msg.sender是你的合约(不是原始交易发送者)。

如果您希望msg.sender成为原始交易发送者(用户),则需要使用委托调用( docs )。 但是……delegatecall 使用调用者的存储(您的合约;而不是被调用的合约),因此它主要用于代理合约。


出于安全原因,无法使用目标合约存储和原始发件人的msg.sender执行目标合约中的函数。

如果可能的话,理论上你可以从任何不/不能验证你的合约源代码的人那里窃取代币。 例子:

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

需要从某人那里转移资金是一种非常常见的模式,它被内置到 ERC20 规范中,并且几乎在所有 DeFi 合约中都有使用。

您需要使用的是transferFrom()而不是transfer() 它将“发件人”地址作为第一个参数,如果发送用户已批准您的合同转移他们的资金,则调用将成功。

在您的情况下,传输线将更改为:

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

发件人需要先批准您的合同。

这是 ERC20 规范。 https://eips.ethereum.org/EIPS/eip-20

如果你正在使用 ERC20s 并想从一个单独的合约中转移另一个账户的代币,正确的使用方法是transferFrom 这需要对调用transferFrom的合约给予allowance 这是通过使用approveincreaseAllowance允许(推荐后者)来完成的。

然而,一般来说,如果您希望在当前合约的上下文中调用另一个合约的方法,即使用相同的msg.sender (除其他外),您可以使用delegatecall 有关更多详细信息,请参阅https://docs.soliditylang.org/en/v0.8.11/types.html#address

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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