0

I'm attempting to transfer an erc20 token, but keep running into insufficiant funds for gas * price + value, regardles of how much eth I have, I also have an estimate function which returns a value thats several times lower than what I have in eth.

I'm using Infura.

My ETH balance is:

79475000000000000 (0,079475)

Here's my estimate output:

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...

So the fee should be 0,004683728, which is less than my balance.

Here's my code:

@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())
    }
}

Can someone tell me what I have to change to be able to specify my own GAS_LIMIT as I'm stumped?

Here's the error that I endlessly keep encountering:

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

I'm completely new to kotlin, java, so sorry if I'm dumb. Thanks.

3
  • How much gas are you using? If it is 21584, it seems low for ERC20 transfers.
    – Ismael
    Aug 31 '20 at 21:29
  • For the estimate function, I am able to specify the GAS_LIMIT, which I do by using DefaultGasProvider.GAS_LIMIT, which as far as I can see is 4,300,000. But for the transfer function, I can't really see where I am able to specify it, and looking through the web3j code I can't quite understand which value is being used, as the Contract class has it set within it as 4_300_000, but the .transfer function has it set as 21000, and I can't quite figure out how to overwrite it. Sep 1 '20 at 6:08
  • Sorry, I don't know enough java to help but when I used some code usually load had the possibility of accepting GAS_LIMIT as parameter. There are more details in web3j documentation.
    – Ismael
    Sep 1 '20 at 6:41
0

I managed to resolve the issue, it was caused by the app setting the default GAS_PRICE and GAS_LIMIT as values that we're too high or too low.

For example, the web3j API had the GAS_LIMIT for the contract set at 4,300,000, but the GAS_PRICE at 22 GWEI (22,000,000,000 WEI), which was well bellow the network average gas price which was 450 GWEI (450,000,000,000 WEI).

First of all, I adjusted the GAS_PRICE to match the current average network GAS_PRICE, but still encountered the same "insufficient funds for gas * price + value" error, at which point I figured that the Transaction cost that the API was trying to reserve (the transaction is able to reserve more than it will spend) was greater than the balance I had

(450,000,000,000 * 4,300,000 = 1,935,000,000,000,000,000 WEI [1.935 ETH]).

So the next step was reducing the GAS_LIMIT, for regular ETH transactions it's usually set at 21,000, but token transactions are more expensive, so I set it at 30,000. Finally, my transaction went through and appeared on the network, but after about 10 minutes the transaction failed with the error OUT OF GAS. This meant the GAS_LIMIT I specified was too low, so I increased it to 100,000. This meant that at the current GAS_PRICE the max cost of the transaction was ~20$. The transaction went through again and got confirmed within a minute, costing me 9$.

Here's the updated code in case anyone is wondering how I updated the GAS_LIMIT and 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())
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.