为什么在尝试将 tUSDT 添加到特定帐户时出现 "Error processing transaction request: intrinsic gas too low" 错误?

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

我正在尝试使用以下 code 将测试 USDT 发送到 Java 中的特定帐户:

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();

最后一条语句导致以下异常:

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(Contract.java:410)
    at org.web3j.protocol.core.RemoteCall.send(RemoteCall.java:42)
    at com.dpisarenko.minimalcryptoexchange.delegates.TransferUsdtToExchangeAccount.execute(TransferUsdtToExchangeAccount.java:57)

TestGasProvider 定义为:

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 是使用 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);
  });

此合约是 运行 在本地测试网上设置的 here

为了将任意数量的 USDT 发送到特定地址(没有任何错误),我需要更改这些组件(测试网、合同、部署脚本、Java 代码)中的哪些内容?

更新 1: 如果我将 TestGasProvider 更改为

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);
    }
}

我收到另一个错误:

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(Contract.java:410)
    at org.web3j.protocol.core.RemoteCall.send(RemoteCall.java:42)
    at com.dpisarenko.minimalcryptoexchange.delegates.TransferUsdtToExchangeAccount.execute(TransferUsdtToExchangeAccount.java:57)

赏金条款

我会将赏金奖励给向 minimal-crypto-exchange 项目的分支 i16 提交一组代码更改并通过以下测试的人:

步骤 1

按照描述设置环境 here

第 2 步

TransferUsdtToExchangeAccount usdtContract.transfer(exchangeAddress, BigInteger.valueOf(10)).send(); 行设置断点 class:

步骤 3

以调试模式启动流程引擎应用程序。它的 Java 主要方法位于 here.

等到您在控制台输出中看到消息 starting to acquire jobs

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

步骤 4

在 http://localhost:8080 使用凭据 demo/demo 登录。

登录后您应该会看到这样的页面:

第 5 步

单击任务列表 link。您应该会看到如下所示的页面:

按“开始进程”link。将出现以下屏幕:

点击 Send USDT to the exchange account process link。将出现以下对话框:

在“业务键”字段中输入任意值,然后按“开始”按钮。

第 6 步

几秒钟后,步骤 2 中的断点将激活。

如果 usdtContract.transfer(exchangeAddress, BigInteger.valueOf(10)).send(); 执行无误,则满足授予赏金的条件。

备注

  1. 您可以将 usdtContract.transfer(exchangeAddress, BigInteger.valueOf(10)).send(); 中的金额从 10 修改为其他金额。
  2. 您还可以修改docker-compose.yml and genesis.json, as well as those of the USDT smart contract which is deployed using this script中指定的以太坊测试网的参数。
  3. 您的解决方案必须在此受控环境中工作(即不得使用水龙头)。

更新二 (2021-12-31)

我做了以下更改:

  1. set-up tutorial 现在包含将 ETH 添加到交易账户的步骤 7。
  2. 现在有新版本了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. 修改了TransferUsdtToExchangeAccount中的代码,现在USDT不是从兑换账户(余额为零)转账,而是从缓冲账户转账。

现在我收到错误

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

我的以太坊技术还不够熟练,无法给你正确的答案,但我希望你能得到一些指导。

该错误表明您正试图由一方 A 以另一方 B 的名义向第三方 C 转移一定数量,但您尝试转移的金额,使用 transferFrom,大于乙方approved甲方发送

您可以使用与合同名称相同的方法检查双方之间的实际allowance

请考虑 Github 中来自 web3j 库的评论 this integration test。它与您的不同,但我认为它可能会有所帮助。

特别指出,实际的transferFrom操作应由津贴受益人进行。请看相关代码:

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 OpenZeppelin forum post 中指出。