简体   繁体   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

I am using the code from Dapp Unversity's trading bot masterclass to try to create a bot that will scan cryptocurrency decentralized exchanges for price differences in token pairs and then execute a smart contract to use a flash loan to profit off of this.我正在使用 Dapp 大学的交易机器人大师班的代码来尝试创建一个机器人,该机器人将扫描加密货币去中心化交易所以获取代币对的价格差异,然后执行智能合约以使用 flash 贷款从中获利。 When testing, I am able to see run a ganache-cli node and run my scanning bot to listen for swap opportunities on ganache.测试时,我能够看到运行一个 ganache-cli 节点并运行我的扫描机器人以侦听 ganache 上的交换机会。 There is a script designed to create a swap opportunity by swapping a large amount of SHIB for WETH on the test.net to see if the smart contract will deploy and execute when a swap opportunity is detected by the bot.有一个脚本旨在通过在 test.net 上将大量 SHIB 换成 WETH 来创建交换机会,以查看智能合约是否会在机器人检测到交换机会时部署和执行。 However, running this script yields the error但是,运行此脚本会产生错误

UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert TransferHelper: TRANSFER_FROM_FAILED UnhandledPromiseRejectionWarning:错误:返回错误:处理事务时出现VM异常:还原TransferHelper:TRANSFER_FROM_FAILED

Also, in the ganache-cli terminal, I get:此外,在 ganache-cli 终端中,我得到:

Runtime Error: revert Revert reason: TransferHelper: TRANSFER_FROM_FAILED运行时错误:还原还原原因:TransferHelper:TRANSFER_FROM_FAILED

Here are the commands I run to get to the points above: First, I successfully run ganache-cli -f wss://eth-mai.net.alchemyapi.io/v2/<Your-App-Key> -u 0x0e5069514a3dd613350bab01b58fd850058e5ca4 -p 7545 with my app key.以下是我为达到上述目的而运行的命令:首先,我成功运行了ganache-cli -f wss://eth-mai.net.alchemyapi.io/v2/<Your-App-Key> -u 0x0e5069514a3dd613350bab01b58fd850058e5ca4 -p 7545与我的应用程序密钥。 Then, I successfully run node bot.js in another terminal to scan for swap opportunities on ganache.然后,我在另一个终端成功运行了node bot.js来扫描 ganache 上的交换机会。 Finally, I run node scripts\manipulatePrice.JS which outputs "Beginnig Swap... Input token: SHIB Output token: WETH" before outputting the above error.最后,我运行node scripts\manipulatePrice.JS ,输出“Beginnig Swap... Input token: SHIB Output token: WETH”,然后输出上述错误。

I have tried using node --trace-warnings to show where the warning was created, but was led nowhere helpful.我尝试使用node --trace-warnings来显示警告的创建位置,但没有任何帮助。 I am wondering if it has something to do with the Runtime Error: revert message?我想知道它是否与运行时错误有关:还原消息? Below is the code for the manipulatePrice.js script I am trying to run to test my bot.下面是我试图运行以测试我的机器人的 manipulatePrice.js 脚本的代码。 I can attach more code if need be, but don't want to post too much.如果需要,我可以附加更多代码,但不想发布太多。 If anyone has insight as to what or where the issue might be, I would greatly appreciate it!!如果有人知道问题出在哪里或出在哪里,我将不胜感激!!

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
}

I ran into this issue for the same bot myself and I found the solution.我自己遇到了同一个机器人的这个问题,我找到了解决方案。 Instead of using .send you should use .sendSignedTransaction and sign it yourself with the correct parameters.而不是使用.send你应该使用.sendSignedTransaction并用正确的参数自己签名。 BUT if you are sending from an unlocked account, then use ethers.js to get a signer without knowing the private key!但是,如果您从未锁定的帐户发送,请使用 ethers.js 在不知道私钥的情况下获得签名者!

So, you should replace所以,你应该更换

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

With this ethers.js alternative有了这个 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)

Note: the following code, will only work provided that you signed the transaction with THE SENDER'S PRIVATE KEY.注意:以下代码仅在您使用发件人的私钥签署交易时才有效。 So, if you are sending a transaction on behalf of your own account, use this code (presumably for bot.js)因此,如果您代表自己的帐户发送交易,请使用此代码(大概用于 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)

NOTE : For those of you following the same Trading Bot masterclass, this same logic applies to the bot.js code as well when you execute your trade..注意:对于那些学习相同 Trading Bot 大师班的人来说,同样的逻辑也适用于bot.js代码,当您执行交易时。

SUMMARY: If you are sending a signed transaction using an unlocked account with ganache-cli, you will need to use ethers.js to sign the message without knowing the private key.摘要:如果您使用带有 ganache-cli 的解锁帐户发送签名交易,您将需要使用 ethers.js 在不知道私钥的情况下对消息进行签名。 Otherwise if you are sending a signed transaction on behalf of yourself, you can use Web3.js to sign the message with your own private否则,如果您代表自己发送已签名的交易,则可以使用 Web3.js 以您自己的私有身份对消息进行签名

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

相关问题 错误:处理事务时出现 VM 异常:还原 - Error : VM Exception while processing transaction: revert 在终端中使用“node bot.js”运行程序时出错 - Error when running program using "node bot.js" in the terminal 错误:调用还原异常; 处理事务时出现 VM 异常: - Error: call revert exception; VM Exception while processing transaction: 无法弄清楚为什么在处理事务时出现 VM 异常:恢复错误 - Cannot figure out why I am getting VM Exception while processing transaction: revert error Discord bot.js 中的 BOT 错误(语法错误:无效或意外的令牌) - Discord BOT ERROR in bot.js (SyntaxError: Invalid or unexpected token) Discord机器人显示离线,bot.js中出现ReferenceError - Discord bot showing offline, ReferenceError in bot.js “node bot.js”不在 heroku 中运行 - “node bot.js” doesn't run in heroku web3 - 处理事务时出现 VM 异常:gas 耗尽 - web3 - VM Exception while processing transaction: out of gas 使用 Knex.js 还原已提交的事务 - Revert a committed transaction with Knex.js 错误:处理交易时出现 VM 异常:已恢复,原因字符串为“您需要花费更多 ETH!” - Error: VM Exception while processing transaction: reverted with reason string 'You need to spend more ETH!'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM