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 个问题:

  1. 我每次都必须批准合同,即使我批准的 maxAmount 高于投注金额。我如何让 Metamask 知道合同已获批准?
  2. 通过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”数量的代币。