简体   繁体   English

在调用贷款池时,在多边形网络上调用快速贷款 aave 时出现“失败”错误

[英]I am getting "fail" error when calling flash loans aave on polygon network, when calling the loan pool

I am having error when calling flash loans aave on polygon network, when calling the pool the transaction fails "fail" here is my contract code and my bot script, what could it be?我在多边形网络上调用 flash loans aave 时出错,调用池时交易失败“失败”这是我的合同代码和我的机器人脚本,它可能是什么?

SCRIPT BOT脚本机器人

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

CONTRACT合同

// 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];
    }
}

The ArbitInfo struct does not have a defined tokenOut field, but it is referenced in the swapV3 and swapV2 functions as the second argument. ArbitInfo 结构没有定义的 tokenOut 字段,但它在 swapV3 和 swapV2 函数中被引用为第二个参数。 You should define a tokenOut field in the struct or pass the correct token address as the second argument.您应该在结构中定义一个 tokenOut 字段或将正确的令牌地址作为第二个参数传递。

The swapV3 and swapV2 functions are not defined in the contract.合约中没有定义 swapV3 和 swapV2 函数。 You should either define these functions or remove the calls to them.您应该定义这些函数或删除对它们的调用。

The flashLoan function in the execute function takes the _amount and _data arguments in the wrong order. execute 函数中的 flashLoan 函数以错误的顺序获取 _amount 和 _data 参数。 The _amount argument should be the first argument, followed by the _data argument. _amount 参数应该是第一个参数,然后是 _data 参数。

The executeOperation function does not have a return type. executeOperation 函数没有返回类型。 You should specify a return type for the function, for example function executeOperation(...) external returns (uint256).您应该为函数指定返回类型,例如 function executeOperation(...) external returns (uint256)。

The swapV3 and swapV2 functions should have a return type, but they do not. swapV3 和 swapV2 函数应该有返回类型,但它们没有。 You should specify a return type for these functions, for example function swapV3(...) internal returns (uint256).您应该为这些函数指定返回类型,例如函数 swapV3(...) 内部返回 (uint256)。

The swapV3 function takes a _poolFee argument, but it is not used in the function body. swapV3 函数接受一个 _poolFee 参数,但它没有在函数体中使用。 You should either remove this argument or use it in the function.您应该删除此参数或在函数中使用它。

The swapV2 function does not have a _poolFee argument, but it is used in the executeOperation function as if it does. swapV2 函数没有 _poolFee 参数,但它在 executeOperation 函数中的使用就像它有一样。 You should either add a _poolFee argument to the swapV2 function or remove the reference to it in the executeOperation function.您应该向 swapV2 函数添加一个 _poolFee 参数,或者在 executeOperation 函数中删除对它的引用。

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

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