[英]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.