繁体   English   中英

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

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

我在多边形网络上调用 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 函数没有返回类型。 您应该为函数指定返回类型,例如 function executeOperation(...) external returns (uint256)。

swapV3 和 swapV2 函数应该有返回类型,但它们没有。 您应该为这些函数指定返回类型,例如函数 swapV3(...) 内部返回 (uint256)。

swapV3 函数接受一个 _poolFee 参数,但它没有在函数体中使用。 您应该删除此参数或在函数中使用它。

swapV2 函数没有 _poolFee 参数,但它在 executeOperation 函数中的使用就像它有一样。 您应该向 swapV2 函数添加一个 _poolFee 参数,或者在 executeOperation 函数中删除对它的引用。

暂无
暂无

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

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