├── .gitignore ├── README.md └── aave_v2_flashloan ├── README.md ├── contracts ├── Flashloan.sol ├── Migrations.sol ├── aave │ ├── FlashLoanReceiverBase.sol │ ├── IFlashLoanReceiver.sol │ ├── ILendingPool.sol │ └── ILendingPoolAddressesProvider.sol └── utils │ └── Withdrawable.sol ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── truffle-config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # Truffle contract build files 107 | build/ 108 | 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 免责申明 2 | 本项目代码仅供学习交流,请谨慎使用。 3 | ### 搭建开发环境 4 | ``` 5 | npm install -g ganache-cli 6 | npm install -g truffle 7 | npm install -g yarn 8 | ``` 9 | ### 进入子目录执行demo -------------------------------------------------------------------------------- /aave_v2_flashloan/README.md: -------------------------------------------------------------------------------- 1 | ### 写在前面 2 | 这个flashloan demo来源于[aave官方github](https://github.com/aave/flashloan-box),做了适当修改才成功跑通。 3 | 4 | ### 开发环境准备 5 | 按照项目根目录下的README.md安装cli工具 6 | 进入目录 7 | ``` 8 | cd aave_v2_flashloan 9 | ``` 10 | 安装package.json依赖 11 | ``` 12 | yarn 13 | ``` 14 | 设置环境变量 15 | ``` 16 | export BOT_MNEMONIC="测试账号的助记词" 17 | export BOT_PRIVATE_KEY="测试账号的私钥" 18 | export BOT_ACCOUNT="测试账号地址" 19 | export BOT_INFURA_KEY="你的infura主网key" 20 | ``` 21 | Fork主网到本地节点 22 | ``` 23 | ganache-cli --fork https://mainnet.infura.io/v3/$BOT_INFURA_KEY -i 1 -m "$BOT_MNEMONIC" 24 | ``` 25 | * 保持监听状态,监听地址127.0.0.1:8545已配置到truffle-config.js中。 26 | * 看输出可以发现,BOT_ACCOUNT在本地节点有1000ETH。 27 | 28 | ### 使用truffle进行闪电贷 29 | 进入truffle console: 30 | ``` 31 | truffle console --network development 32 | ``` 33 | 部署合约: 34 | ``` 35 | migrate --reset 36 | let f = await Flashloan.deployed() 37 | ``` 38 | 第一次查询合约ETH余额: 39 | ``` 40 | await web3.eth.getBalance(f.address) 41 | ``` 42 | 向合约转账,使得没有盈利逻辑也能完成闪电贷: 43 | ``` 44 | f.send(web3.utils.toWei("1", "ether")).then(function(result) {}); 45 | ``` 46 | 第二次查询合约ETH余额: 47 | ``` 48 | await web3.eth.getBalance(f.address) 49 | ``` 50 | 进行闪电贷,从aave借出ETH: 51 | ``` 52 | await f.flashloan("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") 53 | ``` 54 | 第三次查询合约ETH余额: 55 | ``` 56 | await web3.eth.getBalance(f.address) 57 | ``` 58 | 闪电贷结束。 59 | -------------------------------------------------------------------------------- /aave_v2_flashloan/contracts/Flashloan.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.6; 2 | 3 | import "./aave/FlashLoanReceiverBase.sol"; 4 | import "./aave/ILendingPoolAddressesProvider.sol"; 5 | import "./aave/ILendingPool.sol"; 6 | 7 | contract Flashloan is FlashLoanReceiverBase { 8 | 9 | constructor(address _addressProvider) FlashLoanReceiverBase(_addressProvider) public {} 10 | 11 | /** 12 | This function is called after your contract has received the flash loaned amount 13 | */ 14 | function executeOperation( 15 | address _reserve, 16 | uint256 _amount, 17 | uint256 _fee, 18 | bytes calldata _params 19 | ) 20 | external 21 | override 22 | { 23 | require(_amount <= getBalanceInternal(address(this), _reserve), "Invalid balance, was the flashLoan successful?"); 24 | 25 | // 26 | // Your logic goes here. 27 | // !! Ensure that *this contract* has enough of `_reserve` funds to payback the `_fee` !! 28 | // 29 | 30 | uint totalDebt = _amount.add(_fee); 31 | transferFundsBackToPoolInternal(_reserve, totalDebt); 32 | } 33 | 34 | /** 35 | Flash loan 1000000000000000000 wei (1 ether) worth of `_asset` 36 | */ 37 | function flashloan(address _asset) public onlyOwner { 38 | bytes memory data = ""; 39 | uint amount = 1 ether; 40 | 41 | ILendingPool lendingPool = ILendingPool(addressesProvider.getLendingPool()); 42 | lendingPool.flashLoan(address(this), _asset, amount, data); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /aave_v2_flashloan/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // This file is part of Truffle suite and helps keep track of your deployments 2 | 3 | pragma solidity >=0.4.21 <0.7.0; 4 | 5 | contract Migrations { 6 | address public owner; 7 | uint public last_completed_migration; 8 | 9 | constructor() public { 10 | owner = msg.sender; 11 | } 12 | 13 | modifier restricted() { 14 | if (msg.sender == owner) _; 15 | } 16 | 17 | function setCompleted(uint completed) public restricted { 18 | last_completed_migration = completed; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /aave_v2_flashloan/contracts/aave/FlashLoanReceiverBase.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.6; 2 | 3 | import "@openzeppelin/contracts/math/SafeMath.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; 6 | import "./IFlashLoanReceiver.sol"; 7 | import "./ILendingPoolAddressesProvider.sol"; 8 | import "../utils/Withdrawable.sol"; 9 | 10 | abstract contract FlashLoanReceiverBase is IFlashLoanReceiver, Withdrawable { 11 | 12 | using SafeERC20 for IERC20; 13 | using SafeMath for uint256; 14 | 15 | address constant ethAddress = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; 16 | ILendingPoolAddressesProvider public addressesProvider; 17 | 18 | constructor(address _addressProvider) public { 19 | addressesProvider = ILendingPoolAddressesProvider(_addressProvider); 20 | } 21 | 22 | receive() payable external {} 23 | 24 | function transferFundsBackToPoolInternal(address _reserve, uint256 _amount) internal { 25 | address payable core = addressesProvider.getLendingPoolCore(); 26 | transferInternal(core, _reserve, _amount); 27 | } 28 | 29 | function transferInternal(address payable _destination, address _reserve, uint256 _amount) internal { 30 | if(_reserve == ethAddress) { 31 | (bool success, ) = _destination.call{value: _amount}(""); 32 | require(success == true, "Couldn't transfer ETH"); 33 | return; 34 | } 35 | IERC20(_reserve).safeTransfer(_destination, _amount); 36 | } 37 | 38 | function getBalanceInternal(address _target, address _reserve) internal view returns(uint256) { 39 | if(_reserve == ethAddress) { 40 | return _target.balance; 41 | } 42 | return IERC20(_reserve).balanceOf(_target); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /aave_v2_flashloan/contracts/aave/IFlashLoanReceiver.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.6; 2 | 3 | /** 4 | * @title IFlashLoanReceiver interface 5 | * @notice Interface for the Aave fee IFlashLoanReceiver. 6 | * @author Aave 7 | * @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract 8 | **/ 9 | interface IFlashLoanReceiver { 10 | function executeOperation(address _reserve, uint256 _amount, uint256 _fee, bytes calldata _params) external; 11 | } -------------------------------------------------------------------------------- /aave_v2_flashloan/contracts/aave/ILendingPool.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.6; 2 | 3 | interface ILendingPool { 4 | function addressesProvider () external view returns ( address ); 5 | function deposit ( address _reserve, uint256 _amount, uint16 _referralCode ) external payable; 6 | function redeemUnderlying ( address _reserve, address _user, uint256 _amount ) external; 7 | function borrow ( address _reserve, uint256 _amount, uint256 _interestRateMode, uint16 _referralCode ) external; 8 | function repay ( address _reserve, uint256 _amount, address _onBehalfOf ) external payable; 9 | function swapBorrowRateMode ( address _reserve ) external; 10 | function rebalanceFixedBorrowRate ( address _reserve, address _user ) external; 11 | function setUserUseReserveAsCollateral ( address _reserve, bool _useAsCollateral ) external; 12 | function liquidationCall ( address _collateral, address _reserve, address _user, uint256 _purchaseAmount, bool _receiveAToken ) external payable; 13 | function flashLoan ( address _receiver, address _reserve, uint256 _amount, bytes calldata _params ) external; 14 | function getReserveConfigurationData ( address _reserve ) external view returns ( uint256 ltv, uint256 liquidationThreshold, uint256 liquidationDiscount, address interestRateStrategyAddress, bool usageAsCollateralEnabled, bool borrowingEnabled, bool fixedBorrowRateEnabled, bool isActive ); 15 | function getReserveData ( address _reserve ) external view returns ( uint256 totalLiquidity, uint256 availableLiquidity, uint256 totalBorrowsFixed, uint256 totalBorrowsVariable, uint256 liquidityRate, uint256 variableBorrowRate, uint256 fixedBorrowRate, uint256 averageFixedBorrowRate, uint256 utilizationRate, uint256 liquidityIndex, uint256 variableBorrowIndex, address aTokenAddress, uint40 lastUpdateTimestamp ); 16 | function getUserAccountData ( address _user ) external view returns ( uint256 totalLiquidityETH, uint256 totalCollateralETH, uint256 totalBorrowsETH, uint256 availableBorrowsETH, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor ); 17 | function getUserReserveData ( address _reserve, address _user ) external view returns ( uint256 currentATokenBalance, uint256 currentUnderlyingBalance, uint256 currentBorrowBalance, uint256 principalBorrowBalance, uint256 borrowRateMode, uint256 borrowRate, uint256 liquidityRate, uint256 originationFee, uint256 variableBorrowIndex, uint256 lastUpdateTimestamp, bool usageAsCollateralEnabled ); 18 | function getReserves () external view; 19 | } -------------------------------------------------------------------------------- /aave_v2_flashloan/contracts/aave/ILendingPoolAddressesProvider.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.6; 2 | 3 | /** 4 | @title ILendingPoolAddressesProvider interface 5 | @notice provides the interface to fetch the LendingPoolCore address 6 | */ 7 | 8 | interface ILendingPoolAddressesProvider { 9 | function getLendingPoolCore() external view returns (address payable); 10 | function getLendingPool() external view returns (address); 11 | } -------------------------------------------------------------------------------- /aave_v2_flashloan/contracts/utils/Withdrawable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.6; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | /** 8 | Ensures that any contract that inherits from this contract is able to 9 | withdraw funds that are accidentally received or stuck. 10 | */ 11 | 12 | contract Withdrawable is Ownable { 13 | using SafeERC20 for ERC20; 14 | address constant ETHER = address(0); 15 | 16 | event LogWithdraw( 17 | address indexed _from, 18 | address indexed _assetAddress, 19 | uint amount 20 | ); 21 | 22 | /** 23 | * @dev Withdraw asset. 24 | * @param _assetAddress Asset to be withdrawn. 25 | */ 26 | function withdraw(address _assetAddress) public onlyOwner { 27 | uint assetBalance; 28 | if (_assetAddress == ETHER) { 29 | address self = address(this); // workaround for a possible solidity bug 30 | assetBalance = self.balance; 31 | msg.sender.transfer(assetBalance); 32 | } else { 33 | assetBalance = ERC20(_assetAddress).balanceOf(address(this)); 34 | ERC20(_assetAddress).safeTransfer(msg.sender, assetBalance); 35 | } 36 | emit LogWithdraw(msg.sender, _assetAddress, assetBalance); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /aave_v2_flashloan/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = deployer => { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /aave_v2_flashloan/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | let Flashloan = artifacts.require("Flashloan") 2 | 3 | module.exports = async function (deployer, network) { 4 | try { 5 | 6 | let lendingPoolAddressesProviderAddress; 7 | 8 | switch(network) { 9 | case "mainnet": 10 | case "mainnet-fork": 11 | case "development": // For Ganache mainnet forks 12 | lendingPoolAddressesProviderAddress = "0x24a42fD28C976A61Df5D00D0599C34c4f90748c8"; break 13 | case "ropsten": 14 | case "ropsten-fork": 15 | lendingPoolAddressesProviderAddress = "0x1c8756FD2B28e9426CDBDcC7E3c4d64fa9A54728"; break 16 | case "kovan": 17 | case "kovan-fork": 18 | lendingPoolAddressesProviderAddress = "0x506B0B2CF20FAA8f38a4E2B524EE43e1f4458Cc5"; break 19 | default: 20 | throw Error(`Are you deploying to the correct network? (network selected: ${network})`) 21 | } 22 | 23 | await deployer.deploy(Flashloan, lendingPoolAddressesProviderAddress) 24 | } catch (e) { 25 | console.log(`Error in migration: ${e.message}`) 26 | } 27 | } -------------------------------------------------------------------------------- /aave_v2_flashloan/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flashloan-box", 3 | "description": "A truffle box containing all you need to get started with developing flash loans", 4 | "version": "1.0.0", 5 | "license": "AGPLv3", 6 | "author": "Aave", 7 | "contributors": [ 8 | "David Truong " 9 | ], 10 | "homepage": "https://docs.aave.com/developers/tutorials/performing-a-flash-loan/...-with-truffle", 11 | "repository": "https://github.com/aave/flashloan-box", 12 | "dependencies": {}, 13 | "devDependencies": { 14 | "@openzeppelin/contracts": "^3.0.0", 15 | "@truffle/hdwallet-provider": "^1.0.36", 16 | "dotenv": "^8.2.0", 17 | "truffle": "^5.1.32" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /aave_v2_flashloan/truffle-config.js: -------------------------------------------------------------------------------- 1 | const HDWalletProvider = require("@truffle/hdwallet-provider") 2 | 3 | module.exports = { 4 | networks: { 5 | development: { 6 | provider: function() { 7 | return new HDWalletProvider(process.env.BOT_PRIVATE_KEY, "http://127.0.0.1:8545/"); 8 | }, 9 | network_id: "*", 10 | skipDryRun: true 11 | }, 12 | ropsten: { 13 | provider: new HDWalletProvider(process.env.BOT_PRIVATE_KEY, "https://ropsten.infura.io/v3/" + process.env.BOT_INFURA_KEY), 14 | network_id: 3, 15 | gas: 5000000, 16 | gasPrice: 5000000000, // 5 Gwei 17 | skipDryRun: true 18 | }, 19 | kovan: { 20 | provider: new HDWalletProvider(process.env.BOT_PRIVATE_KEY, "https://kovan.infura.io/v3/" + process.env.BOT_INFURA_KEY), 21 | network_id: 42, 22 | gas: 5000000, 23 | gasPrice: 5000000000, // 5 Gwei 24 | skipDryRun: true 25 | }, 26 | mainnet: { 27 | provider: new HDWalletProvider(process.env.BOT_PRIVATE_KEY, "https://mainnet.infura.io/v3/" + process.env.BOT_INFURA_KEY), 28 | network_id: 1, 29 | gas: 5000000, 30 | gasPrice: 5000000000 // 5 Gwei 31 | } 32 | }, 33 | compilers: { 34 | solc: { 35 | version: "^0.6.6", 36 | }, 37 | }, 38 | } 39 | --------------------------------------------------------------------------------