├── AssetParameters.PNG ├── LICENSE ├── README.md ├── MySimpleFlashloanV3.sol ├── MyBatchFlashloanV3.sol └── MyBatchFlashloanV2.sol /AssetParameters.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defispartan/flashloan/HEAD/AssetParameters.PNG -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, DeFiSpartan 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Testnet Flash Liquidity Demo 2 | 3 | Template smart contracts for accessing flash liquidity from Aave V3 testnet markets. Two variants: simple (borrowing a single token) and batch (multiple tokens). 4 | 5 | These templates utilize faucet of Aave testnet markets to mint flashloan premium, allowing an address to call `executeFlashloan` and execute a simple borrow and return transaction. 6 | 7 | Notes: 8 | 9 | - Aave V3 faucets have a per-txn limit of 10000 (in underlying token decimals) 10 | - [BGD Labs Address Registry](https://github.com/bgd-labs/aave-address-book/) contains `PoolAddressesProvider`, `Faucet`, and underlying reserve token addresses 11 | - It's recommended to add access modifiers (e.g. onlyOwner) to any public facing functions to prevent griefing attacks, especially if funds are stored on contract 12 | - For more instructions on deploying a contract in Remix, check out this [awesome guide](https://docs.chain.link/docs/deploy-your-first-contract/) from Chainlink 13 | 14 | ## Steps 15 | 16 | - 1.) Open contract in remix: 17 | - [Batch](https://remix.ethereum.org/#url=https://github.com/defispartan/testnet-flash-liquidity/blob/main/MyBatchFlashloanV3.sol) 18 | - [Simple](https://remix.ethereum.org/#url=https://github.com/defispartan/testnet-flash-liquidity/blob/main/MySimpleFlashloanV3.sol) 19 | - 2.) Complile and deploy to any network with Aave Protocol market, passing in the `PoolAddressesProvider` and `Faucet` for Aave market to the constructor, addresses [here](https://github.com/bgd-labs/aave-address-book/) 20 | - 3.) Call `executeFlashloan` with `underlyingToken` and `amount` parameters, token addresses [here](https://github.com/bgd-labs/aave-address-book/), 21 | 22 | \* To get the underlying token address and available amount, go to the overview page for the reserve you want to borrow: 23 | 24 | ![Aave Reserve Data](AssetParameters.PNG) 25 | 26 | - underlying token address is: `A` 27 | - max amount available to borrow is: `B` / `C` \* (10^`D`) 28 | 29 | If an underlying token has a debtCeiling, the max amount available to borrow is min(`totalBorrowed` - `debtCeiling`, `availableLiquidity`). 30 | 31 | Aave V3 testnet faucets which are used in templates have a per-tx mint limit of 10000 (in underlying token decimals). 32 | -------------------------------------------------------------------------------- /MySimpleFlashloanV3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | pragma solidity 0.8.10; 3 | 4 | 5 | import { 6 | IPoolAddressesProvider 7 | } from "https://github.com/aave/aave-v3-core/contracts/interfaces/IPoolAddressesProvider.sol"; 8 | import { IPool } from "https://github.com/aave/aave-v3-core/contracts/interfaces/IPool.sol"; 9 | import { IFlashLoanSimpleReceiver } from "https://github.com/aave/aave-v3-core/contracts/flashloan/interfaces/IFlashLoanSimpleReceiver.sol"; 10 | import { IERC20 } from "https://github.com/aave/aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 11 | import { IFaucet } from "https://github.com/aave/aave-v3-periphery/contracts/mocks/testnet-helpers/IFaucet.sol"; 12 | 13 | abstract contract FlashLoanSimpleReceiverBase is IFlashLoanSimpleReceiver { 14 | IPoolAddressesProvider public immutable override ADDRESSES_PROVIDER; 15 | IPool public immutable override POOL; 16 | IFaucet public immutable FAUCET; 17 | 18 | constructor(IPoolAddressesProvider provider, IFaucet faucet) { 19 | ADDRESSES_PROVIDER = provider; 20 | POOL = IPool(provider.getPool()); 21 | FAUCET = faucet; 22 | } 23 | } 24 | 25 | contract MySimpleFlashLoanV3 is FlashLoanSimpleReceiverBase { 26 | constructor(IPoolAddressesProvider _poolAddressesProvider, IFaucet _faucet) FlashLoanSimpleReceiverBase(_poolAddressesProvider, _faucet) {} 27 | 28 | // Modifier to restrict access to the Pool 29 | modifier onlyPool() { 30 | require(msg.sender == address(POOL), "Caller is not the Pool"); 31 | _; 32 | } 33 | 34 | /** 35 | This function is called after your contract has received the borrowed amount 36 | */ 37 | function executeOperation( 38 | address asset, 39 | uint256 amount, 40 | uint256 premium, 41 | address initiator, 42 | bytes calldata params 43 | ) 44 | external 45 | override 46 | onlyPool 47 | returns (bool) 48 | { 49 | 50 | // 51 | // This contract now has the funds requested. 52 | // Your logic goes here. 53 | // 54 | 55 | // At the end of your logic above, this contract owes 56 | // the flashloaned amounts + premiums. 57 | // Therefore ensure your contract has enough to repay 58 | // these amounts. 59 | 60 | // Approve the Pool contract allowance to *pull* the owed amount 61 | uint amountOwed = amount + premium; 62 | FAUCET.mint(asset, address(this), premium); 63 | IERC20(asset).approve(address(POOL), amountOwed); 64 | 65 | return true; 66 | } 67 | 68 | function executeFlashLoan( 69 | address underlyingToken, 70 | uint256 amount 71 | ) public { 72 | address receiverAddress = address(this); 73 | 74 | bytes memory params = ""; 75 | uint16 referralCode = 0; 76 | 77 | POOL.flashLoanSimple( 78 | receiverAddress, 79 | underlyingToken, 80 | amount, 81 | params, 82 | referralCode 83 | ); 84 | } 85 | } -------------------------------------------------------------------------------- /MyBatchFlashloanV3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | pragma solidity 0.8.10; 3 | 4 | 5 | import { 6 | IPoolAddressesProvider 7 | } from "https://github.com/aave/aave-v3-core/contracts/interfaces/IPoolAddressesProvider.sol"; 8 | import { IPool } from "https://github.com/aave/aave-v3-core/contracts/interfaces/IPool.sol"; 9 | import { IFlashLoanReceiver } from "https://github.com/aave/aave-v3-core/contracts/flashloan/interfaces/IFlashLoanReceiver.sol"; 10 | import { IERC20 } from "https://github.com/aave/aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol"; 11 | import { IFaucet } from "https://github.com/aave/aave-v3-periphery/contracts/mocks/testnet-helpers/IFaucet.sol"; 12 | 13 | abstract contract FlashLoanReceiverBase is IFlashLoanReceiver { 14 | IPoolAddressesProvider public immutable override ADDRESSES_PROVIDER; 15 | IPool public immutable override POOL; 16 | IFaucet public immutable FAUCET; 17 | 18 | constructor(IPoolAddressesProvider provider, IFaucet faucet) { 19 | ADDRESSES_PROVIDER = provider; 20 | POOL = IPool(provider.getPool()); 21 | FAUCET = faucet; 22 | } 23 | } 24 | 25 | contract MyBatchFlashLoanV3 is FlashLoanReceiverBase { 26 | constructor(IPoolAddressesProvider _poolAddressesProvider, IFaucet _faucet) FlashLoanReceiverBase(_poolAddressesProvider, _faucet) {} 27 | 28 | // Modifier to restrict access to the Pool 29 | modifier onlyPool() { 30 | require(msg.sender == address(POOL), "Caller is not the Pool"); 31 | _; 32 | } 33 | 34 | /** 35 | This function is called after your contract has received the flash loaned amount 36 | */ 37 | function executeOperation( 38 | address[] calldata assets, 39 | uint256[] calldata amounts, 40 | uint256[] calldata premiums, 41 | address initiator, 42 | bytes calldata params 43 | ) 44 | external 45 | override 46 | onlyPool 47 | returns (bool) 48 | { 49 | 50 | // 51 | // This contract now has the funds requested. 52 | // Your logic goes here. 53 | // 54 | 55 | // At the end of your logic above, this contract owes 56 | // the flashloaned amounts + premiums. 57 | // Therefore ensure your contract has enough to repay 58 | // these amounts. 59 | 60 | // Approve the Pool contract allowance to *pull* the owed amount 61 | for (uint i = 0; i < assets.length; i++) { 62 | uint amountOwed = amounts[i] + premiums[i]; 63 | FAUCET.mint(assets[i], address(this), premiums[i]); 64 | IERC20(assets[i]).approve(address(POOL), amountOwed); 65 | } 66 | 67 | return true; 68 | } 69 | 70 | function executeFlashLoan( 71 | address[] memory underlyingTokens, 72 | uint256[] memory amounts 73 | ) public { 74 | address receiverAddress = address(this); 75 | 76 | // 0 = no debt, 1 = stable, 2 = variable 77 | uint256[] memory modes = new uint256[](1); 78 | modes[0] = 0; 79 | 80 | address onBehalfOf = address(this); 81 | bytes memory params = ""; 82 | uint16 referralCode = 0; 83 | 84 | POOL.flashLoan( 85 | receiverAddress, 86 | underlyingTokens, 87 | amounts, 88 | modes, 89 | onBehalfOf, 90 | params, 91 | referralCode 92 | ); 93 | } 94 | } -------------------------------------------------------------------------------- /MyBatchFlashloanV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | pragma solidity 0.6.12; 3 | pragma experimental ABIEncoderV2; 4 | 5 | 6 | import { 7 | ILendingPoolAddressesProvider 8 | } from 'https://github.com/aave/protocol-v2/contracts/interfaces/ILendingPoolAddressesProvider.sol'; 9 | import { ILendingPool } from 'https://github.com/aave/protocol-v2/contracts/interfaces/ILendingPool.sol'; 10 | import { IFlashLoanReceiver } from 'https://github.com/aave/protocol-v2/contracts/flashloan/interfaces/IFlashLoanReceiver.sol'; 11 | import { IERC20 } from 'https://github.com/aave/protocol-v2/contracts/dependencies/openzeppelin/contracts/IERC20.sol'; 12 | import { SafeERC20 } from 'https://github.com/aave/protocol-v2/contracts/dependencies/openzeppelin/contracts/SafeERC20.sol'; 13 | import { SafeMath } from 'https://github.com/aave/protocol-v2/contracts/dependencies/openzeppelin/contracts/SafeMath.sol'; 14 | 15 | interface IFaucet { 16 | function mint( 17 | address _token, 18 | uint256 _amount 19 | ) external; 20 | } 21 | 22 | abstract contract FlashLoanReceiverBase is IFlashLoanReceiver { 23 | using SafeERC20 for IERC20; 24 | using SafeMath for uint256; 25 | 26 | ILendingPoolAddressesProvider public immutable override ADDRESSES_PROVIDER; 27 | ILendingPool public immutable override LENDING_POOL; 28 | IFaucet public immutable FAUCET; 29 | 30 | constructor(ILendingPoolAddressesProvider provider, IFaucet faucet) public { 31 | ADDRESSES_PROVIDER = provider; 32 | LENDING_POOL = ILendingPool(provider.getLendingPool()); 33 | FAUCET = faucet; 34 | } 35 | } 36 | 37 | contract MyBatchFlashLoanV2 is FlashLoanReceiverBase { 38 | using SafeMath for uint256; 39 | 40 | constructor(ILendingPoolAddressesProvider _addressProvider, IFaucet _faucet) FlashLoanReceiverBase(_addressProvider, _faucet) public {} 41 | 42 | /** 43 | This function is called after your contract has received the flash loaned amount 44 | */ 45 | function executeOperation( 46 | address[] calldata assets, 47 | uint256[] calldata amounts, 48 | uint256[] calldata premiums, 49 | address initiator, 50 | bytes calldata params 51 | ) 52 | external 53 | override 54 | returns (bool) 55 | { 56 | 57 | // 58 | // This contract now has the funds requested. 59 | // Your logic goes here. 60 | // 61 | 62 | // At the end of your logic above, this contract owes 63 | // the flashloaned amounts + premiums. 64 | // Therefore ensure your contract has enough to repay 65 | // these amounts. 66 | 67 | // Approve the LendingPool contract allowance to *pull* the owed amount 68 | for (uint i = 0; i < assets.length; i++) { 69 | uint amountOwing = amounts[i].add(premiums[i]); 70 | FAUCET.mint(assets[i],premiums[i]); 71 | IERC20(assets[i]).approve(address(LENDING_POOL), amountOwing); 72 | } 73 | 74 | return true; 75 | } 76 | 77 | function executeFlashLoan( 78 | address[] memory assets, 79 | uint256[] memory amounts 80 | ) public { 81 | address receiverAddress = address(this); 82 | 83 | // 0 = no debt, 1 = stable, 2 = variable 84 | uint256[] memory modes = new uint256[](1); 85 | modes[0] = 0; 86 | 87 | address onBehalfOf = address(this); 88 | bytes memory params = ""; 89 | uint16 referralCode = 0; 90 | 91 | LENDING_POOL.flashLoan( 92 | receiverAddress, 93 | assets, 94 | amounts, 95 | modes, 96 | onBehalfOf, 97 | params, 98 | referralCode 99 | ); 100 | } 101 | } --------------------------------------------------------------------------------