Web3.js - 如何签署批准交易以进行掉期交易?

Web3.js - How to sign an approve transaction for a swap?

我想以编程方式交换两个令牌。我必须先批准金额。我如何批准使用 web3.js?

这是我到目前为止的想法,但我收到错误 Error: Returned error: nonce too low

const myAddress = "my-wallet-address"
const privateKey = Buffer.from('my-private-key', 'hex');

const test = async () => {
    const allowed = await tokenContract.methods.allowance(myAddress, 'UniswapV2Router02ContractAddress').call()

    const encodedABI = tokenContract.methods.approve('UniswapV2Router02ContractAddress', amountIn).encodeABI();
    const tx = {        
        from: myAddress,
        to: 'UniswapV2Router02ContractAddress',
        gas: 2000000,
        data: encodedABI
    };
    
    const customCommon = Common.default.forCustomChain(
        'mainnet',
        {
          name: 'SAMPLE testnet',
          networkId: custom-testnet-id,
          chainId: custom-testnet-id,
        },
        'petersburg',
      )

    const txTx = new Tx(tx, {common: customCommon});
    txTx.sign(privateKey);

    // below gives true, true
    console.log(txTx.validate(), ethUtil.bufferToHex(txTx.getSenderAddress()) === ethUtil.bufferToHex(ethUtil.privateToAddress(privateKey)))
    
    const serializedTx = txTx.serialize();

    // below line results in error
    await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'))

    // await uniswapV2Router02Contract.methods.swapExactTokensForTokensSupportingFeeOnTransferTokens(amountIn, amountOutMin, path, myAddress, deadline).send({from: myAddress})
}

test()

这个post的最后一个答案讨论了Error: Returned error: nonce too low错误:但是我已经验证我的私钥属于交易的发送者(我)所以我一无所知

我们先了解一下以太坊中的Nonce是什么

基于Ethereum paper:Nonce 是标量值,等于从地址(钱包)发送的交易数量...

交易包括:转账、创建合约...

当您在不同的地方使用您的帐户时,可能会出现 Nonce too low 错误。特别是当你使用私钥签署交易时。

示例:

  • 一个地址有5笔交易,发自MM(PC1)。 Nonce 为 5.
  • 您使用私钥 (PC2) 在另一个地方执行交易。 Nonce是6。但是MM不知道这个。
  • 回到PC1,在MM上再做一笔交易,Nonce应该是7,MM却说是6,这就导致了Nonce太低的问题。

为了修复,我们可以简单地重置 MM 钱包:

从 MM 菜单中选择设置 => 高级设置 => 重置。


为什么重置MM可以解决nonce问题?

  • 通过重置,MM可以同步地址的交易数量。所以随机数增加得很好。

代码如下:

var Web3 = require('web3');
var web3 = new Web3("rpc-node-link");
var Tx = require('ethereumjs-tx').Transaction;
var Common = require('ethereumjs-common');
var ethUtil = require('ethereumjs-util')

web3.eth.getTransactionCount(myAddress, async (err, txCount) => {
        const encodedABI = contractWhichisApproving.methods.approve(contractThatWantsToSpendContractWhichisApprovingsToken, amountIn).encodeABI();
        const tx = {
            nonce: web3.utils.toHex(txCount),
            from: myAddress,
            to: contractWhichisApprovingAddress,
            gas: 2000000,
            data: encodedABI
        };

        const customCommon = Common.default.forCustomChain(
            'mainnet',
            {
            name: 'Example testnet',
            networkId: custom-testnet-id,
            chainId: custom-testnet-id,
            },
            'petersburg',
        )

        const txTx = new Tx(tx, {common: customCommon});
        txTx.sign(privateKey);

        // following line logs true, true
        console.log(txTx.validate(), ethUtil.bufferToHex(txTx.getSenderAddress()) === ethUtil.bufferToHex(ethUtil.privateToAddress(privateKey)))

        const serializedTx = txTx.serialize();
        console.log('sending')
        await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')).on('receipt', console.log);
        console.log('done')
    });

使用自定义链的引用:https://github.com/ethereumjs/ethereumjs-tx/blob/master/examples/custom-chain-tx.ts