嘗試轉移 erc20 代幣,但始終遇到 gas * price + value 資金不足
我正在嘗試轉移一個 erc20 代幣,但是一直遇到 gas * price + value 的資金不足,無論我有多少 eth,我還有一個估計函式,它返回的值比我的值低幾倍乙。
我正在使用 Infura。
我的 ETH 餘額是:
79475000000000000 (0,079475)
這是我的估計輸出:
2020-08-31 14:49:26,036 INFO [EthResource] (vert.x-worker-thread-1) ########## Entering doTokenEstimateTransactionFee... 2020-08-31 14:49:26,513 INFO [Web3jService] (vert.x-worker-thread-1) >>>>>>>>>> (Token tx) DefaultGasProvider.GAS_LIMIT = 4300000 2020-08-31 14:49:26,673 INFO [Web3jService] (vert.x-worker-thread-1) >>>>>>>>>> (Token tx) ethEstimateGas.amountUsed = 21584 2020-08-31 14:49:26,674 INFO [Web3jService] (vert.x-worker-thread-1) >>>>>>>>>> (Token tx) ethGasPrice.gasPrice = 217000000000 2020-08-31 14:49:26,674 INFO [Web3jService] (vert.x-worker-thread-1) >>>>>>>>>> (Token tx) estimated tx fee = 4683728000000000 2020-08-31 14:49:26,674 INFO [EthResource] (vert.x-worker-thread-1) ########## (success) Leaving doTokenEstimateTransactionFee...
所以費用應該是0,004683728,比我的餘額少。
這是我的程式碼:
@Synchronized fun TokenTransferFrom(TokenTransferFromDto: TokenTransferFromDto): ResultDto { return try { val sourceCredentials: Credentials = Util.generateCredentialsBip32(TokenTransferFromDto.sourceMnemonic) return if (TokenTransferFromDto.sourcePrivateKey == sourceCredentials.ecKeyPair.privateKey.toString(16)) { val fastRawTransactionManager = FastRawTransactionManager(web3j, sourceCredentials, NoOpProcessor(web3j)) // Load contract by source val TokenSource = load(infuraTokenContractAddress, web3j, fastRawTransactionManager, DefaultGasProvider()) val transactionReceipt = TokenSource.transfer(TokenTransferFromDto.destination, TokenTransferFromDto.amount).send() if (!transactionReceipt.isStatusOK) { return wrapError("transactionReceipt.isStatusOK false", transactionReceipt.status) } logger.info(">>>>>>>>>> TokenTransferFrom txHash = ${transactionReceipt.transactionHash}") ResultDto("success", null, "", transactionReceipt.transactionHash, null, null, null) } else { wrapError("", "Invalid mnemonic or private key") } } catch (e: Exception) { logger.error(">>>>>>>>>> EXCEPTION: ${e.message}") wrapError("", e.message.toString()) } }
有人能告訴我我必須改變什麼才能指定我自己的 GAS_LIMIT 嗎?
這是我不斷遇到的錯誤:
2020-08-31 14:54:34,787 ERROR [Web3jService] (vert.x-worker-thread-4) >>>>>>>>>> EXCEPTION: Error processing transaction request: insufficient funds for gas * price + value
我對 kotlin,java 完全陌生,如果我很笨,很抱歉。謝謝。
我設法解決了這個問題,這是由於應用程序將預設 GAS_PRICE 和 GAS_LIMIT 設置為我們太高或太低的值。
例如,web3j API 將合約的 GAS_LIMIT 設置為 4,300,000,但 GAS_PRICE 設置為 22 GWEI(22,000,000,000 WEI),遠低於網路平均 gas 價格 450 GWEI(450,000,000,000 WEI)。
首先,我調整了 GAS_PRICE 以匹配目前平均網路 GAS_PRICE,但仍然遇到相同的“gas * price + value 資金不足”錯誤,此時我認為 API 試圖保留的 Transaction cost (交易能夠保留的金額超過它將花費的金額)大於我的餘額
(450,000,000,000 * 4,300,000 = 1,935,000,000,000,000,000 WEI
$$ 1.935 ETH $$). 所以下一步是降低 GAS_LIMIT,對於正常的 ETH 交易,它通常設置為 21,000,但代幣交易更昂貴,所以我將其設置為 30,000。最後,我的交易通過並出現在網路上,但大約 10 分鐘後,交易失敗並出現錯誤 OUT OF GAS。這意味著我指定的 GAS_LIMIT 太低,所以我將其增加到 100,000。這意味著在目前的 GAS_PRICE 下,交易的最大成本約為 20 $ . The transaction went through again and got confirmed within a minute, costing me 9 $ .
這是更新後的程式碼,以防有人想知道我是如何更新 GAS_LIMIT 和 GAS_PRICE 的。
@Synchronized fun TokenTransferFrom(TokenTransferFromDto: TokenTransferFromDto): ResultDto { return try { val sourceCredentials: Credentials = Util.generateCredentialsBip32(TokenTransferFromDto.sourceMnemonic) return if (TokenTransferFromDto.sourcePrivateKey == sourceCredentials.ecKeyPair.privateKey.toString(16)) { val fastRawTransactionManager = FastRawTransactionManager(web3j, sourceCredentials, NoOpProcessor(web3j)) // Load contract by source val TokenSource = load(infuraTokenContractAddress, web3j, fastRawTransactionManager, DefaultGasProvider()) // // NEW CODE STARTS HERE // // Generate a new gasProvider using the current network gasPrice and our own gasLimit val gasProvider = StaticGasProvider(TokenSource.requestCurrentGasPrice(), BigInteger.valueOf(100000)) // Set our own gasProvider as the current gasProvider TokenSource.setGasProvider(gasProvider) // // NEW CODE ENDS HERE // val transactionReceipt = TokenSource.transfer(TokenTransferFromDto.destination, TokenTransferFromDto.amount).send() if (!transactionReceipt.isStatusOK) { return wrapError("transactionReceipt.isStatusOK false", transactionReceipt.status) } logger.info(">>>>>>>>>> TokenTransferFrom txHash = ${transactionReceipt.transactionHash}") ResultDto("success", null, "", transactionReceipt.transactionHash, null, null, null) } else { wrapError("", "Invalid mnemonic or private key") } } catch (e: Exception) { logger.error(">>>>>>>>>> EXCEPTION: ${e.message}") wrapError("", e.message.toString()) } }