简体   繁体   中英

Why am I getting "Error processing transaction request: intrinsic gas too low" error when trying to add tUSDT to a particular account?

I am trying to send test USDT to a particular account in Java using the following code :

final Web3j web3 = createWeb3If(ethNetworkUrl);
final Credentials credentials = Credentials.create(privateKey);
final ERC20 usdtContract = ERC20.load(usdtContractAddress, web3, credentials, new TestGasProvider());

usdtContract.transfer(exchangeAddress, BigInteger.valueOf(10)).send();

The last statement results in the following exception:

java.lang.RuntimeException: Error processing transaction request: intrinsic gas too low
    at org.web3j.tx.TransactionManager.processResponse(TransactionManager.java:176)
    at org.web3j.tx.TransactionManager.executeTransaction(TransactionManager.java:81)
    at org.web3j.tx.ManagedTransaction.send(ManagedTransaction.java:128)
    at org.web3j.tx.Contract.executeTransaction(Contract.java:367)
    at org.web3j.tx.Contract.executeTransaction(Contract.java:350)
    at org.web3j.tx.Contract.executeTransaction(Contract.java:344)
    at org.web3j.tx.Contract.executeTransaction(Contract.java:339)
    at org.web3j.tx.Contract.lambda$executeRemoteCallTransaction$3(Contract.java:410)
    at org.web3j.protocol.core.RemoteCall.send(RemoteCall.java:42)
    at com.dpisarenko.minimalcryptoexchange.delegates.TransferUsdtToExchangeAccount.execute(TransferUsdtToExchangeAccount.java:57)

TestGasProvider is defined as:

public class TestGasProvider extends StaticGasProvider {
    public static final BigInteger GAS_PRICE = BigInteger.valueOf(10L);
    public static final BigInteger GAS_LIMIT = BigInteger.valueOf(1L);

    public TestGasProvider() {
        super(GAS_PRICE, GAS_LIMIT);
    }
}

usdtContract was deployed using this script , which calls deploy.js :

async function main() {
  const USDT = await ethers.getContractFactory("USDT");
  const usdt = await USDT.deploy(1000000000000000);

  console.log("USDT contract deployed to:", usdt.address);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

This contract is running on a local testnet set up as described here .

What do I need to change in any of these components (testnet, contract, deploy scripts, Java code) in order to send any amount of USDT to a particular address (without any errors)?

Update 1: If I change TestGasProvider to

public class TestGasProvider extends StaticGasProvider {
    public static final BigInteger GAS_PRICE = BigInteger.valueOf(1L);
    public static final BigInteger GAS_LIMIT = BigInteger.valueOf(1000000000L);

    public TestGasProvider() {
        super(GAS_PRICE, GAS_LIMIT);
    }
}

I get another error:

java.lang.RuntimeException: Error processing transaction request: exceeds block gas limit
    at org.web3j.tx.TransactionManager.processResponse(TransactionManager.java:176)
    at org.web3j.tx.TransactionManager.executeTransaction(TransactionManager.java:81)
    at org.web3j.tx.ManagedTransaction.send(ManagedTransaction.java:128)
    at org.web3j.tx.Contract.executeTransaction(Contract.java:367)
    at org.web3j.tx.Contract.executeTransaction(Contract.java:350)
    at org.web3j.tx.Contract.executeTransaction(Contract.java:344)
    at org.web3j.tx.Contract.executeTransaction(Contract.java:339)
    at org.web3j.tx.Contract.lambda$executeRemoteCallTransaction$3(Contract.java:410)
    at org.web3j.protocol.core.RemoteCall.send(RemoteCall.java:42)
    at com.dpisarenko.minimalcryptoexchange.delegates.TransferUsdtToExchangeAccount.execute(TransferUsdtToExchangeAccount.java:57)

Terms for the bounty

I will award the bounty to a person who submits a set of code changes to the branch i16 of the minimal-crypto-exchange project which pass the following test:

Step 1

Set up the environment as described here .

Step 2

Set a breakpoint on line usdtContract.transfer(exchangeAddress, BigInteger.valueOf(10)).send();in TransferUsdtToExchangeAccount class:

带断点的代码部分截图

Step 3

Start the process engine application in debug mode. Its Java main method is located here .

Wait until you see the message starting to acquire jobs in the console output:

11:59:16.031 [JobExecutor[org.camunda.bpm.engine.spring.components.jobexecutor.SpringJobExecutor]] INFO  org.camunda.bpm.engine.jobexecutor - ENGINE-14018 JobExecutor[org.camunda.bpm.engine.spring.components.jobexecutor.SpringJobExecutor] starting to acquire jobs

Step 4

Login with the credentials demo/demo at http://localhost:8080.

登录表单的屏幕截图

After login you should see a page like this:

突出显示任务列表链接的 Camunda 主仪表板

Step 5

Click on the tasklist link. You should see a page that looks like this:

“启动进程”链接任务列表

Press the "Start process" link. Following screen will appear:

“开始流程”对话框,突出显示“向交易所账户发送 USDT”流程

Click on Send USDT to the exchange account process link. Following dialog box will appear:

“启动进程”对话框

Enter an arbitrary value into the "business key" field and press the "Start" button.

Step 6

After a couple of seconds, the breakpoint from step 2 will activate.

The conditions for granting the bounty are satisfied, if usdtContract.transfer(exchangeAddress, BigInteger.valueOf(10)).send(); is executed without errors.

Notes

  1. You are allowed to modify the amount in usdtContract.transfer(exchangeAddress, BigInteger.valueOf(10)).send(); from 10 to something else.
  2. You can also modify the parameters of the Ethereum testnet specified in docker-compose.yml and genesis.json , as well as those of the USDT smart contract which is deployed using this script .
  3. Your solution must work in this controlled environment (ie no faucets must be used).

Update 2 (2021-12-31)

I made following changes:

  1. The set-up tutorial now contains step 7 in which ETH is added to the exchange account.
  2. Now a new version of the ETH testnet is being used, major changes being that log output is more verbose and the gas price is set to 1 (see --miner.gasprice 1 in entrypoint.sh ).
  3. Modified the code in TransferUsdtToExchangeAccount so that now USDT is transferred not from the exchange account (which has zero balance), but from the buffer account.

Now I am receiving the error

org.web3j.protocol.exceptions.TransactionException: Transaction 0x4bce379a2673c4564b2eb6080607b00d1a8ac232fbddf903f353f4eeda566cae
has failed with status: 0x0. Gas used: 32767. 
Revert reason: 'ERC20: transfer amount exceeds allowance'.

My skills with Ethereum are still not sharp enough to give you a proper answer, but I hope you get some guidance.

The error states that you are trying to transfer by a party A certain quantity in the name of another party B, to a third one C, but the amount you are trying to transfer, using transferFrom , is greater than the one party B approved party A to send.

You can check the actual allowance between to parties using the method with the same name of your contract.

Please, consider review this integration test from the web3j library in Github. It is different than yours but I think it could be helpful.

Especially, it states that the actual transferFrom operation should be performed by the beneficiary of the allowance. Please, see the relevant code:

final String aliceAddress = ALICE.getAddress();
final String bobAddress = BOB.getAddress();
ContractGasProvider contractGasProvider = new DefaultGasProvider();
HumanStandardToken contract =
        HumanStandardToken.deploy(
                        web3j,
                        ALICE,
                        contractGasProvider,
                        aliceQty,
                        "web3j tokens",
                        BigInteger.valueOf(18),
                        "w3j$")
                .send();

//...

// set an allowance
assertEquals(contract.allowance(aliceAddress, bobAddress).send(), (BigInteger.ZERO));

transferQuantity = BigInteger.valueOf(50);
TransactionReceipt approveReceipt =
        contract.approve(BOB.getAddress(), transferQuantity).send();

HumanStandardToken.ApprovalEventResponse approvalEventValues =
        contract.getApprovalEvents(approveReceipt).get(0);

assertEquals(approvalEventValues._owner, (aliceAddress));
assertEquals(approvalEventValues._spender, (bobAddress));
assertEquals(approvalEventValues._value, (transferQuantity));

assertEquals(contract.allowance(aliceAddress, bobAddress).send(), (transferQuantity));

// perform a transfer as Bob
transferQuantity = BigInteger.valueOf(25);

// Bob requires his own contract instance
HumanStandardToken bobsContract =
        HumanStandardToken.load(
                contract.getContractAddress(), web3j, BOB, STATIC_GAS_PROVIDER);

TransactionReceipt bobTransferReceipt =
        bobsContract.transferFrom(aliceAddress, bobAddress, transferQuantity).send();

HumanStandardToken.TransferEventResponse bobTransferEventValues =
        contract.getTransferEvents(bobTransferReceipt).get(0);
assertEquals(bobTransferEventValues._from, (aliceAddress));
assertEquals(bobTransferEventValues._to, (bobAddress));
assertEquals(bobTransferEventValues._value, (transferQuantity));

//...

This fact is also indicated in this OpenZeppelin forum post .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM