如何通过另一个智能合约与已部署的 ERC20 令牌进行交互?
How to interact with the deployed ERC20 token with another smart-contract?
我通过在 ERC20.sol 文件中实施 OpenZeppelin 创建了一个基本的 ERC20 令牌:
pragma solidity ^0.6.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor(string memory _name, string memory _symbol)
public
ERC20(_name, _symbol)
{
_mint(msg.sender, 10000000000000000000000000000);
}
}
然后执行另一个合约Contract.sol如下:
import "./ERC20.sol";
pragma solidity ^0.6.4;
contract SimpleBank{
Token tokenContract;
constructor(Token _tokenContract) public {
tokenContract = _tokenContract;
}
function deposit(uint amt) public returns (bool) {
require(amt != 0 , "deposit amount cannot be zero");
tokenContract.transfer(address(this),amt);
return true;
}
}
因为,我已经从地址 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 部署了两个合约,所以它拥有 1000000000000000000000000000000 代币。
但是当我从同一地址调用 deposit
函数时,出现以下错误:
transact to SimpleBank.deposit errored: VM error: revert. revert The
transaction has been reverted to the initial state. Reason provided by
the contract: "ERC20: transfer amount exceeds balance". Debug the
transaction to get more information.
那么,与已部署的 ERC20 令牌进行交互的正确方法是什么,以便 deploy
功能起作用。
用户地址0xAb8483...
发送交易执行SimpleBank
的函数deposit()
,使得0xAb8483...
成为msg.sender
的值] 在 SimpleBank
.
但是随后 SimpleBank
发送一个内部事务执行 Token
的函数 transfer()
。这使得 SimpleBank
地址(不是 0xAb8483...
) 成为 Token
.
中 msg.sender
的值
所以 SimpleBank 中的片段 tokenContract.transfer(address(this),amt);
正在尝试发送 SimpleBank
的令牌。不是用户的 (0xAb8483...
) 代币。
此代币转移(从第 2 点开始)恢复,因为 SimpleBank 不拥有任何代币。这使得顶级交易(从第 1 点开始)也恢复了。
如果您希望SimpleBank
能够转移0xAb8483...
的代币,0xAb8483...
需要approve()
代币首先被[=11=花费].直接来自他们的地址,因此他们在 Token
合同中是 msg.sender
。
只有SimpleBank
才能执行transferFrom(0xAb8483..., address(this), amt)
(from,to,amount)
TLDR:你的合约不能花费不属于它的代币,除非所有者手动批准你的合约花费它们。
如果它可以在未经批准的情况下花费别人的代币,那么很容易从无法验证您的源代码的人那里窃取(通过花费他们的 USDT、WETH 和其他广泛使用的代币)代币)。
我通过在 ERC20.sol 文件中实施 OpenZeppelin 创建了一个基本的 ERC20 令牌:
pragma solidity ^0.6.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor(string memory _name, string memory _symbol)
public
ERC20(_name, _symbol)
{
_mint(msg.sender, 10000000000000000000000000000);
}
}
然后执行另一个合约Contract.sol如下:
import "./ERC20.sol";
pragma solidity ^0.6.4;
contract SimpleBank{
Token tokenContract;
constructor(Token _tokenContract) public {
tokenContract = _tokenContract;
}
function deposit(uint amt) public returns (bool) {
require(amt != 0 , "deposit amount cannot be zero");
tokenContract.transfer(address(this),amt);
return true;
}
}
因为,我已经从地址 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 部署了两个合约,所以它拥有 1000000000000000000000000000000 代币。
但是当我从同一地址调用 deposit
函数时,出现以下错误:
transact to SimpleBank.deposit errored: VM error: revert. revert The transaction has been reverted to the initial state. Reason provided by the contract: "ERC20: transfer amount exceeds balance". Debug the transaction to get more information.
那么,与已部署的 ERC20 令牌进行交互的正确方法是什么,以便 deploy
功能起作用。
用户地址
0xAb8483...
发送交易执行SimpleBank
的函数deposit()
,使得0xAb8483...
成为msg.sender
的值] 在SimpleBank
.但是随后
中SimpleBank
发送一个内部事务执行Token
的函数transfer()
。这使得SimpleBank
地址(不是0xAb8483...
) 成为Token
.msg.sender
的值所以 SimpleBank 中的片段
tokenContract.transfer(address(this),amt);
正在尝试发送SimpleBank
的令牌。不是用户的 (0xAb8483...
) 代币。
此代币转移(从第 2 点开始)恢复,因为 SimpleBank 不拥有任何代币。这使得顶级交易(从第 1 点开始)也恢复了。
如果您希望SimpleBank
能够转移0xAb8483...
的代币,0xAb8483...
需要approve()
代币首先被[=11=花费].直接来自他们的地址,因此他们在 Token
合同中是 msg.sender
。
只有SimpleBank
才能执行transferFrom(0xAb8483..., address(this), amt)
(from,to,amount)
TLDR:你的合约不能花费不属于它的代币,除非所有者手动批准你的合约花费它们。
如果它可以在未经批准的情况下花费别人的代币,那么很容易从无法验证您的源代码的人那里窃取(通过花费他们的 USDT、WETH 和其他广泛使用的代币)代币)。