繁体   English   中英

处理事务时出现 VM 异常:恢复 TransferHelper: TRANSFER_FROM_FAILED 运行 bot.js 的 manipulatePrice.js 测试时

[英]VM Exception while processing transaction: revert TransferHelper: TRANSFER_FROM_FAILED when running manipulatePrice.js test for bot.js

我正在使用 Dapp 大学的交易机器人大师班的代码来尝试创建一个机器人,该机器人将扫描加密货币去中心化交易所以获取代币对的价格差异,然后执行智能合约以使用 flash 贷款从中获利。 测试时,我能够看到运行一个 ganache-cli 节点并运行我的扫描机器人以侦听 ganache 上的交换机会。 有一个脚本旨在通过在 test.net 上将大量 SHIB 换成 WETH 来创建交换机会,以查看智能合约是否会在机器人检测到交换机会时部署和执行。 但是,运行此脚本会产生错误

UnhandledPromiseRejectionWarning:错误:返回错误:处理事务时出现VM异常:还原TransferHelper:TRANSFER_FROM_FAILED

此外,在 ganache-cli 终端中,我得到:

运行时错误:还原还原原因:TransferHelper:TRANSFER_FROM_FAILED

以下是我为达到上述目的而运行的命令:首先,我成功运行了ganache-cli -f wss://eth-mai.net.alchemyapi.io/v2/<Your-App-Key> -u 0x0e5069514a3dd613350bab01b58fd850058e5ca4 -p 7545与我的应用程序密钥。 然后,我在另一个终端成功运行了node bot.js来扫描 ganache 上的交换机会。 最后,我运行node scripts\manipulatePrice.JS ,输出“Beginnig Swap... Input token: SHIB Output token: WETH”,然后输出上述错误。

我尝试使用node --trace-warnings来显示警告的创建位置,但没有任何帮助。 我想知道它是否与运行时错误有关:还原消息? 下面是我试图运行以测试我的机器人的 manipulatePrice.js 脚本的代码。 如果需要,我可以附加更多代码,但不想发布太多。 如果有人知道问题出在哪里或出在哪里,我将不胜感激!!

require("dotenv").config();

const Web3 = require('web3')
const {
    ChainId,
    Token,
    WETH
} = require("@uniswap/sdk")
const IUniswapV2Router02 = require('@uniswap/v2-periphery/build/IUniswapV2Router02.json')
const IUniswapV2Factory = require("@uniswap/v2-core/build/IUniswapV2Factory.json")
const IERC20 = require('@openzeppelin/contracts/build/contracts/ERC20.json')

// -- SETUP NETWORK & WEB3 -- //

const chainId = ChainId.MAINNET
const web3 = new Web3('http://127.0.0.1:7545')

// -- IMPORT HELPER FUNCTIONS -- //

const { getPairContract, calculatePrice } = require('../helpers/helpers')

// -- IMPORT & SETUP UNISWAP/SUSHISWAP CONTRACTS -- //

const config = require('../config.json')
const uFactory = new web3.eth.Contract(IUniswapV2Factory.abi, config.UNISWAP.FACTORY_ADDRESS) // UNISWAP FACTORY CONTRACT
const sFactory = new web3.eth.Contract(IUniswapV2Factory.abi, config.SUSHISWAP.FACTORY_ADDRESS) // SUSHISWAP FACTORY CONTRACT
const uRouter = new web3.eth.Contract(IUniswapV2Router02.abi, config.UNISWAP.V2_ROUTER_02_ADDRESS) // UNISWAP ROUTER CONTRACT
const sRouter = new web3.eth.Contract(IUniswapV2Router02.abi, config.SUSHISWAP.V2_ROUTER_02_ADDRESS) // UNISWAP ROUTER CONTRACT

// -- CONFIGURE VALUES HERE -- //

const V2_FACTORY_TO_USE = uFactory
const V2_ROUTER_TO_USE = uRouter

const UNLOCKED_ACCOUNT = '0x0e5069514a3Dd613350BAB01B58FD850058E5ca4' // SHIB Unlocked Account
const ERC20_ADDRESS = process.env.ARB_AGAINST
const AMOUNT = '40500000000000' // 40,500,000,000,000 SHIB -- Tokens will automatically be converted to wei
const GAS = 450000

// -- SETUP ERC20 CONTRACT & TOKEN -- //

const ERC20_CONTRACT = new web3.eth.Contract(IERC20.abi, ERC20_ADDRESS)
const WETH_CONTRACT = new web3.eth.Contract(IERC20.abi, WETH[chainId].address)

// -- MAIN SCRIPT -- //

const main = async () => {
    const accounts = await web3.eth.getAccounts()
    const account = accounts[1] // This will be the account to recieve WETH after we perform the swap to manipulate price

    const pairContract = await getPairContract(V2_FACTORY_TO_USE, ERC20_ADDRESS, WETH[chainId].address)
    const token = new Token(
        ChainId.MAINNET,
        ERC20_ADDRESS,
        18,
        await ERC20_CONTRACT.methods.symbol().call(),
        await ERC20_CONTRACT.methods.name().call()
    )

    // Fetch price of SHIB/WETH before we execute the swap
    const priceBefore = await calculatePrice(pairContract)

    await manipulatePrice(token, account)

    // Fetch price of SHIB/WETH after the swap
    const priceAfter = await calculatePrice(pairContract)

    const data = {
        'Price Before': `1 ${WETH[chainId].symbol} = ${Number(priceBefore).toFixed(0)} ${token.symbol}`,
        'Price After': `1 ${WETH[chainId].symbol} = ${Number(priceAfter).toFixed(0)} ${token.symbol}`,
    }

    console.table(data)

    let balance = await WETH_CONTRACT.methods.balanceOf(account).call()
    balance = web3.utils.fromWei(balance.toString(), 'ether')

    console.log(`\nBalance in reciever account: ${balance} WETH\n`)
}

main()

// 

async function manipulatePrice(token, account) {
    console.log(`\nBeginning Swap...\n`)

    console.log(`Input Token: ${token.symbol}`)
    console.log(`Output Token: ${WETH[chainId].symbol}\n`)

    const amountIn = new web3.utils.BN(
        web3.utils.toWei(AMOUNT, 'ether')
    )

    const path = [token.address, WETH[chainId].address]
    const deadline = Math.floor(Date.now() / 1000) + 60 * 20 // 20 minutes

    await ERC20_CONTRACT.methods.approve(V2_ROUTER_TO_USE._address, amountIn).send({ from: UNLOCKED_ACCOUNT })
    const receipt = await V2_ROUTER_TO_USE.methods.swapExactTokensForTokens(amountIn, 0, path, account, deadline).send({ from: UNLOCKED_ACCOUNT, gas: GAS });

    console.log(`Swap Complete!\n`)

    return receipt
}

我自己遇到了同一个机器人的这个问题,我找到了解决方案。 而不是使用.send你应该使用.sendSignedTransaction并用正确的参数自己签名。 但是,如果您从未锁定的帐户发送,请使用 ethers.js 在不知道私钥的情况下获得签名者!

所以,你应该更换

await ERC20_CONTRACT.methods.approve(V2_ROUTER_TO_USE._address, amountIn).send({ from: UNLOCKED_ACCOUNT })
const receipt = await V2_ROUTER_TO_USE.methods.swapExactTokensForTokens(amountIn, 0, path, account, deadline).send({ from: UNLOCKED_ACCOUNT, gas: GAS });

有了这个 ethers.js 替代品

const { ethers } = require("ethers")
const provider = new ethers.providers.JsonRpcProvider("http://127.0.0.1:8545")
const signer = provider.getSigner(UNLOCKED_ACCOUNT)
console.log(provider.chainId)

/*
    Define the above code at the top,
    Then put the rest of your code here, 
    Then use this for the ethers transaction
*/

const approvalReceiptEthers = await signer.sendTransaction({
    from: UNLOCKED_ACCOUNT,
    to: ERC20_CONTRACT._address,
    data: ERC20_CONTRACT.methods.approve(V2_ROUTER_TO_USE._address, web3.utils.fromWei(amountIn).toString()).encodeABI(),
    gasLimit: GAS
})

/*
 * Verify that your unlocked account is allowed to use the funds
*/
var allowance = await ERC20_CONTRACT.methods.allowance(UNLOCKED_ACCOUNT, V2_ROUTER_TO_USE._address).call()
console.log("ALLOWANCE:\t\t", web3.utils.fromWei(allowance).toString(), 'ether')
console.log("ATTEMPTED AMOUNT:\t", web3.utils.fromWei(amountIn).toString(), 'ether')


const swapReceiptEthers = await signer.sendTransaction({
    from: UNLOCKED_ACCOUNT,
    to: V2_ROUTER_TO_USE._address,
    data: V2_ROUTER_TO_USE.methods.swapExactTokensForTokens(web3.utils.fromWei(amountIn).toString(), 0, path, account, deadline).encodeABI(),
    gasLimit: GAS
}).then(console.log)

注意:以下代码仅在您使用发件人的私钥签署交易时才有效。 因此,如果您代表自己的帐户发送交易,请使用此代码(大概用于 bot.js)

const approvalTransaction = {
    'from' : 'your account address here',
    'to' : ERC20_CONTRACT._address,
    'data' : ERC20_CONTRACT.methods.approve(V2_ROUTER_TO_USE._address, web3.utils.fromWei(amountIn).toString()).encodeABI(),
    'gas' : GAS
}
const transaction = {
    'from' : 'your account address here',
    'to' : V2_ROUTER_TO_USE._address,
    'data' : V2_ROUTER_TO_USE.methods.swapExactTokensForTokens(web3.utils.fromWei(amountIn).toString(), 0, path, account, deadline).encodeABI(),
    'gas' : GAS
    
}
const signedApprovalTx = await web3.eth.accounts.signTransaction(approvalTransaction, process.env.DEPLOYMENT_ACCOUNT_KEY, )
const signedTx = await web3.eth.accounts.signTransaction(transaction, process.env.DEPLOYMENT_ACCOUNT_KEY)

await web3.eth.sendSignedTransaction(signedApprovalTx.rawTransaction)
const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction)

注意:对于那些学习相同 Trading Bot 大师班的人来说,同样的逻辑也适用于bot.js代码,当您执行交易时。

摘要:如果您使用带有 ganache-cli 的解锁帐户发送签名交易,您将需要使用 ethers.js 在不知道私钥的情况下对消息进行签名。 否则,如果您代表自己发送已签名的交易,则可以使用 Web3.js 以您自己的私有身份对消息进行签名

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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