├── .gitignore ├── .gitmodules ├── .env.example ├── src ├── Contract.sol ├── test │ ├── Contract.t.sol │ ├── UniswapWrapper.t.sol │ ├── QuickswapWrapper.t.sol │ ├── SushiswapWrapper.t.sol │ ├── FlashArbitrage.t.sol │ └── LiquidationCall.t.sol ├── interfaces │ ├── ISwapWrapper.sol │ ├── FlashLoanSimpleReceiverBase.sol │ ├── IUniswapV3SwapCallback.sol │ ├── IUniswapV2Router02.sol │ ├── IFlashLoanSimpleReceiver.sol │ ├── ILendingPoolAddressesProvider.sol │ ├── IERC20.sol │ ├── IUniswapV3SwapRouter.sol │ ├── IUniswapV2Router01.sol │ ├── IPoolAddressesProvider.sol │ ├── ILendingPool.sol │ └── IPool.sol ├── BaseWrapper.sol ├── library │ ├── Math.sol │ ├── Context.sol │ ├── Address.sol │ ├── ReentrancyGuard.sol │ ├── Ownable.sol │ ├── SafeMath.sol │ ├── SafeERC20.sol │ └── DataTypes.sol ├── QuickswapWrapper.sol ├── SushiswapWrapper.sol ├── UniswapWrapper.sol └── FlashArbitrage.sol ├── foundry.toml ├── lib └── forge-std │ ├── Script.sol │ ├── Vm.sol │ └── Test.sol ├── script ├── Script.s.sol └── Deploy.s.sol ├── .gas-snapshot ├── LICENSE ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | cache/ 2 | out/ 3 | assets/ 4 | 5 | deploy 6 | test.ts 7 | .vscode 8 | .env -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ds-test"] 2 | path = lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | NETWORK_RPC_URL= 2 | PRIVATE_KEY= 3 | CHAIN_ID= 4 | GAS_PRICE= 5 | ETHERSCAN_KEY= 6 | COMPILER_VERSION= -------------------------------------------------------------------------------- /src/Contract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.0; 3 | 4 | contract Contract {} 5 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | remappings = ['ds-test/=lib/ds-test/src/'] 6 | gas_reports = ["*"] 7 | 8 | # See more config options https://github.com/gakonst/foundry/tree/master/config -------------------------------------------------------------------------------- /src/test/Contract.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.10; 3 | 4 | import "ds-test/test.sol"; 5 | 6 | contract ContractTest is DSTest { 7 | function setUp() public {} 8 | 9 | function testExample() public { 10 | assertTrue(true); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/interfaces/ISwapWrapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.7.5; 3 | 4 | interface ISwapWrapper { 5 | function setFee(uint fee) external; 6 | function setRouter(address router) external; 7 | function swap(address swapIn, address swapOut, uint amount) external returns (uint); 8 | } -------------------------------------------------------------------------------- /lib/forge-std/Script.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity >=0.6.0; 3 | 4 | import "./Vm.sol"; 5 | import "./console.sol"; 6 | import "./console2.sol"; 7 | 8 | abstract contract Script { 9 | address constant private VM_ADDRESS = 10 | address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); 11 | 12 | Vm public constant vm = Vm(VM_ADDRESS); 13 | } -------------------------------------------------------------------------------- /script/Script.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import 'src/Contract.sol'; 5 | import 'forge-std/Script.sol'; 6 | 7 | 8 | contract MyScript is Script { 9 | // function run() external { 10 | // vm.startBroadcast(); 11 | 12 | // Contract c = new Contract(); 13 | // c.test(); 14 | // require(c.x() == 12345); 15 | // } 16 | } 17 | -------------------------------------------------------------------------------- /.gas-snapshot: -------------------------------------------------------------------------------- 1 | ContractTest:testExample() (gas: 190) 2 | FlashArbitrageTest:testAmount():(uint256) (gas: 2351) 3 | FlashArbitrageTest:testDeployWithdraw() (gas: 86535) 4 | FlashArbitrageTest:testFlashArbitrage() (gas: 471916) 5 | LiquidationCallTest:testBorrow() (gas: 331984) 6 | LiquidationCallTest:testDeposit() (gas: 184039) 7 | LiquidationCallTest:testExample() (gas: 258) 8 | LiquidationCallTest:testGetUserAccountData() (gas: 187242) 9 | LiquidationCallTest:testRepay() (gas: 203752) 10 | LiquidationCallTest:testWithdraw() (gas: 322549) 11 | QuickswapWrapperTest:testExample() (gas: 213) 12 | QuickswapWrapperTest:testSwap() (gas: 156865) 13 | SushiswapWrapperTest:testExample() (gas: 213) 14 | SushiswapWrapperTest:testSwap() (gas: 157635) 15 | UniswapWrapperTest:testExample() (gas: 213) 16 | UniswapWrapperTest:testSwap() (gas: 158261) 17 | -------------------------------------------------------------------------------- /src/BaseWrapper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {Ownable} from "./library/Ownable.sol"; 4 | import {SafeMath} from "./library/SafeMath.sol"; 5 | import {IERC20} from "./interfaces/IERC20.sol"; 6 | 7 | abstract contract BaseWrapper is Ownable { 8 | address public loanOwner; 9 | address public router; 10 | 11 | event Swap(address swapIn, address swapOut, uint amount); 12 | modifier onlyLoanOwner{ 13 | require(msg.sender == loanOwner, "can not call this swap"); 14 | _; 15 | } 16 | 17 | function setSwapCaller(address _loanOwner) external onlyOwner { 18 | loanOwner = _loanOwner; 19 | } 20 | 21 | 22 | function setRouter(address _router) external virtual; 23 | function swap(address swapIn, address swapOut, uint amount) external virtual returns (uint); 24 | 25 | } -------------------------------------------------------------------------------- /src/library/Math.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | library Math { 5 | /** 6 | * @dev Returns the largest of two numbers. 7 | */ 8 | function max(uint256 a, uint256 b) internal pure returns (uint256) { 9 | return a >= b ? a : b; 10 | } 11 | 12 | /** 13 | * @dev Returns the smallest of two numbers. 14 | */ 15 | function min(uint256 a, uint256 b) internal pure returns (uint256) { 16 | return a < b ? a : b; 17 | } 18 | 19 | /** 20 | * @dev Returns the average of two numbers. The result is rounded towards 21 | * zero. 22 | */ 23 | function average(uint256 a, uint256 b) internal pure returns (uint256) { 24 | // (a + b) / 2 can overflow, so we distribute 25 | return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); 26 | } 27 | } -------------------------------------------------------------------------------- /src/library/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity 0.8.0; 5 | 6 | /** 7 | * @dev Provides information about the current execution context, including the 8 | * sender of the transaction and its data. While these are generally available 9 | * via msg.sender and msg.data, they should not be accessed in such a direct 10 | * manner, since when dealing with meta-transactions the account sending and 11 | * paying for execution may not be the actual sender (as far as an application 12 | * is concerned). 13 | * 14 | * This contract is only required for intermediate, library-like contracts. 15 | */ 16 | abstract contract Context { 17 | function _msgSender() internal view virtual returns (address) { 18 | return msg.sender; 19 | } 20 | 21 | function _msgData() internal view virtual returns (bytes calldata) { 22 | return msg.data; 23 | } 24 | } -------------------------------------------------------------------------------- /src/library/Address.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | library Address { 5 | /** 6 | * @dev Returns true if `account` is a contract. 7 | * 8 | * This test is non-exhaustive, and there may be false-negatives: during the 9 | * execution of a contract's constructor, its address will be reported as 10 | * not containing a contract. 11 | * 12 | * > It is unsafe to assume that an address for which this function returns 13 | * false is an externally-owned account (EOA) and not a contract. 14 | */ 15 | function isContract(address account) internal view returns (bool) { 16 | // This method relies in extcodesize, which returns 0 for contracts in 17 | // construction, since the code is only stored at the end of the 18 | // constructor execution. 19 | 20 | uint256 size; 21 | // solhint-disable-next-line no-inline-assembly 22 | assembly { size := extcodesize(account) } 23 | return size > 0; 24 | } 25 | } -------------------------------------------------------------------------------- /src/library/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract ReentrancyGuard { 5 | /// @dev counter to allow mutex lock with only one SSTORE operation 6 | uint256 private _guardCounter; 7 | 8 | constructor() { 9 | // The counter starts at one to prevent changing it from zero to a non-zero 10 | // value, which is a more expensive operation. 11 | _guardCounter = 1; 12 | } 13 | 14 | /** 15 | * @dev Prevents a contract from calling itself, directly or indirectly. 16 | * Calling a `nonReentrant` function from another `nonReentrant` 17 | * function is not supported. It is possible to prevent this from happening 18 | * by making the `nonReentrant` function external, and make it call a 19 | * `private` function that does the actual work. 20 | */ 21 | modifier nonReentrant() { 22 | _guardCounter += 1; 23 | uint256 localCounter = _guardCounter; 24 | _; 25 | require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call"); 26 | } 27 | } -------------------------------------------------------------------------------- /src/interfaces/FlashLoanSimpleReceiverBase.sol: -------------------------------------------------------------------------------- 1 | // // SPDX-License-Identifier: AGPL-3.0 2 | // pragma solidity 0.8.0; 3 | 4 | // import {IERC20} from "./IERC20.sol"; 5 | // import {IFlashLoanSimpleReceiver} from '../interfaces/IFlashLoanSimpleReceiver.sol'; 6 | // import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol'; 7 | // import {IPool} from './IPool.sol'; 8 | 9 | // /** 10 | // * @title FlashLoanSimpleReceiverBase 11 | // * @author Aave 12 | // * @notice Base contract to develop a flashloan-receiver contract. 13 | // */ 14 | // abstract contract FlashLoanSimpleReceiverBase is IFlashLoanSimpleReceiver { 15 | // IPoolAddressesProvider public immutable override ADDRESSES_PROVIDER; 16 | // IPool public immutable override POOL; 17 | 18 | // constructor(IPoolAddressesProvider provider) { 19 | // ADDRESSES_PROVIDER = provider; 20 | // POOL = IPool(provider.getPool()); 21 | // } 22 | 23 | // function getBalanceInternal(address _reserve) internal view returns(uint256) { 24 | // return IERC20(_reserve).balanceOf(address(this)); 25 | // } 26 | // } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Eacent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/interfaces/IUniswapV3SwapCallback.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Callback for IUniswapV3PoolActions#swap 5 | /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface 6 | interface IUniswapV3SwapCallback { 7 | /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. 8 | /// @dev In the implementation you must pay the pool tokens owed for the swap. 9 | /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. 10 | /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. 11 | /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by 12 | /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. 13 | /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by 14 | /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. 15 | /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call 16 | function uniswapV3SwapCallback( 17 | int256 amount0Delta, 18 | int256 amount1Delta, 19 | bytes calldata data 20 | ) external; 21 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DEPLOY_CONTRACT ?= 2 | DEPLOYED_CONTRACT_ADDRESS ?= 3 | CONSTRUCTOR_ARGS ?= 4 | VERITY_CONSTRUCTOR_ARGS ?= 5 | VERIFY_CONTRACT ?= 6 | GUID ?= 7 | include .env 8 | 9 | test: 10 | forge test --fork-url ${NETWORK_RPC_URL} 11 | 12 | report: 13 | forge test --fork-url ${NETWORK_RPC_URL} --gas-report 14 | 15 | build: 16 | forge build 17 | 18 | snapshot: 19 | forge snapshot --fork-url ${NETWORK_RPC_URL} 20 | 21 | # deploy the contract 22 | deploy-contract: 23 | forge create --rpc-url ${NETWORK_RPC_URL} --constructor-args $(CONSTRUCTOR_ARGS) \ 24 | --private-key ${PRIVATE_KEY} \ 25 | src/$(DEPLOY_CONTRACT).sol:$(DEPLOY_CONTRACT) \ 26 | --gas-price ${GAS_PRICE} 27 | 28 | # verify the contract 29 | verify-contract: 30 | forge verify-contract --chain-id ${CHAIN_ID} \ 31 | --num-of-optimizations 200 \ 32 | --constructor-args $(VERITY_CONSTRUCTOR_ARGS) \ 33 | --compiler-version ${COMPILER_VERSION} $(DEPLOYED_CONTRACT_ADDRESS) \ 34 | src/$(VERIFY_CONTRACT).sol:$(VERIFY_CONTRACT) \ 35 | ${ETHERSCAN_KEY} 36 | 37 | verify-check: 38 | forge verify-check --chain-id ${CHAIN_ID} $(GUID) ${ETHERSCAN_KEY} 39 | 40 | 41 | # deploy contracts and verify them 42 | scripting: 43 | forge script script/Deploy.s.sol:DeployScript --rpc-url ${NETWORK_RPC_URL} \ 44 | --broadcast \ 45 | --verify \ 46 | --etherscan-api-key ${ETHERSCAN_KEY} \ 47 | --private-key ${PRIVATE_KEY} \ 48 | --gas-price ${GAS_PRICE} 49 | -vvvv -------------------------------------------------------------------------------- /src/interfaces/IUniswapV2Router02.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.2; 2 | 3 | import './IUniswapV2Router01.sol'; 4 | 5 | interface IUniswapV2Router02 is IUniswapV2Router01 { 6 | function removeLiquidityETHSupportingFeeOnTransferTokens( 7 | address token, 8 | uint liquidity, 9 | uint amountTokenMin, 10 | uint amountETHMin, 11 | address to, 12 | uint deadline 13 | ) external returns (uint amountETH); 14 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 15 | address token, 16 | uint liquidity, 17 | uint amountTokenMin, 18 | uint amountETHMin, 19 | address to, 20 | uint deadline, 21 | bool approveMax, uint8 v, bytes32 r, bytes32 s 22 | ) external returns (uint amountETH); 23 | 24 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 25 | uint amountIn, 26 | uint amountOutMin, 27 | address[] calldata path, 28 | address to, 29 | uint deadline 30 | ) external; 31 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 32 | uint amountOutMin, 33 | address[] calldata path, 34 | address to, 35 | uint deadline 36 | ) external payable; 37 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 38 | uint amountIn, 39 | uint amountOutMin, 40 | address[] calldata path, 41 | address to, 42 | uint deadline 43 | ) external; 44 | } -------------------------------------------------------------------------------- /src/interfaces/IFlashLoanSimpleReceiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.0; 3 | 4 | import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol'; 5 | import {IPool} from './IPool.sol'; 6 | 7 | /** 8 | * @title IFlashLoanSimpleReceiver 9 | * @author Aave 10 | * @notice Defines the basic interface of a flashloan-receiver contract. 11 | * @dev Implement this interface to develop a flashloan-compatible flashLoanReceiver contract 12 | **/ 13 | interface IFlashLoanSimpleReceiver { 14 | /** 15 | * @notice Executes an operation after receiving the flash-borrowed asset 16 | * @dev Ensure that the contract can return the debt + premium, e.g., has 17 | * enough funds to repay and has approved the Pool to pull the total amount 18 | * @param asset The address of the flash-borrowed asset 19 | * @param amount The amount of the flash-borrowed asset 20 | * @param premium The fee of the flash-borrowed asset 21 | * @param initiator The address of the flashloan initiator 22 | * @param params The byte-encoded params passed when initiating the flashloan 23 | * @return True if the execution of the operation succeeds, false otherwise 24 | */ 25 | function executeOperation( 26 | address asset, 27 | uint256 amount, 28 | uint256 premium, 29 | address initiator, 30 | bytes calldata params 31 | ) external returns (bool); 32 | 33 | // function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); 34 | 35 | function POOL() external view returns (IPool); 36 | } -------------------------------------------------------------------------------- /src/QuickswapWrapper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {Ownable} from "./library/Ownable.sol"; 4 | import {SafeMath} from "./library/SafeMath.sol"; 5 | import {IERC20} from "./interfaces/IERC20.sol"; 6 | import {IUniswapV2Router01} from "./interfaces/IUniswapV2Router01.sol"; 7 | import {BaseWrapper} from './BaseWrapper.sol'; 8 | 9 | contract QuickswapWrapper is BaseWrapper { 10 | using SafeMath for uint; 11 | IUniswapV2Router01 quickswapRouter; 12 | 13 | function setRouter(address _router) external override onlyOwner { 14 | router = _router; 15 | quickswapRouter = IUniswapV2Router01(_router); 16 | } 17 | 18 | function swap(address swapIn, address swapOut, uint amount) external override onlyLoanOwner returns (uint) { 19 | address[] memory path = new address[](2); 20 | path[0] = swapIn; 21 | path[1] = swapOut; 22 | 23 | IERC20(swapIn).approve(address(quickswapRouter), amount); 24 | uint beforeSwapBalance = IERC20(swapOut).balanceOf(address(this)); 25 | uint[] memory amounts = quickswapRouter.swapExactTokensForTokens( 26 | amount, 27 | 0, 28 | path, 29 | address(this), 30 | block.timestamp 31 | ); 32 | uint afterSwapBalance = IERC20(swapOut).balanceOf(address(this)); 33 | uint swapAmount = afterSwapBalance.sub(beforeSwapBalance); 34 | 35 | IERC20(swapIn).transfer(msg.sender, IERC20(swapIn).balanceOf(address(this))); 36 | IERC20(swapOut).transfer(msg.sender, swapAmount); 37 | require(swapAmount > 0, "Quickswap trade failed"); 38 | emit Swap(swapIn, swapOut, swapAmount); 39 | return swapAmount; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/SushiswapWrapper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {Ownable} from "./library/Ownable.sol"; 4 | import {SafeMath} from "./library/SafeMath.sol"; 5 | import {IERC20} from "./interfaces/IERC20.sol"; 6 | import {IUniswapV2Router01} from "./interfaces/IUniswapV2Router01.sol"; 7 | import {BaseWrapper} from './BaseWrapper.sol'; 8 | 9 | contract SushiswapWrapper is BaseWrapper { 10 | using SafeMath for uint; 11 | IUniswapV2Router01 sushiswapRouter; 12 | 13 | function setRouter(address _router) external override onlyOwner { 14 | router = _router; 15 | sushiswapRouter = IUniswapV2Router01(_router); 16 | } 17 | 18 | function swap(address swapIn, address swapOut, uint amount) external override onlyLoanOwner returns (uint) { 19 | address[] memory path = new address[](2); 20 | path[0] = swapIn; 21 | path[1] = swapOut; 22 | 23 | IERC20(swapIn).approve(address(sushiswapRouter), amount); 24 | uint beforeSwapBalance = IERC20(swapOut).balanceOf(address(this)); 25 | uint[] memory amounts = sushiswapRouter.swapExactTokensForTokens( 26 | amount, 27 | 0, 28 | path, 29 | address(this), 30 | block.timestamp 31 | ); 32 | uint afterSwapBalance = IERC20(swapOut).balanceOf(address(this)); 33 | uint swapAmount = afterSwapBalance.sub(beforeSwapBalance); 34 | 35 | IERC20(swapIn).transfer(msg.sender, IERC20(swapIn).balanceOf(address(this))); 36 | IERC20(swapOut).transfer(msg.sender, swapAmount); 37 | require(swapAmount > 0, "Sushiswap trade failed"); 38 | emit Swap(swapIn, swapOut, swapAmount); 39 | return swapAmount; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/test/UniswapWrapper.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.0; 3 | 4 | import "ds-test/console.sol"; 5 | import "ds-test/test.sol"; 6 | import "ds-test/cheatcodes.sol"; 7 | import {IERC20} from "../interfaces/IERC20.sol"; 8 | import {ISwapWrapper} from "../interfaces/ISwapWrapper.sol"; 9 | import {UniswapWrapper} from "../UniswapWrapper.sol"; 10 | 11 | contract UniswapWrapperTest is DSTest { 12 | UniswapWrapper swapWrapper; 13 | CheatCodes cheats = CheatCodes(HEVM_ADDRESS); 14 | 15 | address public sam = 0xAF838230fc2E832798ae88fa107C465F7F6Cfd13; 16 | address public USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174; 17 | address public WMATIC = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270; 18 | address public WETH = 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619; 19 | 20 | // Uniswap 21 | address public router = 0xE592427A0AEce92De3Edee1F18E0157C05861564; 22 | 23 | function setUp() public { 24 | swapWrapper = new UniswapWrapper(); 25 | swapWrapper.setRouter(router); 26 | swapWrapper.setSwapCaller(address(this)); 27 | 28 | cheats.prank(address(sam)); 29 | IERC20(USDC).approve(address(swapWrapper), 1e6); 30 | cheats.prank(address(sam)); 31 | IERC20(USDC).transfer(address(swapWrapper), 1e6); 32 | } 33 | 34 | function testExample() public { 35 | assertTrue(true); 36 | } 37 | 38 | function testSwap() public { 39 | uint beforeSwapBalance = IERC20(USDC).balanceOf(address(swapWrapper)); 40 | swapWrapper.swap(USDC, WMATIC, 1e6); 41 | uint afterSwapBalance = IERC20(USDC).balanceOf(address(swapWrapper)); 42 | assertGt(beforeSwapBalance, afterSwapBalance); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/QuickswapWrapper.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.0; 3 | 4 | import "ds-test/console.sol"; 5 | import "ds-test/test.sol"; 6 | import "ds-test/cheatcodes.sol"; 7 | import {IERC20} from "../interfaces/IERC20.sol"; 8 | import {ISwapWrapper} from "../interfaces/ISwapWrapper.sol"; 9 | import {QuickswapWrapper} from "../QuickswapWrapper.sol"; 10 | 11 | contract QuickswapWrapperTest is DSTest { 12 | QuickswapWrapper swapWrapper; 13 | CheatCodes cheats = CheatCodes(HEVM_ADDRESS); 14 | 15 | address public sam = 0xAF838230fc2E832798ae88fa107C465F7F6Cfd13; 16 | address public USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174; 17 | address public WMATIC = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270; 18 | address public WETH = 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619; 19 | 20 | // Quickswap 21 | address public router = 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff; 22 | 23 | function setUp() public { 24 | swapWrapper = new QuickswapWrapper(); 25 | swapWrapper.setRouter(router); 26 | swapWrapper.setSwapCaller(address(this)); 27 | 28 | cheats.prank(address(sam)); 29 | IERC20(USDC).approve(address(swapWrapper), 1e6); 30 | cheats.prank(address(sam)); 31 | IERC20(USDC).transfer(address(swapWrapper), 1e6); 32 | } 33 | 34 | function testExample() public { 35 | assertTrue(true); 36 | } 37 | 38 | function testSwap() public { 39 | uint beforeSwapBalance = IERC20(USDC).balanceOf(address(swapWrapper)); 40 | swapWrapper.swap(USDC, WMATIC, 1e6); 41 | uint afterSwapBalance = IERC20(USDC).balanceOf(address(swapWrapper)); 42 | assertGt(beforeSwapBalance, afterSwapBalance); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/SushiswapWrapper.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.0; 3 | 4 | import "ds-test/console.sol"; 5 | import "ds-test/test.sol"; 6 | import "ds-test/cheatcodes.sol"; 7 | import {IERC20} from "../interfaces/IERC20.sol"; 8 | import {ISwapWrapper} from "../interfaces/ISwapWrapper.sol"; 9 | import {SushiswapWrapper} from "../SushiswapWrapper.sol"; 10 | 11 | contract SushiswapWrapperTest is DSTest { 12 | SushiswapWrapper swapWrapper; 13 | CheatCodes cheats = CheatCodes(HEVM_ADDRESS); 14 | 15 | address public sam = 0xAF838230fc2E832798ae88fa107C465F7F6Cfd13; 16 | address public USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174; 17 | address public WMATIC = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270; 18 | address public WETH = 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619; 19 | 20 | // Sushiswap 21 | address public router = 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506; 22 | 23 | function setUp() public { 24 | swapWrapper = new SushiswapWrapper(); 25 | swapWrapper.setRouter(router); 26 | swapWrapper.setSwapCaller(address(this)); 27 | 28 | cheats.prank(address(sam)); 29 | IERC20(USDC).approve(address(swapWrapper), 1e6); 30 | cheats.prank(address(sam)); 31 | IERC20(USDC).transfer(address(swapWrapper), 1e6); 32 | } 33 | 34 | function testExample() public { 35 | assertTrue(true); 36 | } 37 | 38 | function testSwap() public { 39 | uint beforeSwapBalance = IERC20(USDC).balanceOf(address(swapWrapper)); 40 | swapWrapper.swap(USDC, WMATIC, 1e6); 41 | uint afterSwapBalance = IERC20(USDC).balanceOf(address(swapWrapper)); 42 | assertGt(beforeSwapBalance, afterSwapBalance); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/UniswapWrapper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import {Ownable} from "./library/Ownable.sol"; 4 | import {SafeMath} from "./library/SafeMath.sol"; 5 | import {IERC20} from "./interfaces/IERC20.sol"; 6 | import {IUniswapV3SwapRouter} from "./interfaces/IUniswapV3SwapRouter.sol"; 7 | import {BaseWrapper} from './BaseWrapper.sol'; 8 | 9 | contract UniswapWrapper is BaseWrapper { 10 | uint24 public fee = 500; 11 | IUniswapV3SwapRouter uniswapRouter; 12 | using SafeMath for uint; 13 | 14 | function setFee(uint24 _fee) external onlyOwner { 15 | fee = _fee; 16 | } 17 | 18 | function setRouter(address _router) external override onlyOwner { 19 | router = _router; 20 | uniswapRouter = IUniswapV3SwapRouter(_router); 21 | } 22 | 23 | function swap(address swapIn, address swapOut, uint amount) external override onlyLoanOwner returns (uint) { 24 | IUniswapV3SwapRouter.ExactInputSingleParams memory swapParams = IUniswapV3SwapRouter.ExactInputSingleParams({ 25 | tokenIn: swapIn, 26 | tokenOut: swapOut, 27 | fee: fee, 28 | recipient: address(this), 29 | deadline: block.timestamp, 30 | amountIn: amount, 31 | amountOutMinimum: 0, 32 | sqrtPriceLimitX96: 0 33 | }); 34 | 35 | IERC20(swapIn).approve(address(uniswapRouter), amount); 36 | uint beforeSwapBalance = IERC20(swapOut).balanceOf(address(this)); 37 | uint finalAmounts = uniswapRouter.exactInputSingle(swapParams); 38 | uint afterSwapBalance = IERC20(swapOut).balanceOf(address(this)); 39 | uint swapAmount = afterSwapBalance.sub(beforeSwapBalance); 40 | 41 | IERC20(swapIn).transfer(msg.sender, IERC20(swapIn).balanceOf(address(this))); 42 | IERC20(swapOut).transfer(msg.sender, swapAmount); 43 | require(swapAmount > 0, "Uniswap trade failed"); 44 | emit Swap(swapIn, swapOut, swapAmount); 45 | return swapAmount; 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /script/Deploy.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import {IPoolAddressesProvider} from 'src/interfaces/IPoolAddressesProvider.sol'; 5 | import {FlashArbitrage} from 'src/FlashArbitrage.sol'; 6 | import {QuickswapWrapper} from 'src/QuickswapWrapper.sol'; 7 | import {SushiswapWrapper} from 'src/SushiswapWrapper.sol'; 8 | import {UniswapWrapper} from 'src/UniswapWrapper.sol'; 9 | import 'forge-std/Script.sol'; 10 | 11 | 12 | contract DeployScript is Script { 13 | UniswapWrapper uniswapWrapper; 14 | QuickswapWrapper quickswapWrapper; 15 | SushiswapWrapper sushiswapWrapper; 16 | FlashArbitrage flashArbitrage; 17 | 18 | address public PoolAddressesProvider = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb; 19 | 20 | // quickswap 21 | address public QuickswapRouter = 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff; 22 | 23 | // Uniswap 24 | address public UniwapRouter = 0xE592427A0AEce92De3Edee1F18E0157C05861564; 25 | 26 | // Sushiswap 27 | address public SushiswapRouter = 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506; 28 | 29 | function run() external { 30 | vm.startBroadcast(); 31 | uniswapWrapper = new UniswapWrapper(); 32 | sushiswapWrapper = new SushiswapWrapper(); 33 | quickswapWrapper = new QuickswapWrapper(); 34 | uniswapWrapper.setRouter(UniwapRouter); 35 | quickswapWrapper.setRouter(QuickswapRouter); 36 | sushiswapWrapper.setRouter(SushiswapRouter); 37 | 38 | flashArbitrage = new FlashArbitrage(PoolAddressesProvider); 39 | flashArbitrage.setWrapperMap("uniswap", address(uniswapWrapper)); 40 | flashArbitrage.setWrapperMap("quickswap", address(quickswapWrapper)); 41 | flashArbitrage.setWrapperMap("sushiswap", address(sushiswapWrapper)); 42 | 43 | uniswapWrapper.setSwapCaller(address(flashArbitrage)); 44 | quickswapWrapper.setSwapCaller(address(flashArbitrage)); 45 | sushiswapWrapper.setSwapCaller(address(flashArbitrage)); 46 | vm.stopBroadcast(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/interfaces/ILendingPoolAddressesProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity ^0.8.0; 3 | 4 | /** 5 | * @title LendingPoolAddressesProvider contract 6 | * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles 7 | * - Acting also as factory of proxies and admin of those, so with right to change its implementations 8 | * - Owned by the Aave Governance 9 | * @author Aave 10 | **/ 11 | interface ILendingPoolAddressesProvider { 12 | event MarketIdSet(string newMarketId); 13 | event LendingPoolUpdated(address indexed newAddress); 14 | event ConfigurationAdminUpdated(address indexed newAddress); 15 | event EmergencyAdminUpdated(address indexed newAddress); 16 | event LendingPoolConfiguratorUpdated(address indexed newAddress); 17 | event LendingPoolCollateralManagerUpdated(address indexed newAddress); 18 | event PriceOracleUpdated(address indexed newAddress); 19 | event LendingRateOracleUpdated(address indexed newAddress); 20 | event ProxyCreated(bytes32 id, address indexed newAddress); 21 | event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy); 22 | 23 | function getMarketId() external view returns (string memory); 24 | 25 | function setMarketId(string calldata marketId) external; 26 | 27 | function setAddress(bytes32 id, address newAddress) external; 28 | 29 | function setAddressAsProxy(bytes32 id, address impl) external; 30 | 31 | function getAddress(bytes32 id) external view returns (address); 32 | 33 | function getLendingPool() external view returns (address); 34 | 35 | function setLendingPoolImpl(address pool) external; 36 | 37 | function getLendingPoolConfigurator() external view returns (address); 38 | 39 | function setLendingPoolConfiguratorImpl(address configurator) external; 40 | 41 | function getLendingPoolCollateralManager() external view returns (address); 42 | 43 | function setLendingPoolCollateralManager(address manager) external; 44 | 45 | function getPoolAdmin() external view returns (address); 46 | 47 | function setPoolAdmin(address admin) external; 48 | 49 | function getEmergencyAdmin() external view returns (address); 50 | 51 | function setEmergencyAdmin(address admin) external; 52 | 53 | function getPriceOracle() external view returns (address); 54 | 55 | function setPriceOracle(address priceOracle) external; 56 | 57 | function getLendingRateOracle() external view returns (address); 58 | 59 | function setLendingRateOracle(address lendingRateOracle) external; 60 | } -------------------------------------------------------------------------------- /src/library/Ownable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) 3 | 4 | // SPDX-License-Identifier: MIT 5 | pragma solidity 0.8.0; 6 | 7 | import "./Context.sol"; 8 | 9 | /** 10 | * @dev Contract module which provides a basic access control mechanism, where 11 | * there is an account (an owner) that can be granted exclusive access to 12 | * specific functions. 13 | * 14 | * By default, the owner account will be the one that deploys the contract. This 15 | * can later be changed with {transferOwnership}. 16 | * 17 | * This module is used through inheritance. It will make available the modifier 18 | * `onlyOwner`, which can be applied to your functions to restrict their use to 19 | * the owner. 20 | */ 21 | abstract contract Ownable is Context { 22 | address private _owner; 23 | 24 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 25 | 26 | /** 27 | * @dev Initializes the contract setting the deployer as the initial owner. 28 | */ 29 | constructor() { 30 | _transferOwnership(_msgSender()); 31 | } 32 | 33 | /** 34 | * @dev Returns the address of the current owner. 35 | */ 36 | function owner() public view virtual returns (address) { 37 | return _owner; 38 | } 39 | 40 | /** 41 | * @dev Throws if called by any account other than the owner. 42 | */ 43 | modifier onlyOwner() { 44 | require(owner() == _msgSender(), "Ownable: caller is not the owner"); 45 | _; 46 | } 47 | 48 | /** 49 | * @dev Leaves the contract without owner. It will not be possible to call 50 | * `onlyOwner` functions anymore. Can only be called by the current owner. 51 | * 52 | * NOTE: Renouncing ownership will leave the contract without an owner, 53 | * thereby removing any functionality that is only available to the owner. 54 | */ 55 | function renounceOwnership() public virtual onlyOwner { 56 | _transferOwnership(address(0)); 57 | } 58 | 59 | /** 60 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 61 | * Can only be called by the current owner. 62 | */ 63 | function transferOwnership(address newOwner) public virtual onlyOwner { 64 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 65 | _transferOwnership(newOwner); 66 | } 67 | 68 | /** 69 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 70 | * Internal function without access restriction. 71 | */ 72 | function _transferOwnership(address newOwner) internal virtual { 73 | address oldOwner = _owner; 74 | _owner = newOwner; 75 | emit OwnershipTransferred(oldOwner, newOwner); 76 | } 77 | } -------------------------------------------------------------------------------- /src/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | interface IERC20 { 5 | /** 6 | * @dev Returns the amount of tokens in existence. 7 | */ 8 | function totalSupply() external view returns (uint256); 9 | 10 | /** 11 | * @dev Returns the amount of tokens owned by `account`. 12 | */ 13 | function balanceOf(address account) external view returns (uint256); 14 | 15 | /** 16 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 17 | * 18 | * Returns a boolean value indicating whether the operation succeeded. 19 | * 20 | * Emits a `Transfer` event. 21 | */ 22 | function transfer(address recipient, uint256 amount) external returns (bool); 23 | 24 | /** 25 | * @dev Returns the remaining number of tokens that `spender` will be 26 | * allowed to spend on behalf of `owner` through `transferFrom`. This is 27 | * zero by default. 28 | * 29 | * This value changes when `approve` or `transferFrom` are called. 30 | */ 31 | function allowance(address owner, address spender) external view returns (uint256); 32 | 33 | /** 34 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 35 | * 36 | * Returns a boolean value indicating whether the operation succeeded. 37 | * 38 | * > Beware that changing an allowance with this method brings the risk 39 | * that someone may use both the old and the new allowance by unfortunate 40 | * transaction ordering. One possible solution to mitigate this race 41 | * condition is to first reduce the spender's allowance to 0 and set the 42 | * desired value afterwards: 43 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 44 | * 45 | * Emits an `Approval` event. 46 | */ 47 | function approve(address spender, uint256 amount) external returns (bool); 48 | 49 | /** 50 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 51 | * allowance mechanism. `amount` is then deducted from the caller's 52 | * allowance. 53 | * 54 | * Returns a boolean value indicating whether the operation succeeded. 55 | * 56 | * Emits a `Transfer` event. 57 | */ 58 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 59 | 60 | /** 61 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 62 | * another (`to`). 63 | * 64 | * Note that `value` may be zero. 65 | */ 66 | event Transfer(address indexed from, address indexed to, uint256 value); 67 | 68 | /** 69 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 70 | * a call to `approve`. `value` is the new allowance. 71 | */ 72 | event Approval(address indexed owner, address indexed spender, uint256 value); 73 | } -------------------------------------------------------------------------------- /src/interfaces/IUniswapV3SwapRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.7.5; 3 | pragma abicoder v2; 4 | 5 | import {IUniswapV3SwapCallback} from "./IUniswapV3SwapCallback.sol"; 6 | 7 | /// @title Router token swapping functionality 8 | /// @notice Functions for swapping tokens via Uniswap V3 9 | interface IUniswapV3SwapRouter is IUniswapV3SwapCallback { 10 | struct ExactInputSingleParams { 11 | address tokenIn; 12 | address tokenOut; 13 | uint24 fee; 14 | address recipient; 15 | uint256 deadline; 16 | uint256 amountIn; 17 | uint256 amountOutMinimum; 18 | uint160 sqrtPriceLimitX96; 19 | } 20 | 21 | /// @notice Swaps `amountIn` of one token for as much as possible of another token 22 | /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata 23 | /// @return amountOut The amount of the received token 24 | function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); 25 | 26 | struct ExactInputParams { 27 | bytes path; 28 | address recipient; 29 | uint256 deadline; 30 | uint256 amountIn; 31 | uint256 amountOutMinimum; 32 | } 33 | 34 | /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path 35 | /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata 36 | /// @return amountOut The amount of the received token 37 | function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); 38 | 39 | struct ExactOutputSingleParams { 40 | address tokenIn; 41 | address tokenOut; 42 | uint24 fee; 43 | address recipient; 44 | uint256 deadline; 45 | uint256 amountOut; 46 | uint256 amountInMaximum; 47 | uint160 sqrtPriceLimitX96; 48 | } 49 | 50 | /// @notice Swaps as little as possible of one token for `amountOut` of another token 51 | /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata 52 | /// @return amountIn The amount of the input token 53 | function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); 54 | 55 | struct ExactOutputParams { 56 | bytes path; 57 | address recipient; 58 | uint256 deadline; 59 | uint256 amountOut; 60 | uint256 amountInMaximum; 61 | } 62 | 63 | /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) 64 | /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata 65 | /// @return amountIn The amount of the input token 66 | function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); 67 | } -------------------------------------------------------------------------------- /src/library/SafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | library SafeMath { 5 | /** 6 | * @dev Returns the addition of two unsigned integers, reverting on 7 | * overflow. 8 | * 9 | * Counterpart to Solidity's `+` operator. 10 | * 11 | * Requirements: 12 | * - Addition cannot overflow. 13 | */ 14 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 15 | uint256 c = a + b; 16 | require(c >= a, "SafeMath: addition overflow"); 17 | 18 | return c; 19 | } 20 | 21 | /** 22 | * @dev Returns the subtraction of two unsigned integers, reverting on 23 | * overflow (when the result is negative). 24 | * 25 | * Counterpart to Solidity's `-` operator. 26 | * 27 | * Requirements: 28 | * - Subtraction cannot overflow. 29 | */ 30 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 31 | require(b <= a, "SafeMath: subtraction overflow"); 32 | uint256 c = a - b; 33 | 34 | return c; 35 | } 36 | 37 | /** 38 | * @dev Returns the multiplication of two unsigned integers, reverting on 39 | * overflow. 40 | * 41 | * Counterpart to Solidity's `*` operator. 42 | * 43 | * Requirements: 44 | * - Multiplication cannot overflow. 45 | */ 46 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 47 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 48 | // benefit is lost if 'b' is also tested. 49 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 50 | if (a == 0) { 51 | return 0; 52 | } 53 | 54 | uint256 c = a * b; 55 | require(c / a == b, "SafeMath: multiplication overflow"); 56 | 57 | return c; 58 | } 59 | 60 | /** 61 | * @dev Returns the integer division of two unsigned integers. Reverts on 62 | * division by zero. The result is rounded towards zero. 63 | * 64 | * Counterpart to Solidity's `/` operator. Note: this function uses a 65 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 66 | * uses an invalid opcode to revert (consuming all remaining gas). 67 | * 68 | * Requirements: 69 | * - The divisor cannot be zero. 70 | */ 71 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 72 | // Solidity only automatically asserts when dividing by 0 73 | require(b > 0, "SafeMath: division by zero"); 74 | uint256 c = a / b; 75 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 76 | 77 | return c; 78 | } 79 | 80 | /** 81 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 82 | * Reverts when dividing by zero. 83 | * 84 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 85 | * opcode (which leaves remaining gas untouched) while Solidity uses an 86 | * invalid opcode to revert (consuming all remaining gas). 87 | * 88 | * Requirements: 89 | * - The divisor cannot be zero. 90 | */ 91 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 92 | require(b != 0, "SafeMath: modulo by zero"); 93 | return a % b; 94 | } 95 | } -------------------------------------------------------------------------------- /src/library/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "../interfaces/IERC20.sol"; 5 | import "./SafeMath.sol"; 6 | import "./Address.sol"; 7 | 8 | library SafeERC20 { 9 | using SafeMath for uint256; 10 | using Address for address; 11 | 12 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 13 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 14 | } 15 | 16 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 17 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 18 | } 19 | 20 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 21 | // safeApprove should only be called when setting an initial allowance, 22 | // or when resetting it to zero. To increase and decrease it, use 23 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 24 | // solhint-disable-next-line max-line-length 25 | require((value == 0) || (token.allowance(address(this), spender) == 0), 26 | "SafeERC20: approve from non-zero to non-zero allowance" 27 | ); 28 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 29 | } 30 | 31 | function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { 32 | uint256 newAllowance = token.allowance(address(this), spender).add(value); 33 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 34 | } 35 | 36 | function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { 37 | uint256 newAllowance = token.allowance(address(this), spender).sub(value); 38 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 39 | } 40 | 41 | /** 42 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 43 | * on the return value: the return value is optional (but if data is returned, it must not be false). 44 | * @param token The token targeted by the call. 45 | * @param data The call data (encoded using abi.encode or one of its variants). 46 | */ 47 | function callOptionalReturn(IERC20 token, bytes memory data) private { 48 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 49 | // we're implementing it ourselves. 50 | 51 | // A Solidity high level call has three parts: 52 | // 1. The target address is checked to verify it contains contract code 53 | // 2. The call itself is made, and success asserted 54 | // 3. The return value is decoded, which in turn checks the size of the returned data. 55 | // solhint-disable-next-line max-line-length 56 | require(address(token).isContract(), "SafeERC20: call to non-contract"); 57 | 58 | // solhint-disable-next-line avoid-low-level-calls 59 | (bool success, bytes memory returndata) = address(token).call(data); 60 | require(success, "SafeERC20: low-level call failed"); 61 | 62 | if (returndata.length > 0) { // Return data is optional 63 | // solhint-disable-next-line max-line-length 64 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/interfaces/IUniswapV2Router01.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.2; 2 | 3 | interface IUniswapV2Router01 { 4 | function factory() external pure returns (address); 5 | function WETH() external pure returns (address); 6 | 7 | function addLiquidity( 8 | address tokenA, 9 | address tokenB, 10 | uint amountADesired, 11 | uint amountBDesired, 12 | uint amountAMin, 13 | uint amountBMin, 14 | address to, 15 | uint deadline 16 | ) external returns (uint amountA, uint amountB, uint liquidity); 17 | function addLiquidityETH( 18 | address token, 19 | uint amountTokenDesired, 20 | uint amountTokenMin, 21 | uint amountETHMin, 22 | address to, 23 | uint deadline 24 | ) external payable returns (uint amountToken, uint amountETH, uint liquidity); 25 | function removeLiquidity( 26 | address tokenA, 27 | address tokenB, 28 | uint liquidity, 29 | uint amountAMin, 30 | uint amountBMin, 31 | address to, 32 | uint deadline 33 | ) external returns (uint amountA, uint amountB); 34 | function removeLiquidityETH( 35 | address token, 36 | uint liquidity, 37 | uint amountTokenMin, 38 | uint amountETHMin, 39 | address to, 40 | uint deadline 41 | ) external returns (uint amountToken, uint amountETH); 42 | function removeLiquidityWithPermit( 43 | address tokenA, 44 | address tokenB, 45 | uint liquidity, 46 | uint amountAMin, 47 | uint amountBMin, 48 | address to, 49 | uint deadline, 50 | bool approveMax, uint8 v, bytes32 r, bytes32 s 51 | ) external returns (uint amountA, uint amountB); 52 | function removeLiquidityETHWithPermit( 53 | address token, 54 | uint liquidity, 55 | uint amountTokenMin, 56 | uint amountETHMin, 57 | address to, 58 | uint deadline, 59 | bool approveMax, uint8 v, bytes32 r, bytes32 s 60 | ) external returns (uint amountToken, uint amountETH); 61 | function swapExactTokensForTokens( 62 | uint amountIn, 63 | uint amountOutMin, 64 | address[] calldata path, 65 | address to, 66 | uint deadline 67 | ) external returns (uint[] memory amounts); 68 | function swapTokensForExactTokens( 69 | uint amountOut, 70 | uint amountInMax, 71 | address[] calldata path, 72 | address to, 73 | uint deadline 74 | ) external returns (uint[] memory amounts); 75 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 76 | external 77 | payable 78 | returns (uint[] memory amounts); 79 | function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 80 | external 81 | returns (uint[] memory amounts); 82 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 83 | external 84 | returns (uint[] memory amounts); 85 | function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 86 | external 87 | payable 88 | returns (uint[] memory amounts); 89 | 90 | function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); 91 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 92 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); 93 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 94 | function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); 95 | } -------------------------------------------------------------------------------- /src/FlashArbitrage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import {SafeMath} from "./library/SafeMath.sol"; 5 | import {Ownable} from "./library/Ownable.sol"; 6 | import {IFlashLoanSimpleReceiver} from './interfaces/IFlashLoanSimpleReceiver.sol'; 7 | import {IPoolAddressesProvider} from './interfaces/IPoolAddressesProvider.sol'; 8 | import {IPool} from './interfaces/IPool.sol'; 9 | import {IERC20} from "./interfaces/IERC20.sol"; 10 | import {SafeERC20} from './library/SafeERC20.sol'; 11 | import {ISwapWrapper} from './interfaces/ISwapWrapper.sol'; 12 | 13 | 14 | contract FlashArbitrage is IFlashLoanSimpleReceiver, Ownable{ 15 | using SafeMath for uint; 16 | using SafeERC20 for IERC20; 17 | 18 | // IPoolAddressesProvider public immutable override ADDRESSES_PROVIDER; 19 | IPool public immutable override POOL; 20 | uint16 public referralCode = 0; 21 | 22 | mapping(string => address) public wrapperMap; 23 | 24 | constructor(address provider) { 25 | // ADDRESSES_PROVIDER = provider; 26 | POOL = IPool(IPoolAddressesProvider(provider).getPool()); 27 | } 28 | 29 | function getBalanceInternal(address _reserve) internal view returns(uint256) { 30 | return IERC20(_reserve).balanceOf(address(this)); 31 | } 32 | 33 | function setWrapperMap(string memory name, address wrapper) external onlyOwner { 34 | wrapperMap[name] = wrapper; 35 | } 36 | 37 | function setReferralCode(uint8 _referralCode) external onlyOwner { 38 | referralCode = _referralCode; 39 | emit SetReferralCode(_referralCode); 40 | } 41 | 42 | function deploy(address token, uint256 amount) public onlyOwner { 43 | require(token != address(0), "address cannot be 0"); 44 | require(amount > 0, "Cannot stake 0"); 45 | require(IERC20(token).balanceOf(msg.sender) >= amount, "Not enough tokens"); 46 | IERC20(token).safeTransferFrom(msg.sender, address(this), amount); 47 | emit Deploy(msg.sender, token, amount); 48 | } 49 | 50 | function withdraw(address token, uint256 amount) public onlyOwner { 51 | require(token != address(0), "address cannot be 0"); 52 | require(amount > 0, "Cannot withdraw 0"); 53 | require(IERC20(token).balanceOf(address(this)) >= amount, "Not enough tokens"); 54 | IERC20(token).safeTransfer(msg.sender, amount); 55 | emit Withdrawn(msg.sender, token, amount); 56 | } 57 | 58 | function executeOperation( 59 | address asset, 60 | uint256 amount, 61 | uint256 premium, 62 | address initiator, 63 | bytes calldata params 64 | ) external override returns (bool) { 65 | require(amount <= getBalanceInternal(asset), "Invalid balance"); 66 | ( 67 | address swapInProtocol, 68 | address swapOutProtocol, 69 | address _swapOutToken 70 | ) = abi.decode(params, (address, address, address)); 71 | 72 | IERC20(asset).safeTransfer(swapInProtocol, amount); 73 | uint diffOutAmount = ISwapWrapper(swapInProtocol).swap(asset, _swapOutToken, amount); 74 | IERC20(_swapOutToken).safeTransfer(swapOutProtocol, diffOutAmount); 75 | uint resOutAmount = ISwapWrapper(swapOutProtocol).swap(_swapOutToken, asset, diffOutAmount); 76 | // approve the repay assets 77 | uint repayAmount = premium.add(amount); 78 | IERC20(asset).approve(address(POOL), repayAmount); 79 | ExecuteOperationEvent(asset, amount, premium, initiator, params); 80 | return true; 81 | } 82 | 83 | function execute( 84 | string memory swapInWrapper, 85 | string memory swapOutWrapper, 86 | address InToken, 87 | address OutToken, 88 | uint amount 89 | ) external onlyOwner { 90 | bytes memory data = abi.encode( 91 | wrapperMap[swapInWrapper], 92 | wrapperMap[swapOutWrapper], 93 | OutToken 94 | ); 95 | POOL.flashLoanSimple(address(this), InToken, amount, data, referralCode); 96 | } 97 | 98 | event ExecuteOperationEvent(address asset, uint256 amount, uint256 premium, address initiator, bytes params); 99 | event SetReferralCode(uint8 newReferralCode); 100 | event Deploy(address owner, address token, uint256 amount); 101 | event Withdrawn(address to, address token, uint256 amount); 102 | } 103 | -------------------------------------------------------------------------------- /src/test/FlashArbitrage.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.0; 3 | 4 | import "ds-test/cheatcodes.sol"; 5 | import "ds-test/console.sol"; 6 | import "ds-test/test.sol"; 7 | import {FlashArbitrage} from "../FlashArbitrage.sol"; 8 | import {IERC20} from "../interfaces/IERC20.sol"; 9 | import {IPoolAddressesProvider} from '../interfaces/IPoolAddressesProvider.sol'; 10 | import {UniswapWrapper} from '../UniswapWrapper.sol'; 11 | import {QuickswapWrapper} from '../QuickswapWrapper.sol'; 12 | import {SushiswapWrapper} from '../SushiswapWrapper.sol'; 13 | 14 | contract FlashArbitrageTest is DSTest { 15 | UniswapWrapper uniswapWrapper; 16 | QuickswapWrapper quickswapWrapper; 17 | SushiswapWrapper sushiswapWrapper; 18 | FlashArbitrage flashArbitrage; 19 | CheatCodes cheats = CheatCodes(HEVM_ADDRESS); 20 | 21 | uint public testAmount = 30e6; 22 | address public sam = 0x6F82E3cc2a3d6b7A6d98e7941BCadd7f52919D53; 23 | address public PoolAddressesProvider = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb; 24 | 25 | address public UniswapV2Router02 = 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff; 26 | address public SwapRouter = 0xE592427A0AEce92De3Edee1F18E0157C05861564; 27 | address public USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174; 28 | address public amUSDC = 0x625E7708f30cA75bfd92586e17077590C60eb4cD; 29 | address public WMATIC = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270; 30 | address public WETH = 0x25788a1a171ec66Da6502f9975a15B609fF54CF6; 31 | address public DAI = 0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063; 32 | address public LINK = 0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39; 33 | 34 | // quickswap 35 | address public QuickswapRouter = 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff; 36 | 37 | // Uniswap 38 | address public UniwapRouter = 0xE592427A0AEce92De3Edee1F18E0157C05861564; 39 | 40 | // Sushiswap 41 | address public SushiswapRouter = 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506; 42 | 43 | function setUp() public { 44 | uniswapWrapper = new UniswapWrapper(); 45 | sushiswapWrapper = new SushiswapWrapper(); 46 | quickswapWrapper = new QuickswapWrapper(); 47 | uniswapWrapper.setRouter(UniwapRouter); 48 | quickswapWrapper.setRouter(QuickswapRouter); 49 | sushiswapWrapper.setRouter(SushiswapRouter); 50 | 51 | console.log("uniswapWrapper address", address(uniswapWrapper)); 52 | console.log("quickswapWrapper address", address(quickswapWrapper)); 53 | console.log("sushiswapWrapper address", address(sushiswapWrapper)); 54 | 55 | flashArbitrage = new FlashArbitrage(PoolAddressesProvider); 56 | flashArbitrage.setWrapperMap("uniswap", address(uniswapWrapper)); 57 | flashArbitrage.setWrapperMap("quickswap", address(quickswapWrapper)); 58 | flashArbitrage.setWrapperMap("sushiswap", address(sushiswapWrapper)); 59 | 60 | uniswapWrapper.setSwapCaller(address(flashArbitrage)); 61 | quickswapWrapper.setSwapCaller(address(flashArbitrage)); 62 | sushiswapWrapper.setSwapCaller(address(flashArbitrage)); 63 | 64 | cheats.prank(address(sam)); 65 | IERC20(USDC).approve(address(this), testAmount); 66 | cheats.prank(address(sam)); 67 | IERC20(USDC).transfer(address(this), testAmount); 68 | 69 | IERC20(USDC).approve(address(flashArbitrage), testAmount); 70 | flashArbitrage.deploy(USDC, 20e6); 71 | console.log("FlashArbitrage USDC:", IERC20(USDC).balanceOf(address(flashArbitrage))); 72 | } 73 | 74 | function testDeployWithdraw() public { 75 | cheats.prank(address(sam)); 76 | IERC20(USDC).approve(address(this), 1e6); 77 | cheats.prank(address(sam)); 78 | IERC20(USDC).transfer(address(this), 1e6); 79 | 80 | IERC20(USDC).approve(address(flashArbitrage), 1e6); 81 | flashArbitrage.deploy(USDC, 1e6); 82 | 83 | flashArbitrage.withdraw(USDC, 1e6); 84 | } 85 | 86 | function testFlashArbitrage() public { 87 | uint lastBalance = IERC20(USDC).balanceOf(address(flashArbitrage)); 88 | console.log("FlashArbitrage last Balance", lastBalance); 89 | flashArbitrage.execute( 90 | 'uniswap', 91 | 'sushiswap', 92 | USDC, 93 | WMATIC, 94 | 20e6 95 | ); 96 | uint NowBalance = IERC20(USDC).balanceOf(address(flashArbitrage)); 97 | 98 | console.log("FlashArbitrage Now Balance", NowBalance); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /lib/forge-std/Vm.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity >=0.6.0; 3 | pragma experimental ABIEncoderV2; 4 | 5 | interface Vm { 6 | // Set block.timestamp (newTimestamp) 7 | function warp(uint256) external; 8 | // Set block.height (newHeight) 9 | function roll(uint256) external; 10 | // Set block.basefee (newBasefee) 11 | function fee(uint256) external; 12 | // Set block.chainid 13 | function chainId(uint256) external; 14 | // Loads a storage slot from an address (who, slot) 15 | function load(address,bytes32) external returns (bytes32); 16 | // Stores a value to an address' storage slot, (who, slot, value) 17 | function store(address,bytes32,bytes32) external; 18 | // Signs data, (privateKey, digest) => (v, r, s) 19 | function sign(uint256,bytes32) external returns (uint8,bytes32,bytes32); 20 | // Gets address for a given private key, (privateKey) => (address) 21 | function addr(uint256) external returns (address); 22 | // Gets the nonce of an account 23 | function getNonce(address) external returns (uint64); 24 | // Sets the nonce of an account; must be higher than the current nonce of the account 25 | function setNonce(address, uint64) external; 26 | // Performs a foreign function call via terminal, (stringInputs) => (result) 27 | function ffi(string[] calldata) external returns (bytes memory); 28 | // Sets the *next* call's msg.sender to be the input address 29 | function prank(address) external; 30 | // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called 31 | function startPrank(address) external; 32 | // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input 33 | function prank(address,address) external; 34 | // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input 35 | function startPrank(address,address) external; 36 | // Resets subsequent calls' msg.sender to be `address(this)` 37 | function stopPrank() external; 38 | // Sets an address' balance, (who, newBalance) 39 | function deal(address, uint256) external; 40 | // Sets an address' code, (who, newCode) 41 | function etch(address, bytes calldata) external; 42 | // Expects an error on next call 43 | function expectRevert(bytes calldata) external; 44 | function expectRevert(bytes4) external; 45 | function expectRevert() external; 46 | // Record all storage reads and writes 47 | function record() external; 48 | // Gets all accessed reads and write slot from a recording session, for a given address 49 | function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes); 50 | // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). 51 | // Call this function, then emit an event, then call a function. Internally after the call, we check if 52 | // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) 53 | function expectEmit(bool,bool,bool,bool) external; 54 | function expectEmit(bool,bool,bool,bool,address) external; 55 | // Mocks a call to an address, returning specified data. 56 | // Calldata can either be strict or a partial match, e.g. if you only 57 | // pass a Solidity selector to the expected calldata, then the entire Solidity 58 | // function will be mocked. 59 | function mockCall(address,bytes calldata,bytes calldata) external; 60 | // Mocks a call to an address with a specific msg.value, returning specified data. 61 | // Calldata match takes precedence over msg.value in case of ambiguity. 62 | function mockCall(address,uint256,bytes calldata,bytes calldata) external; 63 | // Clears all mocked calls 64 | function clearMockedCalls() external; 65 | // Expect a call to an address with the specified calldata. 66 | // Calldata can either be strict or a partial match 67 | function expectCall(address,bytes calldata) external; 68 | // Expect a call to an address with the specified msg.value and calldata 69 | function expectCall(address,uint256,bytes calldata) external; 70 | // Gets the code from an artifact file. Takes in the relative path to the json file 71 | function getCode(string calldata) external returns (bytes memory); 72 | // Labels an address in call traces 73 | function label(address, string calldata) external; 74 | // If the condition is false, discard this run's fuzz inputs and generate new ones 75 | function assume(bool) external; 76 | // Set block.coinbase (who) 77 | function coinbase(address) external; 78 | // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain 79 | function broadcast() external; 80 | // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain 81 | function broadcast(address) external; 82 | // Using the address that calls the test contract, has the all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain 83 | function startBroadcast() external; 84 | // Has the all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain 85 | function startBroadcast(address) external; 86 | // Stops collecting onchain transactions 87 | function stopBroadcast() external; 88 | } -------------------------------------------------------------------------------- /src/test/LiquidationCall.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.0; 3 | 4 | import "ds-test/cheatcodes.sol"; 5 | import "ds-test/console.sol"; 6 | import "ds-test/test.sol"; 7 | import {IERC20} from "../interfaces/IERC20.sol"; 8 | import {IPool} from "../interfaces/IPool.sol"; 9 | import {ILendingPool} from "../interfaces/ILendingPool.sol"; 10 | import {ILendingPoolAddressesProvider} from "../interfaces/ILendingPoolAddressesProvider.sol"; 11 | 12 | contract LiquidationCallTest is DSTest { 13 | IPool pool; 14 | CheatCodes cheats = CheatCodes(HEVM_ADDRESS); 15 | 16 | address public sam = 0x6F82E3cc2a3d6b7A6d98e7941BCadd7f52919D53; 17 | address public eacentcheung = 0x6715FcefaaC138C5F2d478973eD13E327dcc2bFa; 18 | address public AavePool = 0x794a61358D6845594F94dc1DB02A252b5b4814aD; 19 | address public USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174; // USDC 20 | address public WETH = 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619; // WETH 21 | address public DAI = 0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063; // DAI 22 | 23 | function setUp() public { 24 | pool = IPool(AavePool); 25 | 26 | } 27 | 28 | function testExample() public { 29 | assertTrue(true); 30 | } 31 | 32 | function testGetUserAccountData() public { 33 | ( 34 | uint256 totalCollateralBase, 35 | uint256 totalDebtBase, 36 | uint256 availableBorrowsBase, 37 | uint256 currentLiquidationThreshold, 38 | uint256 ltv, 39 | uint256 healthFactor 40 | ) = pool.getUserAccountData(sam); 41 | 42 | console.log("totalCollateralBase", totalCollateralBase); 43 | console.log("totalDebtBase", totalDebtBase); 44 | console.log("availableBorrowsBase", availableBorrowsBase); 45 | console.log("currentLiquidationThreshold", currentLiquidationThreshold); 46 | console.log("ltv", ltv); 47 | console.log("healthFactor", healthFactor); 48 | } 49 | 50 | function testDeposit() public { 51 | address asset = USDC; 52 | uint256 amount = 5e6; 53 | address onBehalfOf = sam; 54 | uint16 referralCode = 0; 55 | 56 | uint beforeBalance = IERC20(USDC).balanceOf(address(sam)); 57 | console.log("beforeBalance", beforeBalance); 58 | 59 | cheats.prank(sam); 60 | IERC20(USDC).approve(address(pool), amount); 61 | 62 | cheats.prank(sam); 63 | pool.deposit(asset, amount, onBehalfOf, referralCode); 64 | 65 | uint afterBalance = IERC20(USDC).balanceOf(address(sam)); 66 | console.log("afterBalance", afterBalance); 67 | 68 | assertGt(beforeBalance, afterBalance); 69 | } 70 | 71 | function testBorrow() public { 72 | address asset = USDC; 73 | uint256 amount = 1e5; 74 | uint256 interestRateMode = 2; 75 | address onBehalfOf = sam; 76 | uint16 referralCode = 0; 77 | 78 | uint beforeBalance = IERC20(USDC).balanceOf(address(sam)); 79 | console.log("beforeBalance", beforeBalance); 80 | 81 | cheats.prank(sam); 82 | pool.borrow(asset, amount, interestRateMode, referralCode, onBehalfOf); 83 | 84 | uint afterBalance = IERC20(USDC).balanceOf(address(sam)); 85 | console.log("afterBalance", afterBalance); 86 | 87 | assertGt(afterBalance, beforeBalance); 88 | } 89 | 90 | function testWithdraw() public { 91 | address asset = USDC; 92 | uint256 amount = 1e6; 93 | address to = sam; 94 | 95 | uint beforeBalance = IERC20(USDC).balanceOf(address(sam)); 96 | console.log("beforeBalance", beforeBalance); 97 | 98 | cheats.prank(sam); 99 | pool.withdraw(asset, amount, to); 100 | 101 | uint afterBalance = IERC20(USDC).balanceOf(address(sam)); 102 | console.log("afterBalance", afterBalance); 103 | 104 | assertGt(afterBalance, beforeBalance); 105 | } 106 | 107 | function testRepay() public { 108 | address asset = DAI; 109 | uint256 amount = 1e17; 110 | uint256 interestRateMode = 2; 111 | address onBehalfOf = sam; 112 | uint16 referralCode = 0; 113 | 114 | cheats.prank(sam); 115 | IERC20(asset).approve(address(pool), type(uint).max); 116 | 117 | cheats.prank(sam); 118 | uint res = pool.repay(asset, type(uint).max, interestRateMode, onBehalfOf); 119 | console.log("res", res); 120 | 121 | uint afterRepayBalance = IERC20(asset).balanceOf(address(sam)); 122 | console.log("afterRepayBalance", afterRepayBalance); 123 | 124 | assertGt(res, 0); 125 | 126 | } 127 | 128 | // function testLiquidationCall() public { 129 | // ( 130 | // uint256 totalCollateralBase, 131 | // uint256 totalDebtBase, 132 | // uint256 availableBorrowsBase, 133 | // uint256 currentLiquidationThreshold, 134 | // uint256 ltv, 135 | // uint256 healthFactor 136 | // ) = pool.getUserAccountData(sam); 137 | 138 | // console.log("totalCollateralBase", totalCollateralBase); 139 | // console.log("totalDebtBase", totalDebtBase); 140 | // console.log("availableBorrowsBase", availableBorrowsBase); 141 | // console.log("currentLiquidationThreshold", currentLiquidationThreshold); 142 | // console.log("ltv", ltv); 143 | // console.log("healthFactor", healthFactor); 144 | 145 | // address collateralAsset = USDC; 146 | // address debtAsset = DAI; 147 | // address user = sam; 148 | // uint256 debtToCover = 5e17; 149 | // bool receiveAToken = false; 150 | 151 | // console.log("beforeBalance", IERC20(DAI).balanceOf(eacentcheung)); 152 | // cheats.prank(eacentcheung); 153 | // IERC20(debtAsset).approve(address(pool), type(uint).max); 154 | 155 | // cheats.prank(eacentcheung); 156 | // pool.liquidationCall(collateralAsset, debtAsset, user, debtToCover, receiveAToken); 157 | // console.log("afterBalance", IERC20(DAI).balanceOf(eacentcheung)); 158 | // } 159 | } 160 | -------------------------------------------------------------------------------- /src/library/DataTypes.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity 0.8.0; 3 | 4 | library DataTypes { 5 | struct ReserveData { 6 | //stores the reserve configuration 7 | ReserveConfigurationMap configuration; 8 | //the liquidity index. Expressed in ray 9 | uint128 liquidityIndex; 10 | //the current supply rate. Expressed in ray 11 | uint128 currentLiquidityRate; 12 | //variable borrow index. Expressed in ray 13 | uint128 variableBorrowIndex; 14 | //the current variable borrow rate. Expressed in ray 15 | uint128 currentVariableBorrowRate; 16 | //the current stable borrow rate. Expressed in ray 17 | uint128 currentStableBorrowRate; 18 | //timestamp of last update 19 | uint40 lastUpdateTimestamp; 20 | //the id of the reserve. Represents the position in the list of the active reserves 21 | uint16 id; 22 | //aToken address 23 | address aTokenAddress; 24 | //stableDebtToken address 25 | address stableDebtTokenAddress; 26 | //variableDebtToken address 27 | address variableDebtTokenAddress; 28 | //address of the interest rate strategy 29 | address interestRateStrategyAddress; 30 | //the current treasury balance, scaled 31 | uint128 accruedToTreasury; 32 | //the outstanding unbacked aTokens minted through the bridging feature 33 | uint128 unbacked; 34 | //the outstanding debt borrowed against this asset in isolation mode 35 | uint128 isolationModeTotalDebt; 36 | } 37 | 38 | struct ReserveConfigurationMap { 39 | //bit 0-15: LTV 40 | //bit 16-31: Liq. threshold 41 | //bit 32-47: Liq. bonus 42 | //bit 48-55: Decimals 43 | //bit 56: reserve is active 44 | //bit 57: reserve is frozen 45 | //bit 58: borrowing is enabled 46 | //bit 59: stable rate borrowing enabled 47 | //bit 60: asset is paused 48 | //bit 61: borrowing in isolation mode is enabled 49 | //bit 62-63: reserved 50 | //bit 64-79: reserve factor 51 | //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap 52 | //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap 53 | //bit 152-167 liquidation protocol fee 54 | //bit 168-175 eMode category 55 | //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled 56 | //bit 212-251 debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals 57 | //bit 252-255 unused 58 | 59 | uint256 data; 60 | } 61 | 62 | struct UserConfigurationMap { 63 | uint256 data; 64 | } 65 | 66 | struct EModeCategory { 67 | // each eMode category has a custom ltv and liquidation threshold 68 | uint16 ltv; 69 | uint16 liquidationThreshold; 70 | uint16 liquidationBonus; 71 | // each eMode category may or may not have a custom oracle to override the individual assets price oracles 72 | address priceSource; 73 | string label; 74 | } 75 | 76 | enum InterestRateMode { 77 | NONE, 78 | STABLE, 79 | VARIABLE 80 | } 81 | 82 | struct ReserveCache { 83 | uint256 currScaledVariableDebt; 84 | uint256 nextScaledVariableDebt; 85 | uint256 currPrincipalStableDebt; 86 | uint256 currAvgStableBorrowRate; 87 | uint256 currTotalStableDebt; 88 | uint256 nextAvgStableBorrowRate; 89 | uint256 nextTotalStableDebt; 90 | uint256 currLiquidityIndex; 91 | uint256 nextLiquidityIndex; 92 | uint256 currVariableBorrowIndex; 93 | uint256 nextVariableBorrowIndex; 94 | uint256 currLiquidityRate; 95 | uint256 currVariableBorrowRate; 96 | uint256 reserveFactor; 97 | ReserveConfigurationMap reserveConfiguration; 98 | address aTokenAddress; 99 | address stableDebtTokenAddress; 100 | address variableDebtTokenAddress; 101 | uint40 reserveLastUpdateTimestamp; 102 | uint40 stableDebtLastUpdateTimestamp; 103 | } 104 | 105 | struct ExecuteLiquidationCallParams { 106 | uint256 reservesCount; 107 | uint256 debtToCover; 108 | address collateralAsset; 109 | address debtAsset; 110 | address user; 111 | bool receiveAToken; 112 | address priceOracle; 113 | uint8 userEModeCategory; 114 | address priceOracleSentinel; 115 | } 116 | 117 | struct ExecuteSupplyParams { 118 | address asset; 119 | uint256 amount; 120 | address onBehalfOf; 121 | uint16 referralCode; 122 | } 123 | 124 | struct ExecuteBorrowParams { 125 | address asset; 126 | address user; 127 | address onBehalfOf; 128 | uint256 amount; 129 | InterestRateMode interestRateMode; 130 | uint16 referralCode; 131 | bool releaseUnderlying; 132 | uint256 maxStableRateBorrowSizePercent; 133 | uint256 reservesCount; 134 | address oracle; 135 | uint8 userEModeCategory; 136 | address priceOracleSentinel; 137 | } 138 | 139 | struct ExecuteRepayParams { 140 | address asset; 141 | uint256 amount; 142 | InterestRateMode interestRateMode; 143 | address onBehalfOf; 144 | bool useATokens; 145 | } 146 | 147 | struct ExecuteWithdrawParams { 148 | address asset; 149 | uint256 amount; 150 | address to; 151 | uint256 reservesCount; 152 | address oracle; 153 | uint8 userEModeCategory; 154 | } 155 | 156 | struct ExecuteSetUserEModeParams { 157 | uint256 reservesCount; 158 | address oracle; 159 | uint8 categoryId; 160 | } 161 | 162 | struct FinalizeTransferParams { 163 | address asset; 164 | address from; 165 | address to; 166 | uint256 amount; 167 | uint256 balanceFromBefore; 168 | uint256 balanceToBefore; 169 | uint256 reservesCount; 170 | address oracle; 171 | uint8 fromEModeCategory; 172 | } 173 | 174 | struct FlashloanParams { 175 | address receiverAddress; 176 | address[] assets; 177 | uint256[] amounts; 178 | uint256[] interestRateModes; 179 | address onBehalfOf; 180 | bytes params; 181 | uint16 referralCode; 182 | uint256 flashLoanPremiumToProtocol; 183 | uint256 flashLoanPremiumTotal; 184 | uint256 maxStableRateBorrowSizePercent; 185 | uint256 reservesCount; 186 | address addressesProvider; 187 | uint8 userEModeCategory; 188 | bool isAuthorizedFlashBorrower; 189 | } 190 | 191 | struct FlashloanSimpleParams { 192 | address receiverAddress; 193 | address asset; 194 | uint256 amount; 195 | bytes params; 196 | uint16 referralCode; 197 | uint256 flashLoanPremiumToProtocol; 198 | uint256 flashLoanPremiumTotal; 199 | } 200 | 201 | struct FlashLoanRepaymentParams { 202 | uint256 amount; 203 | uint256 totalPremium; 204 | uint256 flashLoanPremiumToProtocol; 205 | address asset; 206 | address receiverAddress; 207 | uint16 referralCode; 208 | } 209 | 210 | struct CalculateUserAccountDataParams { 211 | UserConfigurationMap userConfig; 212 | uint256 reservesCount; 213 | address user; 214 | address oracle; 215 | uint8 userEModeCategory; 216 | } 217 | 218 | struct ValidateBorrowParams { 219 | ReserveCache reserveCache; 220 | UserConfigurationMap userConfig; 221 | address asset; 222 | address userAddress; 223 | uint256 amount; 224 | InterestRateMode interestRateMode; 225 | uint256 maxStableLoanPercent; 226 | uint256 reservesCount; 227 | address oracle; 228 | uint8 userEModeCategory; 229 | address priceOracleSentinel; 230 | bool isolationModeActive; 231 | address isolationModeCollateralAddress; 232 | uint256 isolationModeDebtCeiling; 233 | } 234 | 235 | struct ValidateLiquidationCallParams { 236 | ReserveCache debtReserveCache; 237 | uint256 totalDebt; 238 | uint256 healthFactor; 239 | address priceOracleSentinel; 240 | } 241 | 242 | struct CalculateInterestRatesParams { 243 | uint256 unbacked; 244 | uint256 liquidityAdded; 245 | uint256 liquidityTaken; 246 | uint256 totalStableDebt; 247 | uint256 totalVariableDebt; 248 | uint256 averageStableBorrowRate; 249 | uint256 reserveFactor; 250 | address reserve; 251 | address aToken; 252 | } 253 | 254 | struct InitReserveParams { 255 | address asset; 256 | address aTokenAddress; 257 | address stableDebtAddress; 258 | address variableDebtAddress; 259 | address interestRateStrategyAddress; 260 | uint16 reservesCount; 261 | uint16 maxNumberReserves; 262 | } 263 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flash Arbitrage 2 | 3 | ## Overview 4 | 5 | To reduce the cost and risk of arbitrage, I use FlashLoan for cross-protocol arbitrage so that I only need to pay the fees of FlashLoan to complete a series of transactions. It calls the `flashloansimple()` method from Aave's pool, trades between the two platforms, and finally repays the fund to the pool. The entire operation is done within one transaction. 6 | 7 | 8 | [![XozXKP.png](https://s1.ax1x.com/2022/06/15/XozXKP.png)](https://imgtu.com/i/XozXKP) 9 | 10 | ## Contracts 11 | 12 | Name | Code | Address | Network 13 | ------------ | ------------- | ------------- | ------------- 14 | FlashArbitrage |[GitHub](https://github.com/YuppieCC/flash-arbitrage/blob/main/src/FlashArbitrage.sol)|[0x77F9E9036151B01eFB80B4D812a29504d674ad1C](https://polygonscan.com/address/0x77F9E9036151B01eFB80B4D812a29504d674ad1C) | Polygon 15 | SushiswapWrapper |[GitHub](https://github.com/YuppieCC/flash-arbitrage/blob/main/src/SushiswapWrapper.sol)|[0xDB76397c6534DB87AFD5A40969076D49E2B703d0](https://polygonscan.com/address/0xDB76397c6534DB87AFD5A40969076D49E2B703d0) | Polygon 16 | UniswapWrapper |[GitHub](https://github.com/YuppieCC/flash-arbitrage/blob/main/src/UniswapWrapper.sol)|[0xeee45d451eDaC60dAA703514deF979F3a1D3120B](https://polygonscan.com/address/0xeee45d451eDaC60dAA703514deF979F3a1D3120B) | Polygon 17 | QuickswapWrapper |[GitHub](https://github.com/YuppieCC/flash-arbitrage/blob/main/src/QuickswapWrapper.sol)|[0xF22FEbD79Cd2b986d00549eBE91A836b686d2f65](https://polygonscan.com/address/0xF22FEbD79Cd2b986d00549eBE91A836b686d2f65) | Polygon 18 | 19 | ## Usage 20 | When all contracts have been deployed, you can stake some assets to the contract, and call the `execute()` method to initiate transactions. 21 | 22 | ```solidity 23 | flashArbitrage.deploy(USDC, 5e6); # remember to approve assets 24 | flashArbitrage.execute( 25 | 'uniswap', # buy WMATIC on Uniswap (using USDC) 26 | 'sushiswap', # sell WMATIC on Sushiswap (receive USDC) 27 | USDC, # borrow USDC ( from AAVE ) 28 | WMATIC, # trade WMATIC 29 | 100e6 # borrow amount, all-in one trade. 30 | ); 31 | ``` 32 | ## Development 33 | 34 | ```Shell 35 | 36 | # Apply an ETHERSCAN_KEY: https://polygonscan.com/apis 37 | # PRIVATE_KEY: Export from your Wallet 38 | cp .env.example .env 39 | make test 40 | 41 | # if tests all passed, deploy all contracts. 42 | # scripting is a way to declaratively deploy contracts using Solidity 43 | # instead of using the more limiting and less user friendly `forge create`. 44 | make scripting 45 | 46 | # if scripting isn't ok, you can deploy a single contract at once time. 47 | make deploy-contract DEPLOY_CONTRACT={DEPLOY_CONTRACT} CONSTRUCTOR_ARGS={CONSTRUCTOR_ARGS} 48 | ``` 49 | ## Gas Reports 50 | 51 | ``` 52 | ╭─────────────────────────┬─────────────────┬────────┬────────┬────────┬─────────╮ 53 | │ FlashArbitrage contract ┆ ┆ ┆ ┆ ┆ │ 54 | ╞═════════════════════════╪═════════════════╪════════╪════════╪════════╪═════════╡ 55 | │ Deployment Cost ┆ Deployment Size ┆ ┆ ┆ ┆ │ 56 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 57 | │ 1062691 ┆ 5595 ┆ ┆ ┆ ┆ │ 58 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 59 | │ Function Name ┆ min ┆ avg ┆ median ┆ max ┆ # calls │ 60 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 61 | │ deploy ┆ 15509 ┆ 29741 ┆ 34486 ┆ 34486 ┆ 4 │ 62 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 63 | │ execute ┆ 456312 ┆ 456312 ┆ 456312 ┆ 456312 ┆ 1 │ 64 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 65 | │ executeOperation ┆ 334736 ┆ 334736 ┆ 334736 ┆ 334736 ┆ 1 │ 66 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 67 | │ setWrapperMap ┆ 23434 ┆ 23434 ┆ 23434 ┆ 23434 ┆ 9 │ 68 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 69 | │ withdraw ┆ 9881 ┆ 9881 ┆ 9881 ┆ 9881 ┆ 1 │ 70 | ╰─────────────────────────┴─────────────────┴────────┴────────┴────────┴─────────╯ 71 | ``` 72 | ``` 73 | ╭───────────────────────────┬─────────────────┬────────┬────────┬────────┬─────────╮ 74 | │ QuickswapWrapper contract ┆ ┆ ┆ ┆ ┆ │ 75 | ╞═══════════════════════════╪═════════════════╪════════╪════════╪════════╪═════════╡ 76 | │ Deployment Cost ┆ Deployment Size ┆ ┆ ┆ ┆ │ 77 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 78 | │ 634013 ┆ 3185 ┆ ┆ ┆ ┆ │ 79 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 80 | │ Function Name ┆ min ┆ avg ┆ median ┆ max ┆ # calls │ 81 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 82 | │ setRouter ┆ 44889 ┆ 44889 ┆ 44889 ┆ 44889 ┆ 5 │ 83 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 84 | │ setSwapCaller ┆ 22701 ┆ 22701 ┆ 22701 ┆ 22701 ┆ 5 │ 85 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 86 | │ swap ┆ 142884 ┆ 142884 ┆ 142884 ┆ 142884 ┆ 1 │ 87 | ╰───────────────────────────┴─────────────────┴────────┴────────┴────────┴─────────╯ 88 | ``` 89 | ``` 90 | ╭───────────────────────────┬─────────────────┬────────┬────────┬────────┬─────────╮ 91 | │ SushiswapWrapper contract ┆ ┆ ┆ ┆ ┆ │ 92 | ╞═══════════════════════════╪═════════════════╪════════╪════════╪════════╪═════════╡ 93 | │ Deployment Cost ┆ Deployment Size ┆ ┆ ┆ ┆ │ 94 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 95 | │ 719608 ┆ 3771 ┆ ┆ ┆ ┆ │ 96 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 97 | │ Function Name ┆ min ┆ avg ┆ median ┆ max ┆ # calls │ 98 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 99 | │ setRouter ┆ 44822 ┆ 44822 ┆ 44822 ┆ 44822 ┆ 5 │ 100 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 101 | │ setSwapCaller ┆ 22723 ┆ 22723 ┆ 22723 ┆ 22723 ┆ 5 │ 102 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 103 | │ swap ┆ 115224 ┆ 129438 ┆ 129438 ┆ 143653 ┆ 2 │ 104 | ╰───────────────────────────┴─────────────────┴────────┴────────┴────────┴─────────╯ 105 | ``` 106 | ``` 107 | ╭─────────────────────────┬─────────────────┬────────┬────────┬────────┬─────────╮ 108 | │ UniswapWrapper contract ┆ ┆ ┆ ┆ ┆ │ 109 | ╞═════════════════════════╪═════════════════╪════════╪════════╪════════╪═════════╡ 110 | │ Deployment Cost ┆ Deployment Size ┆ ┆ ┆ ┆ │ 111 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 112 | │ 641936 ┆ 3135 ┆ ┆ ┆ ┆ │ 113 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 114 | │ Function Name ┆ min ┆ avg ┆ median ┆ max ┆ # calls │ 115 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 116 | │ setRouter ┆ 22989 ┆ 22989 ┆ 22989 ┆ 22989 ┆ 5 │ 117 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 118 | │ setSwapCaller ┆ 22790 ┆ 22790 ┆ 22790 ┆ 22790 ┆ 5 │ 119 | ├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ 120 | │ swap ┆ 142378 ┆ 143241 ┆ 143241 ┆ 144104 ┆ 2 │ 121 | ╰─────────────────────────┴─────────────────┴────────┴────────┴────────┴─────────╯ 122 | ``` 123 | 124 | 125 | -------------------------------------------------------------------------------- /src/interfaces/IPoolAddressesProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.0; 3 | 4 | /** 5 | * @title IPoolAddressesProvider 6 | * @author Aave 7 | * @notice Defines the basic interface for a Pool Addresses Provider. 8 | **/ 9 | interface IPoolAddressesProvider { 10 | /** 11 | * @dev Emitted when the market identifier is updated. 12 | * @param oldMarketId The old id of the market 13 | * @param newMarketId The new id of the market 14 | */ 15 | event MarketIdSet(string indexed oldMarketId, string indexed newMarketId); 16 | 17 | /** 18 | * @dev Emitted when the pool is updated. 19 | * @param oldAddress The old address of the Pool 20 | * @param newAddress The new address of the Pool 21 | */ 22 | event PoolUpdated(address indexed oldAddress, address indexed newAddress); 23 | 24 | /** 25 | * @dev Emitted when the pool configurator is updated. 26 | * @param oldAddress The old address of the PoolConfigurator 27 | * @param newAddress The new address of the PoolConfigurator 28 | */ 29 | event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress); 30 | 31 | /** 32 | * @dev Emitted when the price oracle is updated. 33 | * @param oldAddress The old address of the PriceOracle 34 | * @param newAddress The new address of the PriceOracle 35 | */ 36 | event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress); 37 | 38 | /** 39 | * @dev Emitted when the ACL manager is updated. 40 | * @param oldAddress The old address of the ACLManager 41 | * @param newAddress The new address of the ACLManager 42 | */ 43 | event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress); 44 | 45 | /** 46 | * @dev Emitted when the ACL admin is updated. 47 | * @param oldAddress The old address of the ACLAdmin 48 | * @param newAddress The new address of the ACLAdmin 49 | */ 50 | event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress); 51 | 52 | /** 53 | * @dev Emitted when the price oracle sentinel is updated. 54 | * @param oldAddress The old address of the PriceOracleSentinel 55 | * @param newAddress The new address of the PriceOracleSentinel 56 | */ 57 | event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress); 58 | 59 | /** 60 | * @dev Emitted when the pool data provider is updated. 61 | * @param oldAddress The old address of the PoolDataProvider 62 | * @param newAddress The new address of the PoolDataProvider 63 | */ 64 | event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress); 65 | 66 | /** 67 | * @dev Emitted when a new proxy is created. 68 | * @param id The identifier of the proxy 69 | * @param proxyAddress The address of the created proxy contract 70 | * @param implementationAddress The address of the implementation contract 71 | */ 72 | event ProxyCreated( 73 | bytes32 indexed id, 74 | address indexed proxyAddress, 75 | address indexed implementationAddress 76 | ); 77 | 78 | /** 79 | * @dev Emitted when a new non-proxied contract address is registered. 80 | * @param id The identifier of the contract 81 | * @param oldAddress The address of the old contract 82 | * @param newAddress The address of the new contract 83 | */ 84 | event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress); 85 | 86 | /** 87 | * @dev Emitted when the implementation of the proxy registered with id is updated 88 | * @param id The identifier of the contract 89 | * @param proxyAddress The address of the proxy contract 90 | * @param oldImplementationAddress The address of the old implementation contract 91 | * @param newImplementationAddress The address of the new implementation contract 92 | */ 93 | event AddressSetAsProxy( 94 | bytes32 indexed id, 95 | address indexed proxyAddress, 96 | address oldImplementationAddress, 97 | address indexed newImplementationAddress 98 | ); 99 | 100 | /** 101 | * @notice Returns the id of the Aave market to which this contract points to. 102 | * @return The market id 103 | **/ 104 | function getMarketId() external view returns (string memory); 105 | 106 | /** 107 | * @notice Associates an id with a specific PoolAddressesProvider. 108 | * @dev This can be used to create an onchain registry of PoolAddressesProviders to 109 | * identify and validate multiple Aave markets. 110 | * @param newMarketId The market id 111 | */ 112 | function setMarketId(string calldata newMarketId) external; 113 | 114 | /** 115 | * @notice Returns an address by its identifier. 116 | * @dev The returned address might be an EOA or a contract, potentially proxied 117 | * @dev It returns ZERO if there is no registered address with the given id 118 | * @param id The id 119 | * @return The address of the registered for the specified id 120 | */ 121 | function getAddress(bytes32 id) external view returns (address); 122 | 123 | /** 124 | * @notice General function to update the implementation of a proxy registered with 125 | * certain `id`. If there is no proxy registered, it will instantiate one and 126 | * set as implementation the `newImplementationAddress`. 127 | * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit 128 | * setter function, in order to avoid unexpected consequences 129 | * @param id The id 130 | * @param newImplementationAddress The address of the new implementation 131 | */ 132 | function setAddressAsProxy(bytes32 id, address newImplementationAddress) external; 133 | 134 | /** 135 | * @notice Sets an address for an id replacing the address saved in the addresses map. 136 | * @dev IMPORTANT Use this function carefully, as it will do a hard replacement 137 | * @param id The id 138 | * @param newAddress The address to set 139 | */ 140 | function setAddress(bytes32 id, address newAddress) external; 141 | 142 | /** 143 | * @notice Returns the address of the Pool proxy. 144 | * @return The Pool proxy address 145 | **/ 146 | function getPool() external view returns (address); 147 | 148 | /** 149 | * @notice Updates the implementation of the Pool, or creates a proxy 150 | * setting the new `pool` implementation when the function is called for the first time. 151 | * @param newPoolImpl The new Pool implementation 152 | **/ 153 | function setPoolImpl(address newPoolImpl) external; 154 | 155 | /** 156 | * @notice Returns the address of the PoolConfigurator proxy. 157 | * @return The PoolConfigurator proxy address 158 | **/ 159 | function getPoolConfigurator() external view returns (address); 160 | 161 | /** 162 | * @notice Updates the implementation of the PoolConfigurator, or creates a proxy 163 | * setting the new `PoolConfigurator` implementation when the function is called for the first time. 164 | * @param newPoolConfiguratorImpl The new PoolConfigurator implementation 165 | **/ 166 | function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external; 167 | 168 | /** 169 | * @notice Returns the address of the price oracle. 170 | * @return The address of the PriceOracle 171 | */ 172 | function getPriceOracle() external view returns (address); 173 | 174 | /** 175 | * @notice Updates the address of the price oracle. 176 | * @param newPriceOracle The address of the new PriceOracle 177 | */ 178 | function setPriceOracle(address newPriceOracle) external; 179 | 180 | /** 181 | * @notice Returns the address of the ACL manager. 182 | * @return The address of the ACLManager 183 | */ 184 | function getACLManager() external view returns (address); 185 | 186 | /** 187 | * @notice Updates the address of the ACL manager. 188 | * @param newAclManager The address of the new ACLManager 189 | **/ 190 | function setACLManager(address newAclManager) external; 191 | 192 | /** 193 | * @notice Returns the address of the ACL admin. 194 | * @return The address of the ACL admin 195 | */ 196 | function getACLAdmin() external view returns (address); 197 | 198 | /** 199 | * @notice Updates the address of the ACL admin. 200 | * @param newAclAdmin The address of the new ACL admin 201 | */ 202 | function setACLAdmin(address newAclAdmin) external; 203 | 204 | /** 205 | * @notice Returns the address of the price oracle sentinel. 206 | * @return The address of the PriceOracleSentinel 207 | */ 208 | function getPriceOracleSentinel() external view returns (address); 209 | 210 | /** 211 | * @notice Updates the address of the price oracle sentinel. 212 | * @param newPriceOracleSentinel The address of the new PriceOracleSentinel 213 | **/ 214 | function setPriceOracleSentinel(address newPriceOracleSentinel) external; 215 | 216 | /** 217 | * @notice Returns the address of the data provider. 218 | * @return The address of the DataProvider 219 | */ 220 | function getPoolDataProvider() external view returns (address); 221 | 222 | /** 223 | * @notice Updates the address of the data provider. 224 | * @param newDataProvider The address of the new DataProvider 225 | **/ 226 | function setPoolDataProvider(address newDataProvider) external; 227 | } -------------------------------------------------------------------------------- /src/interfaces/ILendingPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity ^0.8.0; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import {ILendingPoolAddressesProvider} from './ILendingPoolAddressesProvider.sol'; 6 | import {DataTypes} from '../library/DataTypes.sol'; 7 | 8 | interface ILendingPool { 9 | /** 10 | * @dev Emitted on deposit() 11 | * @param reserve The address of the underlying asset of the reserve 12 | * @param user The address initiating the deposit 13 | * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens 14 | * @param amount The amount deposited 15 | * @param referral The referral code used 16 | **/ 17 | event Deposit( 18 | address indexed reserve, 19 | address user, 20 | address indexed onBehalfOf, 21 | uint256 amount, 22 | uint16 indexed referral 23 | ); 24 | 25 | /** 26 | * @dev Emitted on withdraw() 27 | * @param reserve The address of the underlyng asset being withdrawn 28 | * @param user The address initiating the withdrawal, owner of aTokens 29 | * @param to Address that will receive the underlying 30 | * @param amount The amount to be withdrawn 31 | **/ 32 | event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); 33 | 34 | /** 35 | * @dev Emitted on borrow() and flashLoan() when debt needs to be opened 36 | * @param reserve The address of the underlying asset being borrowed 37 | * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just 38 | * initiator of the transaction on flashLoan() 39 | * @param onBehalfOf The address that will be getting the debt 40 | * @param amount The amount borrowed out 41 | * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable 42 | * @param borrowRate The numeric rate at which the user has borrowed 43 | * @param referral The referral code used 44 | **/ 45 | event Borrow( 46 | address indexed reserve, 47 | address user, 48 | address indexed onBehalfOf, 49 | uint256 amount, 50 | uint256 borrowRateMode, 51 | uint256 borrowRate, 52 | uint16 indexed referral 53 | ); 54 | 55 | /** 56 | * @dev Emitted on repay() 57 | * @param reserve The address of the underlying asset of the reserve 58 | * @param user The beneficiary of the repayment, getting his debt reduced 59 | * @param repayer The address of the user initiating the repay(), providing the funds 60 | * @param amount The amount repaid 61 | **/ 62 | event Repay( 63 | address indexed reserve, 64 | address indexed user, 65 | address indexed repayer, 66 | uint256 amount 67 | ); 68 | 69 | /** 70 | * @dev Emitted on swapBorrowRateMode() 71 | * @param reserve The address of the underlying asset of the reserve 72 | * @param user The address of the user swapping his rate mode 73 | * @param rateMode The rate mode that the user wants to swap to 74 | **/ 75 | event Swap(address indexed reserve, address indexed user, uint256 rateMode); 76 | 77 | /** 78 | * @dev Emitted on setUserUseReserveAsCollateral() 79 | * @param reserve The address of the underlying asset of the reserve 80 | * @param user The address of the user enabling the usage as collateral 81 | **/ 82 | event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); 83 | 84 | /** 85 | * @dev Emitted on setUserUseReserveAsCollateral() 86 | * @param reserve The address of the underlying asset of the reserve 87 | * @param user The address of the user enabling the usage as collateral 88 | **/ 89 | event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); 90 | 91 | /** 92 | * @dev Emitted on rebalanceStableBorrowRate() 93 | * @param reserve The address of the underlying asset of the reserve 94 | * @param user The address of the user for which the rebalance has been executed 95 | **/ 96 | event RebalanceStableBorrowRate(address indexed reserve, address indexed user); 97 | 98 | /** 99 | * @dev Emitted on flashLoan() 100 | * @param target The address of the flash loan receiver contract 101 | * @param initiator The address initiating the flash loan 102 | * @param asset The address of the asset being flash borrowed 103 | * @param amount The amount flash borrowed 104 | * @param premium The fee flash borrowed 105 | * @param referralCode The referral code used 106 | **/ 107 | event FlashLoan( 108 | address indexed target, 109 | address indexed initiator, 110 | address indexed asset, 111 | uint256 amount, 112 | uint256 premium, 113 | uint16 referralCode 114 | ); 115 | 116 | /** 117 | * @dev Emitted when the pause is triggered. 118 | */ 119 | event Paused(); 120 | 121 | /** 122 | * @dev Emitted when the pause is lifted. 123 | */ 124 | event Unpaused(); 125 | 126 | /** 127 | * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via 128 | * LendingPoolCollateral manager using a DELEGATECALL 129 | * This allows to have the events in the generated ABI for LendingPool. 130 | * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation 131 | * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation 132 | * @param user The address of the borrower getting liquidated 133 | * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover 134 | * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator 135 | * @param liquidator The address of the liquidator 136 | * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants 137 | * to receive the underlying collateral asset directly 138 | **/ 139 | event LiquidationCall( 140 | address indexed collateralAsset, 141 | address indexed debtAsset, 142 | address indexed user, 143 | uint256 debtToCover, 144 | uint256 liquidatedCollateralAmount, 145 | address liquidator, 146 | bool receiveAToken 147 | ); 148 | 149 | /** 150 | * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared 151 | * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal, 152 | * the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it 153 | * gets added to the LendingPool ABI 154 | * @param reserve The address of the underlying asset of the reserve 155 | * @param liquidityRate The new liquidity rate 156 | * @param stableBorrowRate The new stable borrow rate 157 | * @param variableBorrowRate The new variable borrow rate 158 | * @param liquidityIndex The new liquidity index 159 | * @param variableBorrowIndex The new variable borrow index 160 | **/ 161 | event ReserveDataUpdated( 162 | address indexed reserve, 163 | uint256 liquidityRate, 164 | uint256 stableBorrowRate, 165 | uint256 variableBorrowRate, 166 | uint256 liquidityIndex, 167 | uint256 variableBorrowIndex 168 | ); 169 | 170 | /** 171 | * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. 172 | * - E.g. User deposits 100 USDC and gets in return 100 aUSDC 173 | * @param asset The address of the underlying asset to deposit 174 | * @param amount The amount to be deposited 175 | * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user 176 | * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens 177 | * is a different wallet 178 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 179 | * 0 if the action is executed directly by the user, without any middle-man 180 | **/ 181 | function deposit( 182 | address asset, 183 | uint256 amount, 184 | address onBehalfOf, 185 | uint16 referralCode 186 | ) external; 187 | 188 | /** 189 | * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned 190 | * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC 191 | * @param asset The address of the underlying asset to withdraw 192 | * @param amount The underlying amount to be withdrawn 193 | * - Send the value type(uint256).max in order to withdraw the whole aToken balance 194 | * @param to Address that will receive the underlying, same as msg.sender if the user 195 | * wants to receive it on his own wallet, or a different address if the beneficiary is a 196 | * different wallet 197 | * @return The final amount withdrawn 198 | **/ 199 | function withdraw( 200 | address asset, 201 | uint256 amount, 202 | address to 203 | ) external returns (uint256); 204 | 205 | /** 206 | * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower 207 | * already deposited enough collateral, or he was given enough allowance by a credit delegator on the 208 | * corresponding debt token (StableDebtToken or VariableDebtToken) 209 | * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet 210 | * and 100 stable/variable debt tokens, depending on the `interestRateMode` 211 | * @param asset The address of the underlying asset to borrow 212 | * @param amount The amount to be borrowed 213 | * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable 214 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 215 | * 0 if the action is executed directly by the user, without any middle-man 216 | * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself 217 | * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator 218 | * if he has been given credit delegation allowance 219 | **/ 220 | function borrow( 221 | address asset, 222 | uint256 amount, 223 | uint256 interestRateMode, 224 | uint16 referralCode, 225 | address onBehalfOf 226 | ) external; 227 | 228 | /** 229 | * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned 230 | * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address 231 | * @param asset The address of the borrowed underlying asset previously borrowed 232 | * @param amount The amount to repay 233 | * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` 234 | * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable 235 | * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the 236 | * user calling the function if he wants to reduce/remove his own debt, or the address of any other 237 | * other borrower whose debt should be removed 238 | * @return The final amount repaid 239 | **/ 240 | function repay( 241 | address asset, 242 | uint256 amount, 243 | uint256 rateMode, 244 | address onBehalfOf 245 | ) external returns (uint256); 246 | 247 | /** 248 | * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa 249 | * @param asset The address of the underlying asset borrowed 250 | * @param rateMode The rate mode that the user wants to swap to 251 | **/ 252 | function swapBorrowRateMode(address asset, uint256 rateMode) external; 253 | 254 | /** 255 | * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. 256 | * - Users can be rebalanced if the following conditions are satisfied: 257 | * 1. Usage ratio is above 95% 258 | * 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been 259 | * borrowed at a stable rate and depositors are not earning enough 260 | * @param asset The address of the underlying asset borrowed 261 | * @param user The address of the user to be rebalanced 262 | **/ 263 | function rebalanceStableBorrowRate(address asset, address user) external; 264 | 265 | /** 266 | * @dev Allows depositors to enable/disable a specific deposited asset as collateral 267 | * @param asset The address of the underlying asset deposited 268 | * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise 269 | **/ 270 | function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; 271 | 272 | /** 273 | * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 274 | * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives 275 | * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk 276 | * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation 277 | * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation 278 | * @param user The address of the borrower getting liquidated 279 | * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover 280 | * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants 281 | * to receive the underlying collateral asset directly 282 | **/ 283 | function liquidationCall( 284 | address collateralAsset, 285 | address debtAsset, 286 | address user, 287 | uint256 debtToCover, 288 | bool receiveAToken 289 | ) external; 290 | 291 | /** 292 | * @dev Allows smartcontracts to access the liquidity of the pool within one transaction, 293 | * as long as the amount taken plus a fee is returned. 294 | * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration. 295 | * For further details please visit https://developers.aave.com 296 | * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface 297 | * @param assets The addresses of the assets being flash-borrowed 298 | * @param amounts The amounts amounts being flash-borrowed 299 | * @param modes Types of the debt to open if the flash loan is not returned: 300 | * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver 301 | * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address 302 | * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address 303 | * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 304 | * @param params Variadic packed params to pass to the receiver as extra information 305 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 306 | * 0 if the action is executed directly by the user, without any middle-man 307 | **/ 308 | function flashLoan( 309 | address receiverAddress, 310 | address[] calldata assets, 311 | uint256[] calldata amounts, 312 | uint256[] calldata modes, 313 | address onBehalfOf, 314 | bytes calldata params, 315 | uint16 referralCode 316 | ) external; 317 | 318 | /** 319 | * @dev Returns the user account data across all the reserves 320 | * @param user The address of the user 321 | * @return totalCollateralETH the total collateral in ETH of the user 322 | * @return totalDebtETH the total debt in ETH of the user 323 | * @return availableBorrowsETH the borrowing power left of the user 324 | * @return currentLiquidationThreshold the liquidation threshold of the user 325 | * @return ltv the loan to value of the user 326 | * @return healthFactor the current health factor of the user 327 | **/ 328 | function getUserAccountData(address user) 329 | external 330 | view 331 | returns ( 332 | uint256 totalCollateralETH, 333 | uint256 totalDebtETH, 334 | uint256 availableBorrowsETH, 335 | uint256 currentLiquidationThreshold, 336 | uint256 ltv, 337 | uint256 healthFactor 338 | ); 339 | 340 | function initReserve( 341 | address reserve, 342 | address aTokenAddress, 343 | address stableDebtAddress, 344 | address variableDebtAddress, 345 | address interestRateStrategyAddress 346 | ) external; 347 | 348 | function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress) 349 | external; 350 | 351 | function setConfiguration(address reserve, uint256 configuration) external; 352 | 353 | /** 354 | * @dev Returns the configuration of the reserve 355 | * @param asset The address of the underlying asset of the reserve 356 | * @return The configuration of the reserve 357 | **/ 358 | function getConfiguration(address asset) 359 | external 360 | view 361 | returns (DataTypes.ReserveConfigurationMap memory); 362 | 363 | /** 364 | * @dev Returns the configuration of the user across all the reserves 365 | * @param user The user address 366 | * @return The configuration of the user 367 | **/ 368 | function getUserConfiguration(address user) 369 | external 370 | view 371 | returns (DataTypes.UserConfigurationMap memory); 372 | 373 | /** 374 | * @dev Returns the normalized income normalized income of the reserve 375 | * @param asset The address of the underlying asset of the reserve 376 | * @return The reserve's normalized income 377 | */ 378 | function getReserveNormalizedIncome(address asset) external view returns (uint256); 379 | 380 | /** 381 | * @dev Returns the normalized variable debt per unit of asset 382 | * @param asset The address of the underlying asset of the reserve 383 | * @return The reserve normalized variable debt 384 | */ 385 | function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); 386 | 387 | /** 388 | * @dev Returns the state and configuration of the reserve 389 | * @param asset The address of the underlying asset of the reserve 390 | * @return The state of the reserve 391 | **/ 392 | function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); 393 | 394 | function finalizeTransfer( 395 | address asset, 396 | address from, 397 | address to, 398 | uint256 amount, 399 | uint256 balanceFromAfter, 400 | uint256 balanceToBefore 401 | ) external; 402 | 403 | function getReservesList() external view returns (address[] memory); 404 | 405 | function getAddressesProvider() external view returns (ILendingPoolAddressesProvider); 406 | 407 | function setPause(bool val) external; 408 | 409 | function paused() external view returns (bool); 410 | } -------------------------------------------------------------------------------- /lib/forge-std/Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity >=0.6.0; 3 | 4 | import "./Script.sol"; 5 | import "ds-test/test.sol"; 6 | 7 | // Wrappers around Cheatcodes to avoid footguns 8 | abstract contract Test is DSTest, Script { 9 | using stdStorage for StdStorage; 10 | 11 | uint256 private constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; 12 | 13 | event WARNING_Deprecated(string msg); 14 | 15 | StdStorage internal stdstore; 16 | 17 | /*////////////////////////////////////////////////////////////////////////// 18 | STD-CHEATS 19 | //////////////////////////////////////////////////////////////////////////*/ 20 | 21 | // Skip forward or rewind time by the specified number of seconds 22 | function skip(uint256 time) public { 23 | vm.warp(block.timestamp + time); 24 | } 25 | 26 | function rewind(uint256 time) public { 27 | vm.warp(block.timestamp - time); 28 | } 29 | 30 | // Setup a prank from an address that has some ether 31 | function hoax(address who) public { 32 | vm.deal(who, 1 << 128); 33 | vm.prank(who); 34 | } 35 | 36 | function hoax(address who, uint256 give) public { 37 | vm.deal(who, give); 38 | vm.prank(who); 39 | } 40 | 41 | function hoax(address who, address origin) public { 42 | vm.deal(who, 1 << 128); 43 | vm.prank(who, origin); 44 | } 45 | 46 | function hoax(address who, address origin, uint256 give) public { 47 | vm.deal(who, give); 48 | vm.prank(who, origin); 49 | } 50 | 51 | // Start perpetual prank from an address that has some ether 52 | function startHoax(address who) public { 53 | vm.deal(who, 1 << 128); 54 | vm.startPrank(who); 55 | } 56 | 57 | function startHoax(address who, uint256 give) public { 58 | vm.deal(who, give); 59 | vm.startPrank(who); 60 | } 61 | 62 | // Start perpetual prank from an address that has some ether 63 | // tx.origin is set to the origin parameter 64 | function startHoax(address who, address origin) public { 65 | vm.deal(who, 1 << 128); 66 | vm.startPrank(who, origin); 67 | } 68 | 69 | function startHoax(address who, address origin, uint256 give) public { 70 | vm.deal(who, give); 71 | vm.startPrank(who, origin); 72 | } 73 | 74 | function changePrank(address who) internal { 75 | vm.stopPrank(); 76 | vm.startPrank(who); 77 | } 78 | 79 | // DEPRECATED: Use `deal` instead 80 | function tip(address token, address to, uint256 give) public { 81 | emit WARNING_Deprecated("The `tip` stdcheat has been deprecated. Use `deal` instead."); 82 | stdstore 83 | .target(token) 84 | .sig(0x70a08231) 85 | .with_key(to) 86 | .checked_write(give); 87 | } 88 | 89 | // The same as Hevm's `deal` 90 | // Use the alternative signature for ERC20 tokens 91 | function deal(address to, uint256 give) public { 92 | vm.deal(to, give); 93 | } 94 | 95 | // Set the balance of an account for any ERC20 token 96 | // Use the alternative signature to update `totalSupply` 97 | function deal(address token, address to, uint256 give) public { 98 | deal(token, to, give, false); 99 | } 100 | 101 | function deal(address token, address to, uint256 give, bool adjust) public { 102 | // get current balance 103 | (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to)); 104 | uint256 prevBal = abi.decode(balData, (uint256)); 105 | 106 | // update balance 107 | stdstore 108 | .target(token) 109 | .sig(0x70a08231) 110 | .with_key(to) 111 | .checked_write(give); 112 | 113 | // update total supply 114 | if(adjust){ 115 | (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd)); 116 | uint256 totSup = abi.decode(totSupData, (uint256)); 117 | if(give < prevBal) { 118 | totSup -= (prevBal - give); 119 | } else { 120 | totSup += (give - prevBal); 121 | } 122 | stdstore 123 | .target(token) 124 | .sig(0x18160ddd) 125 | .checked_write(totSup); 126 | } 127 | } 128 | 129 | function bound(uint256 x, uint256 min, uint256 max) public returns (uint256 result) { 130 | require(min <= max, "Test bound(uint256,uint256,uint256): Max is less than min."); 131 | 132 | uint256 size = max - min; 133 | 134 | if (size == 0) 135 | { 136 | result = min; 137 | } 138 | else if (size == UINT256_MAX) 139 | { 140 | result = x; 141 | } 142 | else 143 | { 144 | ++size; // make `max` inclusive 145 | uint256 mod = x % size; 146 | result = min + mod; 147 | } 148 | 149 | emit log_named_uint("Bound Result", result); 150 | } 151 | 152 | // Deploy a contract by fetching the contract bytecode from 153 | // the artifacts directory 154 | // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))` 155 | function deployCode(string memory what, bytes memory args) 156 | public 157 | returns (address addr) 158 | { 159 | bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); 160 | /// @solidity memory-safe-assembly 161 | assembly { 162 | addr := create(0, add(bytecode, 0x20), mload(bytecode)) 163 | } 164 | 165 | require( 166 | addr != address(0), 167 | "Test deployCode(string,bytes): Deployment failed." 168 | ); 169 | } 170 | 171 | function deployCode(string memory what) 172 | public 173 | returns (address addr) 174 | { 175 | bytes memory bytecode = vm.getCode(what); 176 | /// @solidity memory-safe-assembly 177 | assembly { 178 | addr := create(0, add(bytecode, 0x20), mload(bytecode)) 179 | } 180 | 181 | require( 182 | addr != address(0), 183 | "Test deployCode(string): Deployment failed." 184 | ); 185 | } 186 | 187 | /*////////////////////////////////////////////////////////////////////////// 188 | STD-ASSERTIONS 189 | //////////////////////////////////////////////////////////////////////////*/ 190 | 191 | function fail(string memory err) internal virtual { 192 | emit log_named_string("Error", err); 193 | fail(); 194 | } 195 | 196 | function assertFalse(bool data) internal virtual { 197 | assertTrue(!data); 198 | } 199 | 200 | function assertFalse(bool data, string memory err) internal virtual { 201 | assertTrue(!data, err); 202 | } 203 | 204 | function assertEq(bool a, bool b) internal { 205 | if (a != b) { 206 | emit log ("Error: a == b not satisfied [bool]"); 207 | emit log_named_string (" Expected", b ? "true" : "false"); 208 | emit log_named_string (" Actual", a ? "true" : "false"); 209 | fail(); 210 | } 211 | } 212 | 213 | function assertEq(bool a, bool b, string memory err) internal { 214 | if (a != b) { 215 | emit log_named_string("Error", err); 216 | assertEq(a, b); 217 | } 218 | } 219 | 220 | function assertEq(bytes memory a, bytes memory b) internal { 221 | assertEq0(a, b); 222 | } 223 | 224 | function assertEq(bytes memory a, bytes memory b, string memory err) internal { 225 | assertEq0(a, b, err); 226 | } 227 | 228 | function assertApproxEqAbs( 229 | uint256 a, 230 | uint256 b, 231 | uint256 maxDelta 232 | ) internal virtual { 233 | uint256 delta = stdMath.delta(a, b); 234 | 235 | if (delta > maxDelta) { 236 | emit log ("Error: a ~= b not satisfied [uint]"); 237 | emit log_named_uint (" Expected", b); 238 | emit log_named_uint (" Actual", a); 239 | emit log_named_uint (" Max Delta", maxDelta); 240 | emit log_named_uint (" Delta", delta); 241 | fail(); 242 | } 243 | } 244 | 245 | function assertApproxEqAbs( 246 | uint256 a, 247 | uint256 b, 248 | uint256 maxDelta, 249 | string memory err 250 | ) internal virtual { 251 | uint256 delta = stdMath.delta(a, b); 252 | 253 | if (delta > maxDelta) { 254 | emit log_named_string ("Error", err); 255 | assertApproxEqAbs(a, b, maxDelta); 256 | } 257 | } 258 | 259 | function assertApproxEqAbs( 260 | int256 a, 261 | int256 b, 262 | uint256 maxDelta 263 | ) internal virtual { 264 | uint256 delta = stdMath.delta(a, b); 265 | 266 | if (delta > maxDelta) { 267 | emit log ("Error: a ~= b not satisfied [int]"); 268 | emit log_named_int (" Expected", b); 269 | emit log_named_int (" Actual", a); 270 | emit log_named_uint (" Max Delta", maxDelta); 271 | emit log_named_uint (" Delta", delta); 272 | fail(); 273 | } 274 | } 275 | 276 | function assertApproxEqAbs( 277 | int256 a, 278 | int256 b, 279 | uint256 maxDelta, 280 | string memory err 281 | ) internal virtual { 282 | uint256 delta = stdMath.delta(a, b); 283 | 284 | if (delta > maxDelta) { 285 | emit log_named_string ("Error", err); 286 | assertApproxEqAbs(a, b, maxDelta); 287 | } 288 | } 289 | 290 | function assertApproxEqRel( 291 | uint256 a, 292 | uint256 b, 293 | uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% 294 | ) internal virtual { 295 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. 296 | 297 | uint256 percentDelta = stdMath.percentDelta(a, b); 298 | 299 | if (percentDelta > maxPercentDelta) { 300 | emit log ("Error: a ~= b not satisfied [uint]"); 301 | emit log_named_uint (" Expected", b); 302 | emit log_named_uint (" Actual", a); 303 | emit log_named_decimal_uint (" Max % Delta", maxPercentDelta, 18); 304 | emit log_named_decimal_uint (" % Delta", percentDelta, 18); 305 | fail(); 306 | } 307 | } 308 | 309 | function assertApproxEqRel( 310 | uint256 a, 311 | uint256 b, 312 | uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% 313 | string memory err 314 | ) internal virtual { 315 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. 316 | 317 | uint256 percentDelta = stdMath.percentDelta(a, b); 318 | 319 | if (percentDelta > maxPercentDelta) { 320 | emit log_named_string ("Error", err); 321 | assertApproxEqRel(a, b, maxPercentDelta); 322 | } 323 | } 324 | 325 | function assertApproxEqRel( 326 | int256 a, 327 | int256 b, 328 | uint256 maxPercentDelta 329 | ) internal virtual { 330 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. 331 | 332 | uint256 percentDelta = stdMath.percentDelta(a, b); 333 | 334 | if (percentDelta > maxPercentDelta) { 335 | emit log ("Error: a ~= b not satisfied [int]"); 336 | emit log_named_int (" Expected", b); 337 | emit log_named_int (" Actual", a); 338 | emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); 339 | emit log_named_decimal_uint(" % Delta", percentDelta, 18); 340 | fail(); 341 | } 342 | } 343 | 344 | function assertApproxEqRel( 345 | int256 a, 346 | int256 b, 347 | uint256 maxPercentDelta, 348 | string memory err 349 | ) internal virtual { 350 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. 351 | 352 | uint256 percentDelta = stdMath.percentDelta(a, b); 353 | 354 | if (percentDelta > maxPercentDelta) { 355 | emit log_named_string ("Error", err); 356 | assertApproxEqRel(a, b, maxPercentDelta); 357 | } 358 | } 359 | } 360 | 361 | /*////////////////////////////////////////////////////////////////////////// 362 | STD-ERRORS 363 | //////////////////////////////////////////////////////////////////////////*/ 364 | 365 | library stdError { 366 | bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); 367 | bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); 368 | bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); 369 | bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); 370 | bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); 371 | bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); 372 | bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); 373 | bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); 374 | bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); 375 | // DEPRECATED: Use Hevm's `expectRevert` without any arguments instead 376 | bytes public constant lowLevelError = bytes(""); // `0x` 377 | } 378 | 379 | /*////////////////////////////////////////////////////////////////////////// 380 | STD-STORAGE 381 | //////////////////////////////////////////////////////////////////////////*/ 382 | 383 | struct StdStorage { 384 | mapping (address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; 385 | mapping (address => mapping(bytes4 => mapping(bytes32 => bool))) finds; 386 | 387 | bytes32[] _keys; 388 | bytes4 _sig; 389 | uint256 _depth; 390 | address _target; 391 | bytes32 _set; 392 | } 393 | 394 | library stdStorage { 395 | event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint slot); 396 | event WARNING_UninitedSlot(address who, uint slot); 397 | 398 | uint256 private constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; 399 | int256 private constant INT256_MAX = 57896044618658097711785492504343953926634992332820282019728792003956564819967; 400 | 401 | Vm private constant vm_std_store = Vm(address(uint160(uint256(keccak256('hevm cheat code'))))); 402 | 403 | function sigs( 404 | string memory sigStr 405 | ) 406 | internal 407 | pure 408 | returns (bytes4) 409 | { 410 | return bytes4(keccak256(bytes(sigStr))); 411 | } 412 | 413 | /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against 414 | // slot complexity: 415 | // if flat, will be bytes32(uint256(uint)); 416 | // if map, will be keccak256(abi.encode(key, uint(slot))); 417 | // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot))))); 418 | // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); 419 | function find( 420 | StdStorage storage self 421 | ) 422 | internal 423 | returns (uint256) 424 | { 425 | address who = self._target; 426 | bytes4 fsig = self._sig; 427 | uint256 field_depth = self._depth; 428 | bytes32[] memory ins = self._keys; 429 | 430 | // calldata to test against 431 | if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { 432 | return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; 433 | } 434 | bytes memory cald = abi.encodePacked(fsig, flatten(ins)); 435 | vm_std_store.record(); 436 | bytes32 fdat; 437 | { 438 | (, bytes memory rdat) = who.staticcall(cald); 439 | fdat = bytesToBytes32(rdat, 32*field_depth); 440 | } 441 | 442 | (bytes32[] memory reads, ) = vm_std_store.accesses(address(who)); 443 | if (reads.length == 1) { 444 | bytes32 curr = vm_std_store.load(who, reads[0]); 445 | if (curr == bytes32(0)) { 446 | emit WARNING_UninitedSlot(who, uint256(reads[0])); 447 | } 448 | if (fdat != curr) { 449 | require(false, "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isnt supported"); 450 | } 451 | emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0])); 452 | self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]); 453 | self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; 454 | } else if (reads.length > 1) { 455 | for (uint256 i = 0; i < reads.length; i++) { 456 | bytes32 prev = vm_std_store.load(who, reads[i]); 457 | if (prev == bytes32(0)) { 458 | emit WARNING_UninitedSlot(who, uint256(reads[i])); 459 | } 460 | // store 461 | vm_std_store.store(who, reads[i], bytes32(hex"1337")); 462 | bool success; 463 | bytes memory rdat; 464 | { 465 | (success, rdat) = who.staticcall(cald); 466 | fdat = bytesToBytes32(rdat, 32*field_depth); 467 | } 468 | 469 | if (success && fdat == bytes32(hex"1337")) { 470 | // we found which of the slots is the actual one 471 | emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); 472 | self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]); 473 | self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; 474 | vm_std_store.store(who, reads[i], prev); 475 | break; 476 | } 477 | vm_std_store.store(who, reads[i], prev); 478 | } 479 | } else { 480 | require(false, "stdStorage find(StdStorage): No storage use detected for target."); 481 | } 482 | 483 | require(self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], "stdStorage find(StdStorage): Slot(s) not found."); 484 | 485 | delete self._target; 486 | delete self._sig; 487 | delete self._keys; 488 | delete self._depth; 489 | 490 | return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; 491 | } 492 | 493 | function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { 494 | self._target = _target; 495 | return self; 496 | } 497 | 498 | function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { 499 | self._sig = _sig; 500 | return self; 501 | } 502 | 503 | function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { 504 | self._sig = sigs(_sig); 505 | return self; 506 | } 507 | 508 | function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { 509 | self._keys.push(bytes32(uint256(uint160(who)))); 510 | return self; 511 | } 512 | 513 | function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { 514 | self._keys.push(bytes32(amt)); 515 | return self; 516 | } 517 | function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { 518 | self._keys.push(key); 519 | return self; 520 | } 521 | 522 | function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { 523 | self._depth = _depth; 524 | return self; 525 | } 526 | 527 | function checked_write(StdStorage storage self, address who) internal { 528 | checked_write(self, bytes32(uint256(uint160(who)))); 529 | } 530 | 531 | function checked_write(StdStorage storage self, uint256 amt) internal { 532 | checked_write(self, bytes32(amt)); 533 | } 534 | 535 | function checked_write(StdStorage storage self, bool write) internal { 536 | bytes32 t; 537 | /// @solidity memory-safe-assembly 538 | assembly { 539 | t := write 540 | } 541 | checked_write(self, t); 542 | } 543 | 544 | function checked_write( 545 | StdStorage storage self, 546 | bytes32 set 547 | ) internal { 548 | address who = self._target; 549 | bytes4 fsig = self._sig; 550 | uint256 field_depth = self._depth; 551 | bytes32[] memory ins = self._keys; 552 | 553 | bytes memory cald = abi.encodePacked(fsig, flatten(ins)); 554 | if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { 555 | find(self); 556 | } 557 | bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]); 558 | 559 | bytes32 fdat; 560 | { 561 | (, bytes memory rdat) = who.staticcall(cald); 562 | fdat = bytesToBytes32(rdat, 32*field_depth); 563 | } 564 | bytes32 curr = vm_std_store.load(who, slot); 565 | 566 | if (fdat != curr) { 567 | require(false, "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isnt supported."); 568 | } 569 | vm_std_store.store(who, slot, set); 570 | delete self._target; 571 | delete self._sig; 572 | delete self._keys; 573 | delete self._depth; 574 | } 575 | 576 | function read(StdStorage storage self) private returns (bytes memory) { 577 | address t = self._target; 578 | uint256 s = find(self); 579 | return abi.encode(vm_std_store.load(t, bytes32(s))); 580 | } 581 | 582 | function read_bytes32(StdStorage storage self) internal returns (bytes32) { 583 | return abi.decode(read(self), (bytes32)); 584 | } 585 | 586 | 587 | function read_bool(StdStorage storage self) internal returns (bool) { 588 | return abi.decode(read(self), (bool)); 589 | } 590 | 591 | function read_address(StdStorage storage self) internal returns (address) { 592 | return abi.decode(read(self), (address)); 593 | } 594 | 595 | function read_uint(StdStorage storage self) internal returns (uint256) { 596 | return abi.decode(read(self), (uint256)); 597 | } 598 | 599 | function read_int(StdStorage storage self) internal returns (int256) { 600 | return abi.decode(read(self), (int256)); 601 | } 602 | 603 | function bytesToBytes32(bytes memory b, uint offset) public pure returns (bytes32) { 604 | bytes32 out; 605 | 606 | uint256 max = b.length > 32 ? 32 : b.length; 607 | for (uint i = 0; i < max; i++) { 608 | out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); 609 | } 610 | return out; 611 | } 612 | 613 | function flatten(bytes32[] memory b) private pure returns (bytes memory) 614 | { 615 | bytes memory result = new bytes(b.length * 32); 616 | for (uint256 i = 0; i < b.length; i++) { 617 | bytes32 k = b[i]; 618 | /// @solidity memory-safe-assembly 619 | assembly { 620 | mstore(add(result, add(32, mul(32, i))), k) 621 | } 622 | } 623 | 624 | return result; 625 | } 626 | } 627 | 628 | /*////////////////////////////////////////////////////////////////////////// 629 | STD-MATH 630 | //////////////////////////////////////////////////////////////////////////*/ 631 | 632 | library stdMath { 633 | int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; 634 | 635 | function abs(int256 a) internal pure returns (uint256) { 636 | // Required or it will fail when `a = type(int256).min` 637 | if (a == INT256_MIN) 638 | return 57896044618658097711785492504343953926634992332820282019728792003956564819968; 639 | 640 | return uint256(a >= 0 ? a : -a); 641 | } 642 | 643 | function delta(uint256 a, uint256 b) internal pure returns (uint256) { 644 | return a > b 645 | ? a - b 646 | : b - a; 647 | } 648 | 649 | function delta(int256 a, int256 b) internal pure returns (uint256) { 650 | // a and b are of the same sign 651 | if (a >= 0 && b >= 0 || a < 0 && b < 0) { 652 | return delta(abs(a), abs(b)); 653 | } 654 | 655 | // a and b are of opposite signs 656 | return abs(a) + abs(b); 657 | } 658 | 659 | function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { 660 | uint256 absDelta = delta(a, b); 661 | 662 | return absDelta * 1e18 / b; 663 | } 664 | 665 | function percentDelta(int256 a, int256 b) internal pure returns (uint256) { 666 | uint256 absDelta = delta(a, b); 667 | uint256 absB = abs(b); 668 | 669 | return absDelta * 1e18 / absB; 670 | } 671 | } -------------------------------------------------------------------------------- /src/interfaces/IPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.0; 3 | 4 | import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol'; 5 | import {DataTypes} from '../library/DataTypes.sol'; 6 | 7 | /** 8 | * @title IPool 9 | * @author Aave 10 | * @notice Defines the basic interface for an Aave Pool. 11 | **/ 12 | interface IPool { 13 | /** 14 | * @dev Emitted on mintUnbacked() 15 | * @param reserve The address of the underlying asset of the reserve 16 | * @param user The address initiating the supply 17 | * @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens 18 | * @param amount The amount of supplied assets 19 | * @param referralCode The referral code used 20 | **/ 21 | event MintUnbacked( 22 | address indexed reserve, 23 | address user, 24 | address indexed onBehalfOf, 25 | uint256 amount, 26 | uint16 indexed referralCode 27 | ); 28 | 29 | /** 30 | * @dev Emitted on backUnbacked() 31 | * @param reserve The address of the underlying asset of the reserve 32 | * @param backer The address paying for the backing 33 | * @param amount The amount added as backing 34 | * @param fee The amount paid in fees 35 | **/ 36 | event BackUnbacked(address indexed reserve, address indexed backer, uint256 amount, uint256 fee); 37 | 38 | /** 39 | * @dev Emitted on supply() 40 | * @param reserve The address of the underlying asset of the reserve 41 | * @param user The address initiating the supply 42 | * @param onBehalfOf The beneficiary of the supply, receiving the aTokens 43 | * @param amount The amount supplied 44 | * @param referralCode The referral code used 45 | **/ 46 | event Supply( 47 | address indexed reserve, 48 | address user, 49 | address indexed onBehalfOf, 50 | uint256 amount, 51 | uint16 indexed referralCode 52 | ); 53 | 54 | /** 55 | * @dev Emitted on withdraw() 56 | * @param reserve The address of the underlying asset being withdrawn 57 | * @param user The address initiating the withdrawal, owner of aTokens 58 | * @param to The address that will receive the underlying 59 | * @param amount The amount to be withdrawn 60 | **/ 61 | event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); 62 | 63 | /** 64 | * @dev Emitted on borrow() and flashLoan() when debt needs to be opened 65 | * @param reserve The address of the underlying asset being borrowed 66 | * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just 67 | * initiator of the transaction on flashLoan() 68 | * @param onBehalfOf The address that will be getting the debt 69 | * @param amount The amount borrowed out 70 | * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable 71 | * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray 72 | * @param referralCode The referral code used 73 | **/ 74 | event Borrow( 75 | address indexed reserve, 76 | address user, 77 | address indexed onBehalfOf, 78 | uint256 amount, 79 | DataTypes.InterestRateMode interestRateMode, 80 | uint256 borrowRate, 81 | uint16 indexed referralCode 82 | ); 83 | 84 | /** 85 | * @dev Emitted on repay() 86 | * @param reserve The address of the underlying asset of the reserve 87 | * @param user The beneficiary of the repayment, getting his debt reduced 88 | * @param repayer The address of the user initiating the repay(), providing the funds 89 | * @param amount The amount repaid 90 | * @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly 91 | **/ 92 | event Repay( 93 | address indexed reserve, 94 | address indexed user, 95 | address indexed repayer, 96 | uint256 amount, 97 | bool useATokens 98 | ); 99 | 100 | /** 101 | * @dev Emitted on swapBorrowRateMode() 102 | * @param reserve The address of the underlying asset of the reserve 103 | * @param user The address of the user swapping his rate mode 104 | * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable 105 | **/ 106 | event SwapBorrowRateMode( 107 | address indexed reserve, 108 | address indexed user, 109 | DataTypes.InterestRateMode interestRateMode 110 | ); 111 | 112 | /** 113 | * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets 114 | * @param asset The address of the underlying asset of the reserve 115 | * @param totalDebt The total isolation mode debt for the reserve 116 | */ 117 | event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt); 118 | 119 | /** 120 | * @dev Emitted when the user selects a certain asset category for eMode 121 | * @param user The address of the user 122 | * @param categoryId The category id 123 | **/ 124 | event UserEModeSet(address indexed user, uint8 categoryId); 125 | 126 | /** 127 | * @dev Emitted on setUserUseReserveAsCollateral() 128 | * @param reserve The address of the underlying asset of the reserve 129 | * @param user The address of the user enabling the usage as collateral 130 | **/ 131 | event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); 132 | 133 | /** 134 | * @dev Emitted on setUserUseReserveAsCollateral() 135 | * @param reserve The address of the underlying asset of the reserve 136 | * @param user The address of the user enabling the usage as collateral 137 | **/ 138 | event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); 139 | 140 | /** 141 | * @dev Emitted on rebalanceStableBorrowRate() 142 | * @param reserve The address of the underlying asset of the reserve 143 | * @param user The address of the user for which the rebalance has been executed 144 | **/ 145 | event RebalanceStableBorrowRate(address indexed reserve, address indexed user); 146 | 147 | /** 148 | * @dev Emitted on flashLoan() 149 | * @param target The address of the flash loan receiver contract 150 | * @param initiator The address initiating the flash loan 151 | * @param asset The address of the asset being flash borrowed 152 | * @param amount The amount flash borrowed 153 | * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt 154 | * @param premium The fee flash borrowed 155 | * @param referralCode The referral code used 156 | **/ 157 | event FlashLoan( 158 | address indexed target, 159 | address initiator, 160 | address indexed asset, 161 | uint256 amount, 162 | DataTypes.InterestRateMode interestRateMode, 163 | uint256 premium, 164 | uint16 indexed referralCode 165 | ); 166 | 167 | /** 168 | * @dev Emitted when a borrower is liquidated. 169 | * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation 170 | * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation 171 | * @param user The address of the borrower getting liquidated 172 | * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover 173 | * @param liquidatedCollateralAmount The amount of collateral received by the liquidator 174 | * @param liquidator The address of the liquidator 175 | * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants 176 | * to receive the underlying collateral asset directly 177 | **/ 178 | event LiquidationCall( 179 | address indexed collateralAsset, 180 | address indexed debtAsset, 181 | address indexed user, 182 | uint256 debtToCover, 183 | uint256 liquidatedCollateralAmount, 184 | address liquidator, 185 | bool receiveAToken 186 | ); 187 | 188 | /** 189 | * @dev Emitted when the state of a reserve is updated. 190 | * @param reserve The address of the underlying asset of the reserve 191 | * @param liquidityRate The next liquidity rate 192 | * @param stableBorrowRate The next stable borrow rate 193 | * @param variableBorrowRate The next variable borrow rate 194 | * @param liquidityIndex The next liquidity index 195 | * @param variableBorrowIndex The next variable borrow index 196 | **/ 197 | event ReserveDataUpdated( 198 | address indexed reserve, 199 | uint256 liquidityRate, 200 | uint256 stableBorrowRate, 201 | uint256 variableBorrowRate, 202 | uint256 liquidityIndex, 203 | uint256 variableBorrowIndex 204 | ); 205 | 206 | /** 207 | * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest. 208 | * @param reserve The address of the reserve 209 | * @param amountMinted The amount minted to the treasury 210 | **/ 211 | event MintedToTreasury(address indexed reserve, uint256 amountMinted); 212 | 213 | /** 214 | * @dev Mints an `amount` of aTokens to the `onBehalfOf` 215 | * @param asset The address of the underlying asset to mint 216 | * @param amount The amount to mint 217 | * @param onBehalfOf The address that will receive the aTokens 218 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 219 | * 0 if the action is executed directly by the user, without any middle-man 220 | **/ 221 | function mintUnbacked( 222 | address asset, 223 | uint256 amount, 224 | address onBehalfOf, 225 | uint16 referralCode 226 | ) external; 227 | 228 | /** 229 | * @dev Back the current unbacked underlying with `amount` and pay `fee`. 230 | * @param asset The address of the underlying asset to back 231 | * @param amount The amount to back 232 | * @param fee The amount paid in fees 233 | **/ 234 | function backUnbacked( 235 | address asset, 236 | uint256 amount, 237 | uint256 fee 238 | ) external; 239 | 240 | /** 241 | * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. 242 | * - E.g. User supplies 100 USDC and gets in return 100 aUSDC 243 | * @param asset The address of the underlying asset to supply 244 | * @param amount The amount to be supplied 245 | * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user 246 | * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens 247 | * is a different wallet 248 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 249 | * 0 if the action is executed directly by the user, without any middle-man 250 | **/ 251 | function supply( 252 | address asset, 253 | uint256 amount, 254 | address onBehalfOf, 255 | uint16 referralCode 256 | ) external; 257 | 258 | /** 259 | * @notice Supply with transfer approval of asset to be supplied done via permit function 260 | * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 261 | * @param asset The address of the underlying asset to supply 262 | * @param amount The amount to be supplied 263 | * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user 264 | * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens 265 | * is a different wallet 266 | * @param deadline The deadline timestamp that the permit is valid 267 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 268 | * 0 if the action is executed directly by the user, without any middle-man 269 | * @param permitV The V parameter of ERC712 permit sig 270 | * @param permitR The R parameter of ERC712 permit sig 271 | * @param permitS The S parameter of ERC712 permit sig 272 | **/ 273 | function supplyWithPermit( 274 | address asset, 275 | uint256 amount, 276 | address onBehalfOf, 277 | uint16 referralCode, 278 | uint256 deadline, 279 | uint8 permitV, 280 | bytes32 permitR, 281 | bytes32 permitS 282 | ) external; 283 | 284 | /** 285 | * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned 286 | * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC 287 | * @param asset The address of the underlying asset to withdraw 288 | * @param amount The underlying amount to be withdrawn 289 | * - Send the value type(uint256).max in order to withdraw the whole aToken balance 290 | * @param to The address that will receive the underlying, same as msg.sender if the user 291 | * wants to receive it on his own wallet, or a different address if the beneficiary is a 292 | * different wallet 293 | * @return The final amount withdrawn 294 | **/ 295 | function withdraw( 296 | address asset, 297 | uint256 amount, 298 | address to 299 | ) external returns (uint256); 300 | 301 | /** 302 | * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower 303 | * already supplied enough collateral, or he was given enough allowance by a credit delegator on the 304 | * corresponding debt token (StableDebtToken or VariableDebtToken) 305 | * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet 306 | * and 100 stable/variable debt tokens, depending on the `interestRateMode` 307 | * @param asset The address of the underlying asset to borrow 308 | * @param amount The amount to be borrowed 309 | * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable 310 | * @param referralCode The code used to register the integrator originating the operation, for potential rewards. 311 | * 0 if the action is executed directly by the user, without any middle-man 312 | * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself 313 | * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator 314 | * if he has been given credit delegation allowance 315 | **/ 316 | function borrow( 317 | address asset, 318 | uint256 amount, 319 | uint256 interestRateMode, 320 | uint16 referralCode, 321 | address onBehalfOf 322 | ) external; 323 | 324 | /** 325 | * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned 326 | * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address 327 | * @param asset The address of the borrowed underlying asset previously borrowed 328 | * @param amount The amount to repay 329 | * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` 330 | * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable 331 | * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the 332 | * user calling the function if he wants to reduce/remove his own debt, or the address of any other 333 | * other borrower whose debt should be removed 334 | * @return The final amount repaid 335 | **/ 336 | function repay( 337 | address asset, 338 | uint256 amount, 339 | uint256 interestRateMode, 340 | address onBehalfOf 341 | ) external returns (uint256); 342 | 343 | /** 344 | * @notice Repay with transfer approval of asset to be repaid done via permit function 345 | * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 346 | * @param asset The address of the borrowed underlying asset previously borrowed 347 | * @param amount The amount to repay 348 | * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` 349 | * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable 350 | * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the 351 | * user calling the function if he wants to reduce/remove his own debt, or the address of any other 352 | * other borrower whose debt should be removed 353 | * @param deadline The deadline timestamp that the permit is valid 354 | * @param permitV The V parameter of ERC712 permit sig 355 | * @param permitR The R parameter of ERC712 permit sig 356 | * @param permitS The S parameter of ERC712 permit sig 357 | * @return The final amount repaid 358 | **/ 359 | function repayWithPermit( 360 | address asset, 361 | uint256 amount, 362 | uint256 interestRateMode, 363 | address onBehalfOf, 364 | uint256 deadline, 365 | uint8 permitV, 366 | bytes32 permitR, 367 | bytes32 permitS 368 | ) external returns (uint256); 369 | 370 | /** 371 | * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the 372 | * equivalent debt tokens 373 | * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens 374 | * @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken 375 | * balance is not enough to cover the whole debt 376 | * @param asset The address of the borrowed underlying asset previously borrowed 377 | * @param amount The amount to repay 378 | * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` 379 | * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable 380 | * @return The final amount repaid 381 | **/ 382 | function repayWithATokens( 383 | address asset, 384 | uint256 amount, 385 | uint256 interestRateMode 386 | ) external returns (uint256); 387 | 388 | /** 389 | * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa 390 | * @param asset The address of the underlying asset borrowed 391 | * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable 392 | **/ 393 | function swapBorrowRateMode(address asset, uint256 interestRateMode) external; 394 | 395 | /** 396 | * @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. 397 | * - Users can be rebalanced if the following conditions are satisfied: 398 | * 1. Usage ratio is above 95% 399 | * 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too 400 | * much has been borrowed at a stable rate and suppliers are not earning enough 401 | * @param asset The address of the underlying asset borrowed 402 | * @param user The address of the user to be rebalanced 403 | **/ 404 | function rebalanceStableBorrowRate(address asset, address user) external; 405 | 406 | /** 407 | * @notice Allows suppliers to enable/disable a specific supplied asset as collateral 408 | * @param asset The address of the underlying asset supplied 409 | * @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise 410 | **/ 411 | function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; 412 | 413 | /** 414 | * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 415 | * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives 416 | * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk 417 | * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation 418 | * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation 419 | * @param user The address of the borrower getting liquidated 420 | * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover 421 | * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants 422 | * to receive the underlying collateral asset directly 423 | **/ 424 | function liquidationCall( 425 | address collateralAsset, 426 | address debtAsset, 427 | address user, 428 | uint256 debtToCover, 429 | bool receiveAToken 430 | ) external; 431 | 432 | /** 433 | * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, 434 | * as long as the amount taken plus a fee is returned. 435 | * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept 436 | * into consideration. For further details please visit https://developers.aave.com 437 | * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface 438 | * @param assets The addresses of the assets being flash-borrowed 439 | * @param amounts The amounts of the assets being flash-borrowed 440 | * @param interestRateModes Types of the debt to open if the flash loan is not returned: 441 | * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver 442 | * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address 443 | * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address 444 | * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 445 | * @param params Variadic packed params to pass to the receiver as extra information 446 | * @param referralCode The code used to register the integrator originating the operation, for potential rewards. 447 | * 0 if the action is executed directly by the user, without any middle-man 448 | **/ 449 | function flashLoan( 450 | address receiverAddress, 451 | address[] calldata assets, 452 | uint256[] calldata amounts, 453 | uint256[] calldata interestRateModes, 454 | address onBehalfOf, 455 | bytes calldata params, 456 | uint16 referralCode 457 | ) external; 458 | 459 | /** 460 | * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, 461 | * as long as the amount taken plus a fee is returned. 462 | * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept 463 | * into consideration. For further details please visit https://developers.aave.com 464 | * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface 465 | * @param asset The address of the asset being flash-borrowed 466 | * @param amount The amount of the asset being flash-borrowed 467 | * @param params Variadic packed params to pass to the receiver as extra information 468 | * @param referralCode The code used to register the integrator originating the operation, for potential rewards. 469 | * 0 if the action is executed directly by the user, without any middle-man 470 | **/ 471 | function flashLoanSimple( 472 | address receiverAddress, 473 | address asset, 474 | uint256 amount, 475 | bytes calldata params, 476 | uint16 referralCode 477 | ) external; 478 | 479 | /** 480 | * @notice Returns the user account data across all the reserves 481 | * @param user The address of the user 482 | * @return totalCollateralBase The total collateral of the user in the base currency used by the price feed 483 | * @return totalDebtBase The total debt of the user in the base currency used by the price feed 484 | * @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed 485 | * @return currentLiquidationThreshold The liquidation threshold of the user 486 | * @return ltv The loan to value of The user 487 | * @return healthFactor The current health factor of the user 488 | **/ 489 | function getUserAccountData(address user) 490 | external 491 | view 492 | returns ( 493 | uint256 totalCollateralBase, 494 | uint256 totalDebtBase, 495 | uint256 availableBorrowsBase, 496 | uint256 currentLiquidationThreshold, 497 | uint256 ltv, 498 | uint256 healthFactor 499 | ); 500 | 501 | /** 502 | * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an 503 | * interest rate strategy 504 | * @dev Only callable by the PoolConfigurator contract 505 | * @param asset The address of the underlying asset of the reserve 506 | * @param aTokenAddress The address of the aToken that will be assigned to the reserve 507 | * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve 508 | * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve 509 | * @param interestRateStrategyAddress The address of the interest rate strategy contract 510 | **/ 511 | function initReserve( 512 | address asset, 513 | address aTokenAddress, 514 | address stableDebtAddress, 515 | address variableDebtAddress, 516 | address interestRateStrategyAddress 517 | ) external; 518 | 519 | /** 520 | * @notice Drop a reserve 521 | * @dev Only callable by the PoolConfigurator contract 522 | * @param asset The address of the underlying asset of the reserve 523 | **/ 524 | function dropReserve(address asset) external; 525 | 526 | /** 527 | * @notice Updates the address of the interest rate strategy contract 528 | * @dev Only callable by the PoolConfigurator contract 529 | * @param asset The address of the underlying asset of the reserve 530 | * @param rateStrategyAddress The address of the interest rate strategy contract 531 | **/ 532 | function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress) 533 | external; 534 | 535 | /** 536 | * @notice Sets the configuration bitmap of the reserve as a whole 537 | * @dev Only callable by the PoolConfigurator contract 538 | * @param asset The address of the underlying asset of the reserve 539 | * @param configuration The new configuration bitmap 540 | **/ 541 | function setConfiguration(address asset, DataTypes.ReserveConfigurationMap calldata configuration) 542 | external; 543 | 544 | /** 545 | * @notice Returns the configuration of the reserve 546 | * @param asset The address of the underlying asset of the reserve 547 | * @return The configuration of the reserve 548 | **/ 549 | function getConfiguration(address asset) 550 | external 551 | view 552 | returns (DataTypes.ReserveConfigurationMap memory); 553 | 554 | /** 555 | * @notice Returns the configuration of the user across all the reserves 556 | * @param user The user address 557 | * @return The configuration of the user 558 | **/ 559 | function getUserConfiguration(address user) 560 | external 561 | view 562 | returns (DataTypes.UserConfigurationMap memory); 563 | 564 | /** 565 | * @notice Returns the normalized income normalized income of the reserve 566 | * @param asset The address of the underlying asset of the reserve 567 | * @return The reserve's normalized income 568 | */ 569 | function getReserveNormalizedIncome(address asset) external view returns (uint256); 570 | 571 | /** 572 | * @notice Returns the normalized variable debt per unit of asset 573 | * @param asset The address of the underlying asset of the reserve 574 | * @return The reserve normalized variable debt 575 | */ 576 | function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); 577 | 578 | /** 579 | * @notice Returns the state and configuration of the reserve 580 | * @param asset The address of the underlying asset of the reserve 581 | * @return The state and configuration data of the reserve 582 | **/ 583 | function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); 584 | 585 | /** 586 | * @notice Validates and finalizes an aToken transfer 587 | * @dev Only callable by the overlying aToken of the `asset` 588 | * @param asset The address of the underlying asset of the aToken 589 | * @param from The user from which the aTokens are transferred 590 | * @param to The user receiving the aTokens 591 | * @param amount The amount being transferred/withdrawn 592 | * @param balanceFromBefore The aToken balance of the `from` user before the transfer 593 | * @param balanceToBefore The aToken balance of the `to` user before the transfer 594 | */ 595 | function finalizeTransfer( 596 | address asset, 597 | address from, 598 | address to, 599 | uint256 amount, 600 | uint256 balanceFromBefore, 601 | uint256 balanceToBefore 602 | ) external; 603 | 604 | /** 605 | * @notice Returns the list of the underlying assets of all the initialized reserves 606 | * @dev It does not include dropped reserves 607 | * @return The addresses of the underlying assets of the initialized reserves 608 | **/ 609 | function getReservesList() external view returns (address[] memory); 610 | 611 | /** 612 | * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct 613 | * @param id The id of the reserve as stored in the DataTypes.ReserveData struct 614 | * @return The address of the reserve associated with id 615 | **/ 616 | function getReserveAddressById(uint16 id) external view returns (address); 617 | 618 | /** 619 | * @notice Returns the PoolAddressesProvider connected to this contract 620 | * @return The address of the PoolAddressesProvider 621 | **/ 622 | function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); 623 | 624 | /** 625 | * @notice Updates the protocol fee on the bridging 626 | * @param bridgeProtocolFee The part of the premium sent to the protocol treasury 627 | */ 628 | function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external; 629 | 630 | /** 631 | * @notice Updates flash loan premiums. Flash loan premium consists of two parts: 632 | * - A part is sent to aToken holders as extra, one time accumulated interest 633 | * - A part is collected by the protocol treasury 634 | * @dev The total premium is calculated on the total borrowed amount 635 | * @dev The premium to protocol is calculated on the total premium, being a percentage of `flashLoanPremiumTotal` 636 | * @dev Only callable by the PoolConfigurator contract 637 | * @param flashLoanPremiumTotal The total premium, expressed in bps 638 | * @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, expressed in bps 639 | */ 640 | function updateFlashloanPremiums( 641 | uint128 flashLoanPremiumTotal, 642 | uint128 flashLoanPremiumToProtocol 643 | ) external; 644 | 645 | /** 646 | * @notice Configures a new category for the eMode. 647 | * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category. 648 | * The category 0 is reserved as it's the default for volatile assets 649 | * @param id The id of the category 650 | * @param config The configuration of the category 651 | */ 652 | function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external; 653 | 654 | /** 655 | * @notice Returns the data of an eMode category 656 | * @param id The id of the category 657 | * @return The configuration data of the category 658 | */ 659 | function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory); 660 | 661 | /** 662 | * @notice Allows a user to use the protocol in eMode 663 | * @param categoryId The id of the category 664 | */ 665 | function setUserEMode(uint8 categoryId) external; 666 | 667 | /** 668 | * @notice Returns the eMode the user is using 669 | * @param user The address of the user 670 | * @return The eMode id 671 | */ 672 | function getUserEMode(address user) external view returns (uint256); 673 | 674 | /** 675 | * @notice Resets the isolation mode total debt of the given asset to zero 676 | * @dev It requires the given asset has zero debt ceiling 677 | * @param asset The address of the underlying asset to reset the isolationModeTotalDebt 678 | */ 679 | function resetIsolationModeTotalDebt(address asset) external; 680 | 681 | /** 682 | * @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate 683 | * @return The percentage of available liquidity to borrow, expressed in bps 684 | */ 685 | function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() external view returns (uint256); 686 | 687 | /** 688 | * @notice Returns the total fee on flash loans 689 | * @return The total fee on flashloans 690 | */ 691 | function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128); 692 | 693 | /** 694 | * @notice Returns the part of the bridge fees sent to protocol 695 | * @return The bridge fee sent to the protocol treasury 696 | */ 697 | function BRIDGE_PROTOCOL_FEE() external view returns (uint256); 698 | 699 | /** 700 | * @notice Returns the part of the flashloan fees sent to protocol 701 | * @return The flashloan fee sent to the protocol treasury 702 | */ 703 | function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128); 704 | 705 | /** 706 | * @notice Returns the maximum number of reserves supported to be listed in this Pool 707 | * @return The maximum number of reserves supported 708 | */ 709 | function MAX_NUMBER_RESERVES() external view returns (uint16); 710 | 711 | /** 712 | * @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens 713 | * @param assets The list of reserves for which the minting needs to be executed 714 | **/ 715 | function mintToTreasury(address[] calldata assets) external; 716 | 717 | /** 718 | * @notice Rescue and transfer tokens locked in this contract 719 | * @param token The address of the token 720 | * @param to The address of the recipient 721 | * @param amount The amount of token to transfer 722 | */ 723 | function rescueTokens( 724 | address token, 725 | address to, 726 | uint256 amount 727 | ) external; 728 | 729 | /** 730 | * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. 731 | * - E.g. User supplies 100 USDC and gets in return 100 aUSDC 732 | * @dev Deprecated: Use the `supply` function instead 733 | * @param asset The address of the underlying asset to supply 734 | * @param amount The amount to be supplied 735 | * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user 736 | * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens 737 | * is a different wallet 738 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 739 | * 0 if the action is executed directly by the user, without any middle-man 740 | **/ 741 | function deposit( 742 | address asset, 743 | uint256 amount, 744 | address onBehalfOf, 745 | uint16 referralCode 746 | ) external; 747 | } --------------------------------------------------------------------------------