Solidity

ERC20 如何將代幣從合約轉移到賬戶?

  • April 11, 2022

該合約創建了代幣並將其儲存在自己的地址(合約地址)中。

我想實現一個將令牌從這個合約地址轉移到帳戶地址的功能。

pragma solidity ^0.8.4;

import "@openzeppelin/contracts@4.5.0/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
   constructor() ERC20("MyToken", "MTK") {
       _mint(address(this), 500 * 10 ** decimals());
   }
  
   function testTra(address _to, uint _amount) public{
       transfer(_to,_amount);
   }
}

它沒有用,它顯示 remix ide 中的錯誤。

ERC20: transfer amount exceeds balance

此外,當我檢查合約地址的 balanceOf 時,它顯示它有代幣。

基本上,我想要的是一個使用者呼叫 testTra()來獲得 ERC20 代幣的獎勵。使用者如何從 MyToken 合約中接收代幣?

根據 OpenZeppelin 文件(OpenZeppelin),傳遞函式必須滿足以下條件:

  • 收件人不能是零地址。
  • 呼叫者必須至少有一個餘額。

呼叫者表示 msg.sender。現在當有人呼叫你的合約時,他們的地址就是 msg.sender。當呼叫 transfer 函式時,它會檢查 msg.sender 是否有足夠的餘額。然而,所有的代幣餘額實際上都在合約地址中,這就是為什麼 msg.sender 的餘額為 0。因此交易失敗。

所以簡而言之,當人 A 呼叫你的 testTra 函式時,合約會嘗試將人 A 的餘額發送到*_to*參數中指定的地址。

你的邏輯問題是,如果你為合約地址鑄造代幣,你就不能對這些代幣做任何事情,因為在這種情況下你的合約永遠不會是 msg.sender 。因此,您既不能在 testTra 函式中給予津貼,也不能使用 transferFrom 或 transfer。但是,您可以做的是使用另一個地址(如另一個智能合約)作為代幣管理器並將代幣鑄造到該地址。

pragma solidity ^0.8.4;

import "@openzeppelin/contracts@4.5.0/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
   constructor(address _manager) ERC20("MyToken", "MTK") {
       _mint(_manager, 500 * 10 ** decimals());
   }
  
   function testTra(address _to, uint _amount) external{
       transfer(_to,_amount);
   }
}


contract ManagerContract {
   address public myTokenAddress;
   address public owner;
   constructor(){
       owner = msg.sender;
   }

   modifier onlyOwner() {
       require(msg.sender == owner);
       _;
   }

   modifier addressIsNotEmpty() {
       require(myTokenAddress != address(0), "Address is empty!");
       _;
   }

   function setMyTokenAddress(address _myTokenAddress) public onlyOwner {
       myTokenAddress = _myTokenAddress;
   }

   function testTra(address _to, uint _amount) public addressIsNotEmpty {
       (bool success, ) = myTokenAddress.call(abi.encodeWithSignature("testTra(address,uint256)",_to,_amount));

   }
}

將會發生的是,您首先部署您的 ManagerContract。然後您將通過在建構子中提供 ManagerContract 的地址來部署 TokenContract。之後,您將使用 TokenContract 的地址呼叫 setMyTokenAddress 函式。通過這種方式,使用者現在必須呼叫管理器合約中的 testTra 函式來獲取代幣。之後,使用者可以正常與 TokenContract 互動。

引用自:https://ethereum.stackexchange.com/questions/125785