Solidity

接收代幣時出現氣體不足錯誤

  • March 24, 2019

我有一個問題:

我想收到一些 BOKKY 代幣來測試它。當我使用簡單的錢包時,我只是發送乙太幣並接收代幣,一切正常。

我也有自己的智能合約(多重簽名錢包)當我將乙太幣轉移到其他賬戶時它工作正常,但是當我嘗試以與簡單賬戶相同的方式接收代幣時(將乙太幣從我的合約發送到代幣合約地址) 我的交易失敗並出現錯誤

Out of gas

智能合約的程式碼在這裡:

pragma solidity 0.5.0;

import "./ERC20.sol";

contract MultiSigWallet {

// address private _owner;
 mapping(address => uint) private _owners;

 uint constant MIN_SIGNATURES = 2;
 uint private transactionIdx;
 address payable private _commissionAddress;
 mapping(uint => address) private tokens;
 uint private currentToken;

 ERC20 private erc20iface;

 struct Transaction {
   address from;
   address payable to;
   address _contract;
   uint amount;
   uint  signatureCount;
   uint commission;
   mapping(address => uint) signatures;
 }

 mapping(uint => Transaction) private _transactions;
 uint[] private _pendingTransactions;

//   modifier isOwner() {
//     require(msg.sender == _owner);
//     _;
//   }

 modifier validOwner() {
//  require(msg.sender == _owner || _owners[msg.sender] == 1);
   require(_owners[msg.sender] == 1);
   _;
 }

 event DepositFunds(address from, uint amount);
 event TransactionCreated(address from, address to, uint amount, uint transactionId);
 event TransactionCompleted(address from, address to, uint amount, uint transactionId);
 event TransactionSigned(address by, uint transactionId);
 event TransferFailed(address from, address to, uint amount, uint transactionId);

 constructor(address service, address payable commissionAddress, address token) public {
  // _owner = msg.sender;
   _commissionAddress = commissionAddress;
   _owners[msg.sender] = 1;
   _owners[service] = 1;

   currentToken = 0;
   tokens[currentToken] = token;
   currentToken++;
 }

 function () external payable
 {
   emit DepositFunds(msg.sender, msg.value);
 }

 function withdraw(uint amount, uint commission, address token)
   public
     {
   transferTo(msg.sender,  amount, commission, token);
 }

 function transferTo(address payable to, uint amount, uint commission, address token)
   validOwner
   public
     {
   // require(address(this).balance >= amount);
   require(amount > 0);

   uint transactionId = transactionIdx++;

   Transaction memory transaction;
   transaction.from = msg.sender;
   transaction.to = to;
   transaction._contract = token;
   transaction.commission = commission;
   transaction.amount = amount;
   transaction.signatureCount = 0;

   _transactions[transactionId] = transaction;
   _pendingTransactions.push(transactionId);

   emit TransactionCreated(msg.sender, to, amount, transactionId);

   signTransaction(transactionId);
 }

 function getPendingTransactions()
   view
   validOwner
   public
   returns(uint[] memory)
   {
     return _pendingTransactions;
   }

 function signTransaction(uint transactionId)
   validOwner
   public
  {
   Transaction storage transaction = _transactions[transactionId];
   // Transaction must exist
   require(0x0000000000000000000000000000000000000000 != transaction.from);
   // Creator cannot sign the transaction
   // require(msg.sender != transaction.from);
   // sender haven't sign it already
   require(transaction.signatures[msg.sender] != 1);

   transaction.signatures[msg.sender] = 1;
   transaction.signatureCount++;

   emit TransactionSigned(msg.sender, transactionId);

   if(transaction.signatureCount >= MIN_SIGNATURES) {

     if(transaction._contract != 0x0000000000000000000000000000000000000000) {
       // if(amount_ > ERC20Interface.allowance(transaction.from, address(this))) {
       //   emit TransferFailed(from_, to_, amount_, transactionId);
       //   revert();
       // }
       erc20iface =  ERC20(transaction._contract);
       erc20iface.transfer(transaction.to, transaction.amount);
       erc20iface.transfer(_commissionAddress, transaction.commission);
     } else {
       require(address(this).balance >= transaction.amount);
       (transaction.to).transfer(transaction.amount);
       _commissionAddress.transfer(transaction.commission);
     }

     emit TransactionCompleted(transaction.from, transaction.to, transaction.amount, transactionId);
     deleteTransaction(transactionId);
   }
 }

 function deleteTransaction(uint transactionId)
   validOwner
   public
   {
     uint replace = 0;
     assert(_pendingTransactions.length > 0);
     for(uint i = 0; i < _pendingTransactions.length; i++) {
       if(replace == 1) {
         _pendingTransactions[i-1] = _pendingTransactions[i];
       } else if (transactionId == _pendingTransactions[i]) {
         replace = 1;
       }
   }
     assert(replace == 1);
     delete _pendingTransactions[_pendingTransactions.length - 1];
     _pendingTransactions.length--;
     delete _transactions[transactionId];
   }

 function walletBalance()
   view
   public
   returns (uint) {
     return address(this).balance;
   }

}

web3 的程式碼(tx 創建):

const createMsigTxETH = async options => {
 const { targetAddress, contractAddress, amount, commission, initiatorAddress } = options;

 const provider = new Web3.providers.HttpProvider(eth);
 const web3 = new Web3(provider);

 const amountETH = web3.utils.toWei(amount.toString(), 'ether');
 const commissionETH = web3.utils.toWei(commission.toString(), 'ether');
 const msigWalletContract = new web3.eth.Contract(MSIG_ABI, contractAddress);
 const nonce = await web3.eth.getTransactionCount(initiatorAddress);
 const TOKEN_ADDR = '0x0000000000000000000000000000000000000000';

 const txObj = {
   nonce: web3.utils.toHex(nonce),
   gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')),
   gasLimit: web3.utils.toHex(GAS),
   data: msigWalletContract.methods
     .transferTo(targetAddress, amountETH, commissionETH, TOKEN_ADDR)
     .encodeABI(),
   to: contractAddress
 };

 const tx = new Tx(txObj);
 return tx;
};

簽署 tx 的程式碼:

const provider = new Web3.providers.HttpProvider(eth);
   const web3 = new Web3(provider);

   const msigWalletContract = new web3.eth.Contract(MSIG_ABI, contractAddress);
   const nonce = await msigWalletContract.methods
     .getPendingTransactions()
     .call({ from: serviceAddress });
   if (!nonce.length) throw Error('ERROR NONCE ');
   const txObj = {
     nonce: web3.utils.toHex(nonce[nonce.length - 1]),
     gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')),
     gasLimit: web3.utils.toHex(GAS),
     data: msigWalletContract.methods.signTransaction(nonce[nonce.length - 1]).encodeABI(),
     to: contractAddress
   };

   const tx = new Tx(txObj);
   tx.sign(Buffer.from(servicePrivateKey, 'hex'));

   const serializedTx = tx.serialize();
   const raw = `0x${serializedTx.toString('hex')}`;

   try {
     return new Promise((resolve, reject) => {
       web3.eth.sendSignedTransaction(raw).on('transactionHash', txHash => {
         resolve(txHash);
       });
     });
   } catch (err) {
     throw new Error(err);
   }
 }

誰能建議它可以是什麼?

謝謝!

你呼叫signTransaction了你的多重簽名錢包。似乎這個簽名是最後一個需要的,所以你的多重簽名錢包試圖執行交易,即使用函式發送 1 個乙太到地址0x101848D5C5bBca18E6b4431eEdF6B95E9ADF82FAtransfer。函式transfer允許目標合約最多消耗 2300 gas,但是你發送乙太幣的合約試圖消耗更多,所以轉賬失敗。

看起來你的多重簽名錢包不支持將乙太幣發送到需要超過 2300 氣體來處理傳入乙太幣轉賬的智能合約。您可能需要修改多重簽名錢包的程式碼才能支持此類轉賬。

請注意,OpenZeppelin 的 multisig walled 使用call而不是transfer避免此類問題:https ://github.com/OpenZeppelin/openzeppelin-solidity/blob/v1.2.0/contracts/MultisigWallet.sol#L63 。

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