在多边形网络上调用flash loans aave时出错,调用池时事务失败"失败";这是我的合同代码和机器人脚本,可能是什么?
脚本机器人程序
require('dotenv').config()
import { ethers } from 'ethers';
import { uniswapV3Price, uniswapV2Price, poolToDex, poolToRouter, colours, IUniswapV3PoolABI, IUniswapV2PairABI, CntrAbi } from './utils';
import { PriceLookup } from './interfaces';
// ============ Provider ============
const provider = new ethers.providers.JsonRpcProvider(process.env.JSON_RPC_PROVIDER as string);
let runCounter = 0;
let oppCounter = 0;
const runMath = async (buyAmount: number, priceList: PriceLookup[]) => {
// Sort the prices
priceList.sort((a, b) => b.token0_1 - a.token0_1);
const tmpList = [];
for (const [_, value] of Object.entries(priceList)) {
tmpList.push({ Exchange: await poolToDex(value.pool), "In / Out": value.token0_1, "Out / In": value.token1_0, "PoolFee (%)": value.poolFee / 10000 })
}
console.table(tmpList);
// Identify where to buy and sell
const buyAt = priceList[0];
const sellAt = priceList[priceList.length - 1];
// ========================
// xToken = TokenIn for BUY
// yToken = TokenOut for BUY
// ========================
console.log(`${colours.FgBlue}============ Swaps ============`);
console.log(`${colours.FgCyan}First Swap:n - xToken: ${buyAmount} = yToken: ${buyAmount * buyAt.token0_1}`);
console.log(`${colours.FgCyan}Second Swap:n - yToken: ${buyAmount * buyAt.token0_1} = xToken: ${buyAmount * buyAt.token0_1 * sellAt.token1_0}`);
console.log(`${colours.FgBlue}============ Profit ============`);
var netProfit = (buyAmount * buyAt.token0_1 * sellAt.token1_0) - buyAmount;
console.log(`${colours.FgRed}After Swaps: ${netProfit}`);
// Flashloan premium
netProfit -= buyAmount * 0.009;
console.log(`${colours.FgRed}After FL Premium: ${netProfit}`);
// Padding
if (parseFloat(process.env.PADDING as string) > 0) {
netProfit -= netProfit * parseFloat(process.env.PADDING as string);
console.log(`After: Padding: ${netProfit}`);
}
console.log(`${colours.FgBlue}========================n${colours.FgGreen}Total: ${netProfit}${colours.Reset}n`);
// Return null if there is no profit
if (netProfit <= 0) return null;
oppCounter++;
return {
buy: {
router: await poolToRouter(buyAt.pool),
tokenIn: "",
poolFee: buyAt.poolFee,
isV3: buyAt.isV3,
},
sell: {
router: await poolToRouter(sellAt.pool),
tokenIn: "",
poolFee: sellAt.poolFee,
isV3: sellAt.isV3,
}
}
}
function poolContract(adr: string, abi: any) {
return new ethers.Contract(adr, abi, provider)
}
let nonceOffset = 0;
async function getNonce(adr: string) {
let baseNonce = await provider.getTransactionCount(adr);
return baseNonce + (nonceOffset++);
}
async function main() {
const signer = new ethers.Wallet(process.env.PRIVATE_KEY as string, provider);
const cntr = new ethers.Contract(process.env.CONTRACT_ADDRESS as string, CntrAbi, signer);
// ============ wMATIC/MANA ============
{
console.log('wMATIC/MANA');
const dat: any = await runMath(10000000.0, [
// https://info.uniswap.org/#/polygon/pools/0x56845fd95C766eCB0ab450fE2D105a19440a6E35
await uniswapV3Price(poolContract('0x56845fd95C766eCB0ab450fE2D105a19440a6E35', IUniswapV3PoolABI), 18, 18, 3000),
// https://info.quickswap.exchange/#/pair/0x6b0Ce31eAD9b14c2281D80A5DDE903AB0855313A
await uniswapV2Price(poolContract('0x6b0Ce31eAD9b14c2281D80A5DDE903AB0855313A', IUniswapV2PairABI), 3000)
]);
if (dat != null) {
dat.buy["tokenIn"] = '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270';
dat.sell["tokenIn"] = '0xA1c57f48F0Deb89f569dFbE6E2B7f46D33606fD4';
let baseNonce = provider.getTransactionCount(signer.address);
let nonceOffset = 0;
await cntr.functions.execute(dat, ethers.utils.parseUnits('10000000.0', 18), { gasLimit: process.env.GAS_LIMIT, gasPrice: process.env.GAS_PRICE ,nonce: await getNonce(signer.address) }).catch(console.error);
}
}
// ============ wETH/MANA ============
{
console.log('wETH/MANA');
const dat: any = await runMath(10000000.0, [
// https://info.uniswap.org/#/polygon/pools/0x28bdd3749bdea624a726ca153de1cb673f459b9d
await uniswapV3Price(poolContract('0x28bdd3749bdea624a726ca153de1cb673f459b9d', IUniswapV3PoolABI), 18, 18, 3000),
// https://info.quickswap.exchange/#/pair/0x814b6c10bf752bbbea7bd68e5e65dc28b4f45982
await uniswapV2Price(poolContract('0x814b6c10bf752bbbea7bd68e5e65dc28b4f45982', IUniswapV2PairABI), 3000)
]);
if (dat != null) {
dat.buy["tokenIn"] = '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619';
dat.sell["tokenIn"] = '0xa1c57f48f0deb89f569dfbe6e2b7f46d33606fd4';
await cntr.functions.execute(dat, ethers.utils.parseUnits('10000000.0', 18), { gasLimit: process.env.GAS_LIMIT, gasPrice: process.env.GAS_PRICE , nonce: await getNonce(signer.address) }).catch(console.error);
}
}
// ============ wMATIC/AVAX ============
{
console.log('wMATIC/AVAX');
const dat: any = await runMath(10000000.0, [
// https://info.uniswap.org/#/polygon/pools/0xfa3f210cbad19c8b860a256d67a400d616a87c2a
await uniswapV3Price(poolContract('0xfa3f210cbad19c8b860a256d67a400d616a87c2a', IUniswapV3PoolABI), 18, 18, 3000),
// https://info.quickswap.exchange/#/pair/0xeb477ae74774b697b5d515ef8ca09e24fee413b5
await uniswapV2Price(poolContract('0xeb477ae74774b697b5d515ef8ca09e24fee413b5', IUniswapV2PairABI), 3000)
]);
if (dat != null) {
dat.buy["tokenIn"] = '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270';
dat.sell["tokenIn"] = '0x2c89bbc92bd86f8075d1decc58c7f4e0107f286b';
await cntr.functions.execute(dat, ethers.utils.parseUnits('10000000.0', 18), { gasLimit: process.env.GAS_LIMIT, gasPrice: process.env.GAS_PRICE , nonce: await getNonce(signer.address) }).catch(console.error);
}
}
// ============ USDC/wETH ============
{
console.log('USDC/wETH');
// https://info.quickswap.exchange/#/pair/0x853ee4b2a13f8a742d64c8f088be7ba2131f670d
const quickSwapData = await uniswapV2Price(poolContract('0x853ee4b2a13f8a742d64c8f088be7ba2131f670d', IUniswapV2PairABI), 3000);
quickSwapData.token0_1 /= 10**12;
quickSwapData.token1_0 *= 10**12;
// ?
const firebirdData = await uniswapV2Price(poolContract('0x853ee4b2a13f8a742d64c8f088be7ba2131f670d', IUniswapV2PairABI), 3000);
firebirdData.token0_1 /= 10**12;
firebirdData.token1_0 *= 10**12;
const dat: any = await runMath(10000000.0, [
// https://info.uniswap.org/#/polygon/pools/0x45dda9cb7c25131df268515131f647d726f50608
await uniswapV3Price(poolContract('0x45dda9cb7c25131df268515131f647d726f50608', IUniswapV3PoolABI), 6, 18, 500),
quickSwapData,
firebirdData
]);
if (dat != null) {
dat.buy["tokenIn"] = '0x2791bca1f2de4661ed88a30c99a7a9449aa84174';
dat.sell["tokenIn"] = '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619';
await cntr.functions.execute(dat, ethers.utils.parseUnits('10000000.0', 6), { gasLimit: process.env.GAS_LIMIT, gasPrice: process.env.GAS_PRICE , nonce: await getNonce(signer.address) }).catch(console.error);
}
}
// ============ wBTC/wETH ============
{
console.log('wBTC/wETH');
// https://info.quickswap.exchange/#/pair/0xdc9232e2df177d7a12fdff6ecbab114e2231198d
const quickSwapData = await uniswapV2Price(poolContract('0xdc9232e2df177d7a12fdff6ecbab114e2231198d', IUniswapV2PairABI), 3000);
quickSwapData.token0_1 /= 10**10;
quickSwapData.token1_0 *= 10**10;
// ?
const firebirdData = await uniswapV2Price(poolContract('0x10f525cfbce668815da5142460af0fcfb5163c81', IUniswapV2PairABI), 3000);
firebirdData.token0_1 /= 10**10;
firebirdData.token1_0 *= 10**10;
const dat: any = await runMath(2, [
// https://info.uniswap.org/#/polygon/pools/0x50eaedb835021e4a108b7290636d62e9765cc6d7
await uniswapV3Price(poolContract('0x50eaedb835021e4a108b7290636d62e9765cc6d7', IUniswapV3PoolABI), 8, 18, 500),
quickSwapData,
firebirdData
]);
if (dat != null) {
dat.buy["tokenIn"] = '0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6';
dat.sell["tokenIn"] = '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619';
await cntr.functions.execute(dat, ethers.utils.parseUnits('5.0', 8), { gasLimit: process.env.GAS_LIMIT, gasPrice: process.env.GAS_PRICE , nonce: await getNonce(signer.address) }).catch(console.error);
}
}
// ============ wMATIC/USDC ============
// https://info.uniswap.org/#/polygon/pools/0xa374094527e1673a86de625aa59517c5de346d32
// https://info.quickswap.exchange/#/pair/0x6e7a5fafcec6bb1e78bae2a1f0b612012bf14827
// ============ wMATIC/wETH ============
// https://info.uniswap.org/#/polygon/pools/0x167384319b41f7094e62f7506409eb38079abff8
// https://info.quickswap.exchange/#/pair/0xadbf1854e5883eb8aa7baf50705338739e558e5b
// ============ wMATIC/USDT ============
// https://info.uniswap.org/#/polygon/pools/0x781067ef296e5c4a4203f81c593274824b7c185d
// https://info.quickswap.exchange/#/pair/0x604229c960e5cacf2aaeac8be68ac07ba9df81c3
// ========================
runCounter++;
console.log(`(${runCounter}/${oppCounter}) Finished. Awaiting next call.`);
}
main();
setInterval(main, 1000 * parseInt(process.env.REQUEST_INTERVAL as string));
合同
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
pragma abicoder v2;
import {IERC20} from "./interfaces/IERC20.sol";
// Aave
import {FlashLoanReceiverBase} from "./utils/FlashLoanReceiverBase.sol";
import {ILendingPoolAddressesProvider} from "./interfaces/ILendingPoolAddressesProvider.sol";
import {ILendingPool} from "./interfaces/ILendingPool.sol";
// UniswapV3
import "./interfaces/ISwapRouter.sol";
import "./libraries/TransferHelper.sol";
// UniswapV2
import "./interfaces/IUniswapV2Router02.sol";
contract Arbitrage is FlashLoanReceiverBase {
address public immutable minter;
struct SwapInfo {
address router;
address tokenIn;
uint24 poolFee;
bool isV3;
}
struct ArbitInfo {
SwapInfo buy;
SwapInfo sell;
}
constructor(address _flashAddrProvider) FlashLoanReceiverBase(_flashAddrProvider) {
minter = msg.sender;
}
modifier minterOnly {
require(msg.sender == minter, "MO"); // Minter Only
_;
}
function execute(ArbitInfo memory _data, uint256 _amount) external {
ILendingPool lendingPool = ILendingPool(addressesProvider.getLendingPool());
lendingPool.flashLoan(address(this), _data.buy.tokenIn, _amount, abi.encode(_data));
}
function cashOut(address _token, address _receiver) external minterOnly {
uint256 bal = IERC20(_token).balanceOf(address(this));
require(bal > 0, "CO: NEF"); // Not enough funds
TransferHelper.safeTransfer(_token, _receiver, bal);
}
// ============ Callback ============
function executeOperation(address _reserve, uint256 _amount, uint256 _fee, bytes calldata _params) external {
require(msg.sender == addressesProvider.getLendingPool(), "MC"); // Malicious Callback
require(_amount <= getBalanceInternal(address(this), _reserve), "IIB"); // Invalid Internal Balance
// =====================================
ArbitInfo memory decoded = abi.decode(_params, (ArbitInfo));
// ============ Buy ============
uint256 sellAmount;
// If the router is uniswap v3
if (decoded.buy.isV3) {
// Buy at V3
sellAmount = swapV3(decoded.buy.router, _reserve, decoded.sell.tokenIn, decoded.buy.poolFee, _amount);
} else {
// Else, buy at V2
sellAmount = swapV2(decoded.buy.router, _reserve, decoded.sell.tokenIn, _amount);
}
// ============ Sell ============
// If the router is uniswap v3
if (decoded.sell.isV3) {
// Sell at V3
swapV3(decoded.sell.router, decoded.sell.tokenIn, _reserve, decoded.sell.poolFee, sellAmount);
} else {
// Else, sell at V2
swapV2(decoded.sell.router, decoded.sell.tokenIn, _reserve, sellAmount);
}
// =====================================
uint256 totalDebt = _amount + _fee;
transferFundsBackToPoolInternal(_reserve, totalDebt);
}
// ============ Swaps ============
function swapV3(address _router, address _in, address _out, uint24 _fee, uint256 _amount) private returns (uint256) {
// Check for funds
require(_amount > 0, "V3: NA"); // Naught amount
require(IERC20(_in).balanceOf(address(this)) >= _amount, "V3: NEF"); // Not enough funds
// Approve the swap
TransferHelper.safeApprove(_in, address(_router), _amount);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: _in,
tokenOut: _out,
fee: _fee,
recipient: msg.sender,
deadline: block.timestamp,
amountIn: _amount,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
uint256 output = ISwapRouter(_router).exactInputSingle(params);
return output;
}
function swapV2(address _router, address _in, address _out, uint256 _amount) private returns (uint256) {
// Check for funds
require(_amount > 0, "V2: NA"); // Naught amount
require(IERC20(_in).balanceOf(address(this)) >= _amount, "V2: NEF"); // Not enough funds
// Approve the swap
TransferHelper.safeApprove(_in, address(_router), _amount);
address[] memory path = new address[](2);
path[0] = _in;
path[1] = _out;
require(IERC20(_in).approve(_router, _amount), "V2: AF"); // Approval failed
uint[] memory output = IUniswapV2Router02(_router).swapExactTokensForTokens(_amount, 0, path, msg.sender, block.timestamp);
return output[0];
}
}
ArbitInfo结构没有定义的tokenOut字段,但它在swapV3和swapV2函数中被引用作为第二个参数。您应该在结构中定义一个tokenOut字段,或者传递正确的令牌地址作为第二个参数。
swapV3和swapV2功能未在合同中定义。您应该定义这些函数或删除对它们的调用。
execute函数中的flashLoan函数以错误的顺序接收_amount和_data参数。_amount参数应该是第一个参数,然后是_data参数。
executeOperation函数没有返回类型。您应该为函数指定一个返回类型,例如函数executeOperation(…(外部返回(uint256(。
swapV3和swapV2函数应该有一个返回类型,但它们没有。您应该为这些函数指定一个返回类型,例如函数swapV3(…(内部返回(uint256(。
swapV3函数采用_poolFee参数,但在函数体中未使用该参数。您应该删除此参数,或者在函数中使用它。
swapV2函数没有_poolFee参数,但它在executeOperation函数中的使用方式与它一样。您应该向swapV2函数添加_poolFee参数,或者在executeOperation函数中删除对它的引用。