深入浅出的分析一下dodo闪电贷

最近两三年,闪电贷比较流行,也有不少的分析文章。最近深入的研究了一下dodo闪电贷,分享给大家。话不多说,先上源码。//Thisisafilecopiedfromhttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/

最近两三年,闪电贷比较流行,也有不少的分析文章。最近深入的研究了一下dodo闪电贷,分享给大家。 话不多说,先上源码。

// This is a file copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
//导入IERC20接口,这个就不用讲解了。
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function decimals() external view returns (uint8);
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);
}
//这里导入币安的路由接口,方便举例子。
interface IPancakeRouter01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);
    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

// File: contracts\interfaces\IPancakeRouter02.sol

pragma solidity >=0.6.2;

interface IPancakeRouter02 is IPancakeRouter01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}
interface IDODO {
    function flashLoan(
        uint256 baseAmount,
        uint256 quoteAmount,
        address assetTo,
        bytes calldata data
    ) external;

    function _BASE_TOKEN_() external view returns (address);
}

contract DODOFlashloan {

    //flashLoanPool:0x0fe261aeE0d1C4DFdDee4102E82Dd425999065F4
    //flashLoanPool:0x6ddcc16c80a08de35866a5e173a25502d4a940da
    //flashLoanPool:0xbdc7df7bb398e40125d7f82176a7d2f23e64ad06
    //loanToken:0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
    address wbnb=0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
    address usdt=0x55d398326f99059fF775485246999027B3197955;
    address router=0x10ED43C718714eb63d5aA57B78B54704E256024E;
    //借贷的主函数。这个函数不用动,基本上就是照抄就可以了。
     //1、flashloanpool如何查找,看后面的说明。
    //2、loanAmount怎么确认?
    //3、loantoken在哪里查找?
    function dodoFlashLoan(
        address flashLoanPool, //You will make a flashloan from this DODOV2 pool
        uint256 loanAmount, 
        address loanToken
    ) external  {
        bytes memory data = abi.encode(flashLoanPool, loanToken, loanAmount);
        address flashLoanBase = IDODO(flashLoanPool)._BASE_TOKEN_();
        //这个函数说明一下。_BASE_TOKEN是POOL池中,会有两个币对,那个币做为主要币种的。比如,wbnb/usdt,那么,_BASE_TOKEN就是wbnb
        if(flashLoanBase == loanToken) {
        //下面这个判断,就是看我们要借贷那一种币,如果是_BASE_TOKEN,那么,合约就会把loanAmount数量的币转到我们的合约地址,0是另一种币。
            IDODO(flashLoanPool).flashLoan(loanAmount, 0, address(this), data);
        } else {
            IDODO(flashLoanPool).flashLoan(0, loanAmount, address(this), data);
        }
    }

    function DVMFlashLoanCall(address sender, uint256 baseAmount, uint256 quoteAmount,bytes calldata data) external {
    //我这里只是写了一个简单的兑换,就是将借来的wbnb兑换成usdt,这里就会有一个比较有意思的问题。如果我们部署了合约,直接调用的话,就会出错,主要问题就是我们把借来的wbnb兑换成usdt了,没有足够的币还给借贷池,执行就出错了,所以,在执行借贷之前,需要先向合约里转大于我们借贷值的wbnb.
       address[] memory path1 = new address[](2);
        IERC20(wbnb).approve(router,2**256-1);
        path1[0] = wbnb;

        path1[1] = usdt;
        //这个就是一个简单的池子兑换函数
        IPancakeRouter02(router).swapExactTokensForTokens(
        baseAmount,
        0,
        path1,
        address(this),
        block.timestamp+12000
         );

        //过程执行完成 ,将借来的wbnb原数返还。
        _flashLoanCallBack(sender,baseAmount,quoteAmount,data);
        //下面两句,比较重要,一定要将我们换回的币和多余的wbnb转回我们自己的钱包或者合约,否则,这些币就会死在合约中。当然了,你加一个提现函数也是可以的,不过要手工调用几次,比较麻烦。
        IERC20(usdt).transfer(tx.origin, IERC20(usdt).balanceOf(address(this)));
        IERC20(wbnb).transfer(tx.origin, IERC20(wbnb).balanceOf(address(this)));
    }
    event test(uint,address[]);

    function DPPFlashLoanCall(address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data)  external {

        _flashLoanCallBack(sender,baseAmount,quoteAmount,data);

    }

    //Note: CallBack function executed by DODOV2(DSP) flashLoan pool
    function DSPFlashLoanCall(address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data) external {
        _flashLoanCallBack(sender,baseAmount,quoteAmount,data);

    }

    function _flashLoanCallBack(address sender, uint256, uint256, bytes calldata data) internal {
        (address flashLoanPool, address loanToken, uint256 loanAmount) = abi.decode(data, (address, address, uint256));

        require(sender == address(this) && msg.sender == flashLoanPool, "HANDLE_FLASH_NENIED");

        IERC20(loanToken).transfer(flashLoanPool, loanAmount);
    }
}

1、flashloanpool如何查找,看后面的说明。 打开https://app.dodoex.io/pool?network=bsc-mainnet,然后点左边的流动池,选择您要使用的链,选择您要选择的币种。

image.png 点击复制池子的address.然后进入币安链查询。

image.png 首先看一下,是DVM,DPP还是DSP,那么这里就确定着你的主要逻辑,是写在哪个函数中。

2、loanAmount怎么确认? image.png 函数4,表示我们可以借多少个amount,_Base_TOKEN,上面已经讲过了。

image.png 这里可以看到我们每个币种可以借贷的最大数量。 3、loantoken在哪里查找? 用getpari函数,查询这个lp里面的币对组成,就可以查找需要的币种了,当然,你可以直接看到,有经验用更好的方式 。

image.png 有经验的直接在这里就找到了。

  • 原创
  • 学分: 21
  • 分类: DeFi
  • 标签:
点赞 2
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
老树@dapp,智能合约,软件开发
老树@dapp,智能合约,软件开发
江湖只有他的大名,没有他的介绍。