我有 2 个合约,第一个是 openzeppelin ERC20 代币,第二个是彩票合约,玩家可以在其中下注。
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,});
}
我正在 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;
}
所有以太坊钱包地址均兼容 ERC20。此外,这意味着每次 ERC20 转账都可以在两个以太坊钱包地址或 ERC20 兼容地址之间发生。这通常包括所有与 EVM 兼容的区块链。您发送 weth 令牌,用户可以交换元掩码:
对于第1部分,你已经完成了你想要做的事情,即你已经将限额设置为最大金额,这样用户就不必为每次调用allow()交易而付费。
MetaMask 正在征求您的许可,以向合约发送“betAmount”数量的代币,以支付燃气费(以 ETH 为单位)。
我是以太坊新手,但我在项目中也遇到过类似的情况。所以,这是根据我的理解。
另外,对于第二个问题,正如我之前所说,MetaMask 正在请求您支付 Gas 费(以 ETH 形式支付,但代币的实际转移也必须发生)。仅需要一定数量的 ETH用于“Gas 费”。
我有一篇非常好的文章讨论了同样的事情。 链接:https://medium.com/ethex-market/erc20-approve-allow-explained-88d6de921ce9
你可以看我刚才说的演示。您可以看到,gas 费用是以 ETH 形式收取的。另外,如果您没有提前将限额设置为最大值,则您必须支付两次gas费用才能使您的合约发生交易,首先调用approve()以获得限额,然后获取“betAmount”金额转移到合约的代币。