Solidity
接收代幣時出現氣體不足錯誤
我有一個問題:
我想收到一些 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 。