solidity:从另一个具有相同 msg.sender 的合约调用合约函数
solidity: call contract function from another contract with the same msg.sender
我有一个函数需要调用另一个合约的转账方法。
我希望从原始调用者的地址而不是合约调用传输方法。
可能吗?
这是代码:
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 调用。它使用 target 合约的存储,msg.sender
是你的合约(不是原始交易发送者)。
如果您希望msg.sender
成为原始交易发送者(用户),您需要使用delegatecall(docs)。但是... delegatecall 使用调用者的存储(你的合约;不是被调用的合约),所以它对代理合约最有用。
出于安全原因,无法使用目标合约存储和原始发送者的 msg.sender
在目标合约中执行功能。
如果可能的话,理论上你可以从任何不t/can不验证你的合约源代码的人那里窃取代币。示例:
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
如果您正在使用 ERC20 并想从一个单独的合约中转移另一个帐户的代币,正确的使用方法是 transferFrom
。这需要向调用 transferFrom
的合约提供 allowance
。这是使用 approve
或 increaseAllowance
完成的(推荐后者)。
然而,一般来说,如果你想在当前合约的上下文中调用另一个合约的方法,即使用相同的msg.sender
(除其他外),你可以使用delegatecall
。有关详细信息,请参阅 https://docs.soliditylang.org/en/v0.8.11/types.html#address。
我有一个函数需要调用另一个合约的转账方法。 我希望从原始调用者的地址而不是合约调用传输方法。 可能吗?
这是代码:
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 调用。它使用 target 合约的存储,msg.sender
是你的合约(不是原始交易发送者)。
如果您希望msg.sender
成为原始交易发送者(用户),您需要使用delegatecall(docs)。但是... delegatecall 使用调用者的存储(你的合约;不是被调用的合约),所以它对代理合约最有用。
出于安全原因,无法使用目标合约存储和原始发送者的 msg.sender
在目标合约中执行功能。
如果可能的话,理论上你可以从任何不t/can不验证你的合约源代码的人那里窃取代币。示例:
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
如果您正在使用 ERC20 并想从一个单独的合约中转移另一个帐户的代币,正确的使用方法是 transferFrom
。这需要向调用 transferFrom
的合约提供 allowance
。这是使用 approve
或 increaseAllowance
完成的(推荐后者)。
然而,一般来说,如果你想在当前合约的上下文中调用另一个合约的方法,即使用相同的msg.sender
(除其他外),你可以使用delegatecall
。有关详细信息,请参阅 https://docs.soliditylang.org/en/v0.8.11/types.html#address。