Solidity

無法將 ERC20 代幣從另一個智能合約轉移給發送乙太幣的人

  • July 22, 2018

我創建了兩個智能合約,都部署在 Ropsten 測試網路上。我正在使用 MetaMask 進行交易。

  1. ERC20 代幣的實現如下(請注意,我可以在 MetaMask 中看到我的代幣):
contract AppleToken is ERC20Interface, Owned, SafeMath {
string public symbol;
string public  name;
uint8 public decimals;
uint public _totalSupply;

mapping(address => uint) balances;
mapping(address => mapping(address => uint)) allowed;


// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
function AppleToken()  public {
   symbol = "AppleToken";
   name = "Apple Token";
   decimals = 18;
   _totalSupply = 100000000000000000000000000;
   balances[0x2cBccb25319231B921fCf02Ec3bc213FcdFAeA15] = _totalSupply;
   Transfer(address(0), 0x2cBccb25319231B921fCf02Ec3bc213FcdFAeA15, _totalSupply);
}


// ------------------------------------------------------------------------
// Total supply
// ------------------------------------------------------------------------
function totalSupply() public constant returns (uint) {
   return _totalSupply  - balances[address(0)];
}


// ------------------------------------------------------------------------
// Get the token balance for account tokenOwner
// ------------------------------------------------------------------------
function balanceOf(address tokenOwner) public constant returns (uint balance) {
   return balances[tokenOwner];
}


// ------------------------------------------------------------------------
// Transfer the balance from token owner's account to to account
// - Owner's account must have sufficient balance to transfer
// - 0 value transfers are allowed
// ------------------------------------------------------------------------
function transfer(address to, uint tokens) public returns (bool success) {
   balances[msg.sender] = safeSub(balances[msg.sender], tokens);
   balances[to] = safeAdd(balances[to], tokens);
   Transfer(msg.sender, to, tokens);
   return true;
}


// ------------------------------------------------------------------------
// Token owner can approve for spender to transferFrom(...) tokens
// from the token owner's account
//
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
// recommends that there are no checks for the approval double-spend attack
// as this should be implemented in user interfaces 
// ------------------------------------------------------------------------
function approve(address spender, uint tokens) public returns (bool success) {
   allowed[msg.sender][spender] = tokens;
   Approval(msg.sender, spender, tokens);
   return true;
}


// ------------------------------------------------------------------------
// Transfer tokens from the from account to the to account
// 
// The calling account must already have sufficient tokens approve(...)-d
// for spending from the from account and
// - From account must have sufficient balance to transfer
// - Spender must have sufficient allowance to transfer
// - 0 value transfers are allowed
// ------------------------------------------------------------------------
function transferFrom(address from, address to, uint tokens) public returns (bool success) {
   balances[from] = safeSub(balances[from], tokens);
   allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
   balances[to] = safeAdd(balances[to], tokens);
   Transfer(from, to, tokens);
   return true;
}


// ------------------------------------------------------------------------
// Returns the amount of tokens approved by the owner that can be
// transferred to the spender's account
// ------------------------------------------------------------------------
function allowance(address tokenOwner, address spender) public constant returns (uint remaining) {
   return allowed[tokenOwner][spender];
}


// ------------------------------------------------------------------------
// Token owner can approve for spender to transferFrom(...) tokens
// from the token owner's account. The spender contract function
// receiveApproval(...) is then executed
// ------------------------------------------------------------------------
function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
   allowed[msg.sender][spender] = tokens;
   Approval(msg.sender, spender, tokens);
   ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
   return true;
}


// ------------------------------------------------------------------------
// Don't accept ETH
// ------------------------------------------------------------------------
function () public payable {
   revert();
}


// ------------------------------------------------------------------------
// Owner can transfer out any accidentally sent ERC20 tokens
// ------------------------------------------------------------------------
function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
   return ERC20Interface(tokenAddress).transfer(owner, tokens);
}

} 2. 另一個接收 Ether 的智能合約,它應該與上述給定的智能合約互動,以將我的代幣轉移給 Ether 的發送者。

我正在嘗試實現第 2 點中提到的內容,但是如果我嘗試訪問 ERC20 令牌實例的“轉移”功能,我會收到氣體估計超出錯誤(我嘗試增加氣體限制,沒有工作)。此外,當我嘗試通過 MetaMask 強制交易時,它顯示執行成本為 60001 eth,即使我嘗試僅發送 1 個乙太幣。

這是我的功能的實現

目前,我是 ETH 的發送者,我是 ERC20 代幣的接收者

function sendTokens () public payable returns (uint)
   {
      //tokenAddress is the address of the ERC20 token deployed on Ropsten
       AppleToken appleToken;
       appleToken = AppleToken(tokenAddress);
       appleToken.transfer(msg.sender, 10);
       return appleToken.balanceOf(msg.sender);
   }

我目前正在發送硬編碼的 10 個令牌用於測試目的。 請注意,我已將 AppleToken 包含在 import “browser/AppleToken.sol” 中;

如果我只執行 appleToken.balanceOf 函式,那麼它什麼也不返回。綜上所述,“transfer”函式存在問題,因為計算的執行成本過高,並且“balanceOf”沒有返回任何內容,甚至沒有返回0。

我是否正確啟動了 AppleToken 的實例?還是我做錯了什麼?

任何幫助,將不勝感激。

謝謝你。

更新

Ropsten上的賬戶公共地址:0x2cBccb25319231B921fCf02Ec3bc213FcdFAeA15

Ropsten 上的 ERC20 令牌地址:0x580156edb25D3c3deD584F1075CcCC5dA4861883

以下是 EquityInvestments 合約的完整程式碼:

我已經刪除了程式碼中不必要的東西,因為我沒有呼叫這些函式或使用為我面臨的問題定義的一些變數

pragma solidity ^0.4.16;
import "browser/AppleToken.sol";

contract EquityInvestments 
{
   AppleToken appleToken;
   Group [] _Groups;
   uint PriceEth = 1;
   address tokenAddress = 0x580156edb25D3c3deD584F1075CcCC5dA4861883;
   mapping (address => mapping(uint=>UserInvestment)) private _UserInvestments;

   function EquityInvestments () public
   {
       _Groups.push(Group({
           GroupID: 1,
           GroupName: "Google",
           TotalInvestment: 0,
           GroupPriceDollars: 200,
           GroupPriceEth: 1
       }));
        _Groups.push(Group({
           GroupID: 2,
           GroupName: "Tesla",
            TotalInvestment: 0,
            GroupPriceDollars: 200,
            GroupPriceEth: 1
       }));
        _Groups.push(Group({
           GroupID: 3,
           GroupName: "Apple",
            TotalInvestment: 0,
            GroupPriceDollars: 200,
            GroupPriceEth: 1
       }));
   }

   struct Group
   {
    uint GroupID;
    string GroupName;
    uint TotalInvestment;
    uint GroupPriceDollars;
    uint GroupPriceEth;
   }

   function sendTokens () public payable returns (uint)
   {
       appleToken = AppleToken(tokenAddress);
       // return appleToken.balanceOf(msg.sender);
       // appleToken.approve(this, 10);
       require(appleToken.transfer(msg.sender, 10));
       return appleToken.balanceOf(msg.sender);
   }



}

我看不出代幣合約有什麼問題。

關於第二個,你應該這樣做:

function sendTokens () public payable returns (uint)
   {
       AppleToken appleToken = AppleToken(tokenAddress);
       require(appleToken.transfer(msg.sender, 10));
       return appleToken.balanceOf(msg.sender);
   }
  1. 無需聲明 appleToken 變數然後設置它,您可以將兩者結合起來。
  2. 確保這tokenAddress是正確的。
  3. require在進行令牌傳輸時始終使用 a !不要認為它像 for 的transfer方法那樣工作ether,它處理失敗並會為你拋出。

編輯 :

我已經測試了契約,它工作正常。我認為您只是忘記向EquityInvestments合約發送代幣,因此代幣餘額msg.sender保持在0.

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