最近两三年,闪电贷比较流行,也有不少的分析文章。最近深入的研究了一下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,然后点左边的流动池,选择您要使用的链,选择您要选择的币种。
点击复制池子的address.然后进入币安链查询。
首先看一下,是DVM,DPP还是DSP,那么这里就确定着你的主要逻辑,是写在哪个函数中。
2、loanAmount怎么确认? 函数4,表示我们可以借多少个amount,_Base_TOKEN,上面已经讲过了。
这里可以看到我们每个币种可以借贷的最大数量。 3、loantoken在哪里查找? 用getpari函数,查询这个lp里面的币对组成,就可以查找需要的币种了,当然,你可以直接看到,有经验用更好的方式 。
有经验的直接在这里就找到了。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!