Ethers js 在合约间转账ERC20
Ethers js transferring ERC20 between contracts
我有 2 个合约,第一个是 openzeppelin ERC20 代币,第二个是彩票合约,玩家可以在其中投注一个数字。
lottery.sol
pragma solidity ^0.8.4;
import "./Token.sol"; //import ERC20 token
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Lottery is Ownable {
Token token;
constructor(Token _token) public {
token = _token;
}
// store information about player's bet
struct PlayersStruct {
uint betAmount;
uint betOnNumber;
}
mapping(address => PlayersStruct) public balances;
function enterLottery(string memory _betOnNumber) public payable {
address player = msg.sender;
uint amount = msg.value;
// transfer token from player's wallet to lottery contract
token.transferFrom(player, address(this), betAmount);
balances[player].betAmount += amount ;
balances[player].betOnNumber = _betOnNumber;
}
这就是我在 ReactJS 中的调用方式
async function stakeBet() {
const amount = ethers.utils.parseEther("10");
const maxAmount = ethers.utils.parseEther("1000000");
// approve token once so player can save on gas in future
await token.approve(stakingContract.address, maxAmount);
// bet 10 tokens on number 20
await lottery.enterLottery(20, {value: amount,});
}
此代码有 2 个问题:
- 我每次都必须批准合同,即使我批准的 maxAmount 高于投注金额。我如何让 Metamask 知道合同已获批准?
- 通过ERC20代币后,转账的代币实际上是ETH,而不是Token.sol中定义的ERC20代币,如何指定转账的是ERC20?
我正在 Kovan 测试网上进行测试。
在您的 stakeBet
函数中,您按顺序调用这些函数:
await token.approve(stakingContract.address, maxAmount);
// bet 10 tokens on number 20
await lottery.enterLottery(20, {value: amount,});
调用 approve 时,实际上是在更新 allowance
映射。让合同知道,您允许一定数量的允许地址。应该这样实现:
function approve(address _spender, uint _value)public returns (bool success){
// allowance tells how many tokens can be sent
allowance[msg.sender][_spender]=_value;
// This event must trigger when a successful call is made to the approve function.
emit Approval(msg.sender,_spender,_value);
return true;
}
代币转移或代币转移实际上是更新合约内部的状态。使用 approve
函数,您更新了津贴。现在
token.transferFrom
应该这样实现:
// my address is allowing your address for this much token
mapping(address=>mapping(address=>uint)) public allowance;
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success){
// check the allowance
require(_value <=allowance[_from][msg.sender]);
// update the balances
balanceOf[_to]+=_value;
balanceOf[_from]-=_value;
allowance[_from][msg.sender]-=_value;
// emitting an event
emit Transfer(_from,_to,_value);
return true;
}
- ETH 不是 ERC20 代币。相反,您必须实施 WETH 令牌并转移 WETH 令牌。 WETH 是 eth 的包装版本。 https://weth.io/
所有以太坊钱包地址都兼容 ERC20。此外,这意味着每次 ERC20 转账都可能发生在两个以太坊钱包地址或 ERC20 兼容地址之间。这通常包括所有 EVM-compatible 区块链。您发送 weth 令牌,用户可以换入元掩码:
对于第一部分,您已经完成了您打算做的事情,即您已将津贴设置为最大金额,以便用户无需支付用于每次调用 allow() 的事务。
MetaMask 正在征求您的许可,以向合约发送“betAmount”数量的代币以支付汽油费(以 ETH 为单位)。
我是以太坊的新手,但我在我的项目中遇到过类似的情况。所以,这是我的理解。
此外,对于第二个问题,正如我之前所说,MetaMask 正在请求您支付 gas 费用的许可(它在 ETH 中收取,但实际转移代币也必须发生。只是,一些 ETH 用于支付“Gas 费用”。
我有一篇讨论同样事情的好文章。
Link: https://medium.com/ethex-market/erc20-approve-allow-explained-88d6de921ce9
你可以看到我刚才说的演示。你可以看到 gas 费用是用 ETH 收取的。此外,如果您之前没有将津贴设置为最大值,您将不得不支付 gas 费用 两次才能使您的合约交易发生,首先调用 approve() 以获得津贴,然后获取转移到合约的“betAmount”数量的代币。
我有 2 个合约,第一个是 openzeppelin ERC20 代币,第二个是彩票合约,玩家可以在其中投注一个数字。
lottery.sol
pragma solidity ^0.8.4;
import "./Token.sol"; //import ERC20 token
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Lottery is Ownable {
Token token;
constructor(Token _token) public {
token = _token;
}
// store information about player's bet
struct PlayersStruct {
uint betAmount;
uint betOnNumber;
}
mapping(address => PlayersStruct) public balances;
function enterLottery(string memory _betOnNumber) public payable {
address player = msg.sender;
uint amount = msg.value;
// transfer token from player's wallet to lottery contract
token.transferFrom(player, address(this), betAmount);
balances[player].betAmount += amount ;
balances[player].betOnNumber = _betOnNumber;
}
这就是我在 ReactJS 中的调用方式
async function stakeBet() {
const amount = ethers.utils.parseEther("10");
const maxAmount = ethers.utils.parseEther("1000000");
// approve token once so player can save on gas in future
await token.approve(stakingContract.address, maxAmount);
// bet 10 tokens on number 20
await lottery.enterLottery(20, {value: amount,});
}
此代码有 2 个问题:
- 我每次都必须批准合同,即使我批准的 maxAmount 高于投注金额。我如何让 Metamask 知道合同已获批准?
- 通过ERC20代币后,转账的代币实际上是ETH,而不是Token.sol中定义的ERC20代币,如何指定转账的是ERC20?
我正在 Kovan 测试网上进行测试。
在您的 stakeBet
函数中,您按顺序调用这些函数:
await token.approve(stakingContract.address, maxAmount);
// bet 10 tokens on number 20
await lottery.enterLottery(20, {value: amount,});
调用 approve 时,实际上是在更新 allowance
映射。让合同知道,您允许一定数量的允许地址。应该这样实现:
function approve(address _spender, uint _value)public returns (bool success){
// allowance tells how many tokens can be sent
allowance[msg.sender][_spender]=_value;
// This event must trigger when a successful call is made to the approve function.
emit Approval(msg.sender,_spender,_value);
return true;
}
代币转移或代币转移实际上是更新合约内部的状态。使用 approve
函数,您更新了津贴。现在
token.transferFrom
应该这样实现:
// my address is allowing your address for this much token
mapping(address=>mapping(address=>uint)) public allowance;
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success){
// check the allowance
require(_value <=allowance[_from][msg.sender]);
// update the balances
balanceOf[_to]+=_value;
balanceOf[_from]-=_value;
allowance[_from][msg.sender]-=_value;
// emitting an event
emit Transfer(_from,_to,_value);
return true;
}
- ETH 不是 ERC20 代币。相反,您必须实施 WETH 令牌并转移 WETH 令牌。 WETH 是 eth 的包装版本。 https://weth.io/
所有以太坊钱包地址都兼容 ERC20。此外,这意味着每次 ERC20 转账都可能发生在两个以太坊钱包地址或 ERC20 兼容地址之间。这通常包括所有 EVM-compatible 区块链。您发送 weth 令牌,用户可以换入元掩码:
对于第一部分,您已经完成了您打算做的事情,即您已将津贴设置为最大金额,以便用户无需支付用于每次调用 allow() 的事务。
MetaMask 正在征求您的许可,以向合约发送“betAmount”数量的代币以支付汽油费(以 ETH 为单位)。
我是以太坊的新手,但我在我的项目中遇到过类似的情况。所以,这是我的理解。
此外,对于第二个问题,正如我之前所说,MetaMask 正在请求您支付 gas 费用的许可(它在 ETH 中收取,但实际转移代币也必须发生。只是,一些 ETH 用于支付“Gas 费用”。
我有一篇讨论同样事情的好文章。 Link: https://medium.com/ethex-market/erc20-approve-allow-explained-88d6de921ce9
你可以看到我刚才说的演示。你可以看到 gas 费用是用 ETH 收取的。此外,如果您之前没有将津贴设置为最大值,您将不得不支付 gas 费用 两次才能使您的合约交易发生,首先调用 approve() 以获得津贴,然后获取转移到合约的“betAmount”数量的代币。