├── .gitattributes ├── .vscode └── extensions.json ├── prettier.config.cjs ├── requirements.txt ├── .gitignore ├── brownie-config.yaml ├── default.nix ├── contracts ├── IUniswapV2Factory.sol ├── IUniswapV2Pair.sol ├── flashloans │ ├── aave │ │ ├── protocol │ │ │ └── libraries │ │ │ │ └── types │ │ │ │ └── DataTypes.sol │ │ └── interfaces │ │ │ ├── ILendingPoolAddressesProvider.sol │ │ │ └── ILendingPool.sol │ └── AaveFlashloanMultiRouter.sol └── IUniswapV2Router.sol ├── foundry.toml ├── package.json ├── .github └── workflows │ └── brownie.yml ├── scripts ├── sandwich-test1.py ├── pair-finder.py └── backrun_test1.py ├── README.md ├── justfile ├── missing-pairs.txt └── LICENSE.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | *.vy linguist-language=Python 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["nomicfoundation.hardhat-solidity", "znck.grammarly"] 3 | } 4 | -------------------------------------------------------------------------------- /prettier.config.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const prettierConfig = require('prettier-config-solidity'); 3 | module.exports = prettierConfig; 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | black==22.1.0 3 | eth-brownie == 1.18.1 4 | flake8==3.7.9 5 | isort==4.3.21 6 | pre-commit==2.4.0 7 | tox==3.15.1 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /out 2 | /cache 3 | /artifacts 4 | .DS_Store 5 | node_modules 6 | __pycache__ 7 | .env 8 | .history 9 | .hypothesis/ 10 | build/ 11 | reports/ 12 | -------------------------------------------------------------------------------- /brownie-config.yaml: -------------------------------------------------------------------------------- 1 | # automatically fetch contract sources from Etherscan 2 | autofetch_sources: True 3 | 4 | # require OpenZepplin Contracts v3.0.0 5 | dependencies: 6 | - OpenZeppelin/openzeppelin-contracts@4.3.2 7 | 8 | # path remapping to support OpenZepplin imports with NPM-style path 9 | compiler: 10 | solc: 11 | remappings: 12 | - '@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.3.2' 13 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | let 2 | mach-nix = import (builtins.fetchGit { 3 | url = "https://github.com/DavHau/mach-nix"; 4 | ref = "refs/tags/3.4.0"; 5 | }) { 6 | python = "python310"; 7 | pypiDataRev = "ff8a7c89a967ed480864d47b090d373f240421a4"; 8 | pypiDataSha256 = "0qz7hsld0x8lviyzszpq3i29zchwa8nassdna5ccyhl5xh6zkcvi"; 9 | }; 10 | in 11 | mach-nix.mkPythonShell { 12 | requirements = builtins.readFile ./requirements.txt; 13 | } -------------------------------------------------------------------------------- /contracts/IUniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MPL-2.0 2 | // Creator: Manifold Finance 3 | // PackageName: @securerpc/simulate-bundle 4 | // PackageOriginator: ManifoldFinance 5 | // PackageHomePage: https://github.com/manifoldfinance/securerpc-simulate-bundle 6 | 7 | pragma solidity >=0.8.0 <0.9.0; 8 | 9 | interface IUniswapV2Factory { 10 | function allPairsLength() external view returns (uint256); 11 | 12 | function allPairs(uint256 i) external view returns (address); 13 | 14 | function getPair(address token0, address token1) external view returns (address); 15 | } 16 | -------------------------------------------------------------------------------- /contracts/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MPL-2.0 2 | // Creator: Manifold Finance 3 | // PackageName: @securerpc/simulate-bundle 4 | // PackageOriginator: ManifoldFinance 5 | // PackageHomePage: https://github.com/manifoldfinance/securerpc-simulate-bundle 6 | 7 | pragma solidity >=0.8.0 <0.9.0; 8 | 9 | import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 10 | 11 | interface IUniswapV2Pair is IERC20Metadata { 12 | function factory() external view returns (address); 13 | 14 | function token0() external view returns (address); 15 | 16 | function token1() external view returns (address); 17 | 18 | function getReserves() 19 | external 20 | view 21 | returns ( 22 | uint112, 23 | uint112, 24 | uint32 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | auto_detect_solc = true 3 | block_base_fee_per_gas = 0 4 | block_coinbase = '0x0000000000000000000000000000000000000000' 5 | block_difficulty = 0 6 | block_number = 1 7 | block_timestamp = 1 8 | bytecode_hash = 'none' 9 | cache = true 10 | cache_path = 'cache' 11 | evm_version = 'london' 12 | extra_output = [] 13 | extra_output_files = [] 14 | ffi = false 15 | force = true 16 | fuzz_max_global_rejects = 65536 17 | fuzz_max_local_rejects = 1024 18 | fuzz_runs = 1024 19 | gas_limit = 9223372036854775807 20 | gas_price = 0 21 | gas_reports = ['*'] 22 | ignored_error_codes = [1878] 23 | initial_balance = '0xffffffffffffffffffffffff' 24 | libraries = [] 25 | libs = ['node_modules'] 26 | memory_limit = 33554432 27 | names = false 28 | no_storage_caching = false 29 | offline = false 30 | optimizer = true 31 | optimizer_runs = 200 32 | out = 'out' 33 | remappings = ['@openzeppelin/=node_modules/@openzeppelin/'] 34 | sender = '0x00a329c0648769a73afac7f9381e08fb43dbea72' 35 | sizes = false 36 | sparse_mode = false 37 | src = 'contracts' 38 | test = 'test' 39 | tx_origin = '0x00a329c0648769a73afac7f9381e08fb43dbea72' 40 | verbosity = 4 41 | via_ir = false 42 | 43 | [default.rpc_storage_caching] 44 | chains = 'all' 45 | endpoints = 'all' 46 | 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@manifoldfinance/bundle-simulator", 3 | "version": "0.1.0", 4 | "description": "Standalone repo for simulating specific bundles that need debugging.", 5 | "files": [ 6 | "/dist/**/*", 7 | "/contracts", 8 | "/contracts/base", 9 | "/contracts/interfaces", 10 | "/contracts/libraries", 11 | "/artifacts/contracts/**/*.json", 12 | "!artifacts/contracts/**/*.dbg.json", 13 | "!artifacts/contracts/test/**/*", 14 | "!artifacts/contracts/base/**/*" 15 | ], 16 | "scripts": { 17 | "fmt": "npx prettier --config prettier.config.cjs --write contracts/" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/manifoldfinance/bundle-simulator.git" 22 | }, 23 | "keywords": [], 24 | "author": "SEE CONTRIBUTORS", 25 | "license": "MPL-2.0", 26 | "bugs": { 27 | "url": "https://github.com/manifoldfinance/bundle-simulator/issues" 28 | }, 29 | "homepage": "https://github.com/manifoldfinance/bundle-simulator#readme", 30 | "devDependencies": { 31 | "prettier": "^2.6.2", 32 | "prettier-config-solidity": "^1.7.0", 33 | "prettier-plugin-solidity": "^1.0.0-beta.19" 34 | }, 35 | "dependencies": { 36 | "@openzeppelin/contracts": "^4.6.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/brownie.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths: 4 | - 'tests/**/*.py' 5 | - 'contracts/**/*.sol' 6 | 7 | name: Brownie tests 8 | 9 | env: 10 | ETHERSCAN_TOKEN: ${{ secrets.ETHERSCAN_TOKEN }} 11 | ETHERSCAN_API: ${{ secrets.ETHERSCAN_API }} 12 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 13 | WEB3_INFURA_PROJECT_ID: ${{ secrets.WEB3_INFURA_PROJECT_ID }} 14 | ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }} 15 | 16 | # increasing available memory for node reduces issues with ganache crashing 17 | # https://nodejs.org/api/cli.html#cli_max_old_space_size_size_in_megabytes 18 | NODE_OPTIONS: --max_old_space_size=4096 19 | 20 | jobs: 21 | tests: 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - uses: actions/checkout@v3 26 | with: 27 | submodules: recursive 28 | 29 | - name: Cache Compiler Installations 30 | uses: actions/cache@v3 31 | with: 32 | path: | 33 | ~/.solcx 34 | ~/.vvm 35 | key: compiler-cache 36 | 37 | - name: Setup Node.js 38 | uses: actions/setup-node@v3 39 | 40 | # - name: Setup Node.js 41 | # run: yarn install 42 | 43 | - name: Install Ganache 44 | run: npm install -g ganache-cli@6.12.2 45 | 46 | - name: Setup Python 3.9 47 | uses: actions/setup-python@v3 48 | with: 49 | python-version: 3.9 50 | cache: 'pip' 51 | 52 | - name: Install Requirements 53 | run: pip install -r requirements.txt 54 | 55 | - name: Configure test state 56 | run: brownie networks add development mainnet-fork1 cmd="ganache-cli" host=http://127.0.0.1 fork="$ETH_RPC_URL@14161345" accounts=10 mnemonic=brownie port=8545 timeout=100 57 | 58 | - name: Run Tests 59 | run: brownie test --network mainnet-fork1 60 | -------------------------------------------------------------------------------- /contracts/flashloans/aave/protocol/libraries/types/DataTypes.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MPL-2.0 2 | // Creator: Manifold Finance 3 | // PackageName: @securerpc/simulate-bundle 4 | // PackageOriginator: ManifoldFinance 5 | // PackageHomePage: https://github.com/manifoldfinance/securerpc-simulate-bundle 6 | 7 | pragma solidity >=0.8.0 <0.9.0; 8 | 9 | library DataTypes { 10 | // refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties. 11 | struct ReserveData { 12 | //stores the reserve configuration 13 | ReserveConfigurationMap configuration; 14 | //the liquidity index. Expressed in ray 15 | uint128 liquidityIndex; 16 | //variable borrow index. Expressed in ray 17 | uint128 variableBorrowIndex; 18 | //the current supply rate. Expressed in ray 19 | uint128 currentLiquidityRate; 20 | //the current variable borrow rate. Expressed in ray 21 | uint128 currentVariableBorrowRate; 22 | //the current stable borrow rate. Expressed in ray 23 | uint128 currentStableBorrowRate; 24 | uint40 lastUpdateTimestamp; 25 | //tokens addresses 26 | address aTokenAddress; 27 | address stableDebtTokenAddress; 28 | address variableDebtTokenAddress; 29 | //address of the interest rate strategy 30 | address interestRateStrategyAddress; 31 | //the id of the reserve. Represents the position in the list of the active reserves 32 | uint8 id; 33 | } 34 | 35 | struct ReserveConfigurationMap { 36 | //bit 0-15: LTV 37 | //bit 16-31: Liq. threshold 38 | //bit 32-47: Liq. bonus 39 | //bit 48-55: Decimals 40 | //bit 56: Reserve is active 41 | //bit 57: reserve is frozen 42 | //bit 58: borrowing is enabled 43 | //bit 59: stable rate borrowing enabled 44 | //bit 60-63: reserved 45 | //bit 64-79: reserve factor 46 | uint256 data; 47 | } 48 | 49 | struct UserConfigurationMap { 50 | uint256 data; 51 | } 52 | 53 | enum InterestRateMode { 54 | NONE, 55 | STABLE, 56 | VARIABLE 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /scripts/sandwich-test1.py: -------------------------------------------------------------------------------- 1 | from brownie import Contract, web3, accounts 2 | import requests 3 | import json 4 | import eth_abi 5 | 6 | ICE_ADDRESS = web3.toChecksumAddress("0xf16e81dce15B08F326220742020379B855B87DF9") 7 | WETH_ADDRESS = web3.toChecksumAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") 8 | # UNI_ROUTER = web3.toChecksumAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D") 9 | SUSHI_ROUTER = web3.toChecksumAddress("0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F") 10 | 11 | API_KEY = "ME321ZX4FED2Y4ENII3UYH46PZ51GW8TP6" 12 | 13 | def getABI(contract_address): 14 | url_eth = "https://api.etherscan.io/api" 15 | API_ENDPOINT = url_eth + \ 16 | "?module=contract&action=getabi&address="+str(contract_address)+"&apikey="+API_KEY 17 | r = requests.get(url=API_ENDPOINT) 18 | response = r.json() 19 | return json.loads(response["result"]) 20 | 21 | def main(): 22 | # get USDT contract 23 | 24 | ICE = Contract.from_abi("ICE", ICE_ADDRESS, getABI(ICE_ADDRESS)) 25 | WETH = Contract.from_abi("WETH", WETH_ADDRESS, getABI(WETH_ADDRESS)) 26 | 27 | # router = SUSHI_ROUTER 28 | amountIn = 1051723000000000000 29 | deadline = 16666484022323 30 | path = [WETH_ADDRESS, ICE_ADDRESS] 31 | router = Contract.from_abi("SUSHI_ROUTER", SUSHI_ROUTER, getABI(SUSHI_ROUTER)) 32 | 33 | WETH.deposit({"from": accounts[0], "value": amountIn}) 34 | WETH.approve(SUSHI_ROUTER, amountIn, {"from": accounts[0]}) 35 | tx = router.swapExactTokensForTokens(amountIn, 0, path, accounts[0], deadline, {"from":accounts[0]}) 36 | 37 | abiEncoded = eth_abi.encode_abi(['uint256','uint256', 'address[]', 'address', 'uint256'], [amountIn, 0, path, accounts[0].address, deadline]) 38 | funcSelector = 'swapExactTokensForTokens(uint256,uint256,address[],address,uint256)' 39 | callHash = web3.sha3(text=funcSelector) 40 | callHashAbr = callHash[0:4].hex() 41 | encodedCall = callHashAbr + abiEncoded.hex() 42 | 43 | # print('encodedCall = ',encodedCall) 44 | # web3.eth.send_transaction({ 45 | # 'to': SUSHI_ROUTER, 46 | # 'from': accounts[0].address, 47 | # 'value': 0, 48 | # 'gas': 200000, 49 | # 'maxFeePerGas': web3.toWei(250, 'gwei'), 50 | # 'maxPriorityFeePerGas': web3.toWei(2, 'gwei'), 51 | # 'data': encodedCall 52 | # }) 53 | -------------------------------------------------------------------------------- /contracts/flashloans/aave/interfaces/ILendingPoolAddressesProvider.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MPL-2.0 2 | // Creator: Manifold Finance 3 | // PackageName: @securerpc/simulate-bundle 4 | // PackageOriginator: ManifoldFinance 5 | // PackageHomePage: https://github.com/manifoldfinance/securerpc-simulate-bundle 6 | 7 | pragma solidity >=0.8.0 <0.9.0; 8 | 9 | /** 10 | * @title LendingPoolAddressesProvider contract 11 | * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles 12 | * - Acting also as factory of proxies and admin of those, so with right to change its implementations 13 | * - Owned by the Aave Governance 14 | * @author Aave 15 | **/ 16 | interface ILendingPoolAddressesProvider { 17 | event LendingPoolUpdated(address indexed newAddress); 18 | event ConfigurationAdminUpdated(address indexed newAddress); 19 | event EmergencyAdminUpdated(address indexed newAddress); 20 | event LendingPoolConfiguratorUpdated(address indexed newAddress); 21 | event LendingPoolCollateralManagerUpdated(address indexed newAddress); 22 | event PriceOracleUpdated(address indexed newAddress); 23 | event LendingRateOracleUpdated(address indexed newAddress); 24 | event ProxyCreated(bytes32 id, address indexed newAddress); 25 | event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy); 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 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bundle Simulator 2 | 3 | Standalone repo for simulating specific bundles that need debugging. 4 | 5 | ## Requirements 6 | 7 | Have installed the following: 8 | 9 | - Nix (or Brownie directly) 10 | - ganache-cli (npm install ganache-cli) 11 | 12 | ## Use Brownie 13 | 14 | Just issue the following command: 15 | 16 | ```sh 17 | nix-shell 18 | ``` 19 | 20 | After a couple of minutes you should be inside of `nix-shell` with brownie in our `PATH`. We can quickly double check with: 21 | 22 | ```sh 23 | which brownie 24 | ``` 25 | 26 | ## Run simulations 27 | 28 | Use `scripts/backrun_test1.py` as a template to construct bundle specifics. Note also the target block number for the bundle. 29 | 30 | ### Create a fork 31 | 32 | By default brownie includes a list of providers that can be checked with: 33 | 34 | ```sh 35 | brownie networks list 36 | ``` 37 | 38 | Create a fork at a specific block for the bundle. Note that the fork will need to occur at target block number - 1. 39 | 40 | ```sh 41 | brownie networks add development backrun1 cmd="ganache-cli" host=http://127.0.0.1 fork="$ETH_RPC_URL@14430476" accounts=10 mnemonic=brownie port=8545 timeout=100 42 | ``` 43 | 44 | ### Run script 45 | 46 | ```sh 47 | brownie run backrun_test1.py --network backrun1 48 | ``` 49 | 50 | Result: 51 | 52 | ```python 53 | Running 'scripts/backrun_test1.py::main'... 54 | 55 | Deploy flashloan contract 56 | Transaction sent: 0xf4223827831aea7b60c3169ebf1191c22a84cd104708ec050e6da07e36a06fac 57 | Gas price: 0.0 gwei Gas limit: 6721975 Nonce: 34 58 | AaveFlashloanMultiRouter.constructor confirmed Block: 14430478 Gas used: 1930680 (28.72%) 59 | AaveFlashloanMultiRouter deployed at: 0xa54A0c47330a78E2C1abcD22BB477Dc760fC77b5 60 | 61 | Approving User swap 62 | Transaction sent: 0x04cc7d99ed3fd237f535960f9cc2a52135e5d0a1bd8b5bde295f9dccd86a7e70 63 | Gas price: 0.0 gwei Gas limit: 6721975 Nonce: 19 64 | Transaction confirmed Block: 14430479 Gas used: 30103 (0.45%) 65 | 66 | User swap 67 | Transaction sent: 0x5399fef87774f51195ebaf854e9fd75b5ec1a71eeb73c14a7a2a56a22b88b975 68 | Gas price: 0.0 gwei Gas limit: 6721975 Nonce: 20 69 | Transaction confirmed Block: 14430480 Gas used: 156025 (2.32%) 70 | 71 | Backrun arb 72 | Platform pre-arb weth balance: 1113136168719190148 73 | Transaction sent: 0x97ce6a340493a7332cfb7ca395e022c5bc7d8acbc9d334661d60ceba4d76d440 74 | Gas price: 0.0 gwei Gas limit: 6721975 Nonce: 35 75 | AaveFlashloanMultiRouter.call confirmed Block: 14430481 Gas used: 443855 (6.60%) 76 | 77 | Platform post-arb weth balance: 1160664762353910714 78 | ``` 79 | 80 | ### Debugging 81 | 82 | [See Brownie docs for info on tx tracing](https://eth-brownie.readthedocs.io/en/stable/core-transactions.html) 83 | -------------------------------------------------------------------------------- /contracts/IUniswapV2Router.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MPL-2.0 2 | // Creator: Manifold Finance 3 | // PackageName: @securerpc/simulate-bundle 4 | // PackageOriginator: ManifoldFinance 5 | // PackageHomePage: https://github.com/manifoldfinance/securerpc-simulate-bundle 6 | 7 | pragma solidity >=0.8.0 <0.9.0; 8 | 9 | interface IUniswapV2Router01 { 10 | function swapExactTokensForTokens( 11 | uint256 amountIn, 12 | uint256 amountOutMin, 13 | address[] calldata path, 14 | address to, 15 | uint256 deadline 16 | ) external returns (uint256[] memory amounts); 17 | 18 | function swapTokensForExactTokens( 19 | uint256 amountOut, 20 | uint256 amountInMax, 21 | address[] calldata path, 22 | address to, 23 | uint256 deadline 24 | ) external returns (uint256[] memory amounts); 25 | 26 | function swapExactETHForTokens( 27 | uint256 amountOutMin, 28 | address[] calldata path, 29 | address to, 30 | uint256 deadline 31 | ) external payable returns (uint256[] memory amounts); 32 | 33 | function swapTokensForExactETH( 34 | uint256 amountOut, 35 | uint256 amountInMax, 36 | address[] calldata path, 37 | address to, 38 | uint256 deadline 39 | ) external returns (uint256[] memory amounts); 40 | 41 | function swapExactTokensForETH( 42 | uint256 amountIn, 43 | uint256 amountOutMin, 44 | address[] calldata path, 45 | address to, 46 | uint256 deadline 47 | ) external returns (uint256[] memory amounts); 48 | 49 | function swapETHForExactTokens( 50 | uint256 amountOut, 51 | address[] calldata path, 52 | address to, 53 | uint256 deadline 54 | ) external payable returns (uint256[] memory amounts); 55 | } 56 | 57 | // Taken from https://github.com/sushiswap/sushiswap/blob/master/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol 58 | interface IUniswapV2Router02 is IUniswapV2Router01 { 59 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 60 | uint256 amountIn, 61 | uint256 amountOutMin, 62 | address[] calldata path, 63 | address to, 64 | uint256 deadline 65 | ) external; 66 | 67 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 68 | uint256 amountOutMin, 69 | address[] calldata path, 70 | address to, 71 | uint256 deadline 72 | ) external payable; 73 | 74 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 75 | uint256 amountIn, 76 | uint256 amountOutMin, 77 | address[] calldata path, 78 | address to, 79 | uint256 deadline 80 | ) external; 81 | } 82 | -------------------------------------------------------------------------------- /scripts/pair-finder.py: -------------------------------------------------------------------------------- 1 | from brownie import Contract, web3, accounts 2 | import requests 3 | import json 4 | import eth_abi 5 | from ast import literal_eval 6 | import pprint 7 | # WETH_ADDRESS = web3.toChecksumAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") 8 | # UNI_ROUTER = web3.toChecksumAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D") 9 | UNI_FACTORY = web3.toChecksumAddress("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f") 10 | # SUSHI_ROUTER = web3.toChecksumAddress("0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F") 11 | SUSHI_FACTORY = web3.toChecksumAddress("0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac") 12 | 13 | API_KEY = "ME321ZX4FED2Y4ENII3UYH46PZ51GW8TP6" 14 | 15 | def getABI(contract_address): 16 | url_eth = "https://api.etherscan.io/api" 17 | API_ENDPOINT = url_eth + \ 18 | "?module=contract&action=getabi&address="+str(contract_address)+"&apikey="+API_KEY 19 | r = requests.get(url=API_ENDPOINT) 20 | response = r.json() 21 | return json.loads(response["result"]) 22 | 23 | def main(): 24 | # WETH = Contract.from_abi("WETH", WETH_ADDRESS, getABI(WETH_ADDRESS)) 25 | 26 | sushi_factory = Contract.from_abi("SUSHI_FACTORY", SUSHI_FACTORY, getABI(SUSHI_FACTORY)) 27 | uni_factory = Contract.from_abi("UNI_FACTORY", UNI_FACTORY, getABI(UNI_FACTORY)) 28 | 29 | # Using readlines() 30 | file1 = open('missing-pairs.txt', 'r') 31 | Lines = file1.readlines() 32 | 33 | count = 0 34 | # Strips the newline character 35 | pairs = {} 36 | for line in Lines: 37 | count += 1 38 | path = literal_eval(line.strip()) 39 | # print("{} ({})".format(path, type(path))) 40 | pathLen = len(path) 41 | 42 | for i in range(0,pathLen-1): 43 | uni_pair = uni_factory.getPair(path[i],path[i+1]) 44 | if uni_pair != "0x0000000000000000000000000000000000000000": 45 | if uni_pair in pairs.keys(): 46 | pairs[uni_pair] = pairs[uni_pair] + 1 47 | else: 48 | pairs[uni_pair] = 1 49 | print("Uni pair for missing path [{}, {}] = {}".format(path[i],path[i+1],uni_pair)) 50 | sushi_pair = sushi_factory.getPair(path[i],path[i+1]) 51 | if sushi_pair != "0x0000000000000000000000000000000000000000": 52 | if sushi_pair in pairs.keys(): 53 | pairs[sushi_pair] = pairs[sushi_pair] + 1 54 | else: 55 | pairs[sushi_pair] = 1 56 | print("Sushi pair for missing path [{}, {}] = {}".format(path[i],path[i+1], sushi_pair)) 57 | 58 | pairs_sorted = sorted(pairs.items(), key=lambda d: d[1], reverse=True) 59 | print("Sorted pairs by frequency") 60 | pprint.pprint(pairs_sorted) 61 | 62 | 63 | -------------------------------------------------------------------------------- /scripts/backrun_test1.py: -------------------------------------------------------------------------------- 1 | # brownie networks add development backrun1 cmd="ganache-cli" host=http://127.0.0.1 fork="$ETH_RPC_URL@14430476" accounts=10 mnemonic=brownie port=8545 timeout=100 2 | # brownie run backrun_test1.py --network backrun1 3 | 4 | from brownie import Contract, web3, accounts, AaveFlashloanMultiRouter 5 | import requests 6 | import json 7 | import eth_abi 8 | 9 | OCEAN_ADDRESS = web3.toChecksumAddress("0x967da4048cD07aB37855c090aAF366e4ce1b9F48") 10 | USDC_ADDRESS = web3.toChecksumAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") 11 | WETH_ADDRESS = web3.toChecksumAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") 12 | UNI_ROUTER = web3.toChecksumAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D") 13 | SUSHI_ROUTER = web3.toChecksumAddress("0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F") 14 | 15 | API_KEY = "ME321ZX4FED2Y4ENII3UYH46PZ51GW8TP6" 16 | 17 | def getABI(contract_address): 18 | url_eth = "https://api.etherscan.io/api" 19 | API_ENDPOINT = url_eth + \ 20 | "?module=contract&action=getabi&address="+str(contract_address)+"&apikey="+API_KEY 21 | r = requests.get(url=API_ENDPOINT) 22 | response = r.json() 23 | return json.loads(response["result"]) 24 | 25 | def main(): 26 | # get USDT contract 27 | 28 | USDC = Contract.from_abi("USDC", USDC_ADDRESS, getABI(USDC_ADDRESS)) 29 | OCEAN = Contract.from_abi("OCEAN", OCEAN_ADDRESS, getABI(OCEAN_ADDRESS)) 30 | WETH = Contract.from_abi("WETH", WETH_ADDRESS, getABI(WETH_ADDRESS)) 31 | 32 | platformAccount = accounts.at('0x4F680254517617C175e223b37C8e40c473623647', force=True) 33 | 34 | # deploy flashloan contract 35 | # print("Deploy flashloan contract") 36 | # flashloanContract = AaveFlashloanMultiRouter.deploy([platformAccount.address],[platformAccount.address], {"from": platformAccount}) 37 | flashloanContractAbi = json.load(open('build/contracts/AaveFlashloanMultiRouter.json'))["abi"] 38 | flashloanContract = Contract.from_abi("FlashLoan","0x98b8957bc3EC8f7267Ac6F41Bc381966Ed22E4Af",flashloanContractAbi) 39 | 40 | # router = SUSHI_ROUTER 41 | amountIn = 8750000000000000000000 42 | amountOutMin = 5255123152 43 | deadline = 16666484022323 44 | path = [OCEAN_ADDRESS, WETH_ADDRESS, USDC_ADDRESS] 45 | router = Contract.from_abi("SUSHI_ROUTER", SUSHI_ROUTER, getABI(SUSHI_ROUTER)) 46 | router2 = Contract.from_abi("UNI_ROUTER", UNI_ROUTER, getABI(UNI_ROUTER)) 47 | 48 | userAccount = accounts.at('0x03a1dd908b7e17ac8b478c5064b549d4267768e1', force=True) 49 | # WETH.deposit({"from": accounts[0], "value": amountIn}) 50 | print('Approving swap') 51 | OCEAN.approve(SUSHI_ROUTER, amountIn, {"from": userAccount}) 52 | print('User swap') 53 | router.swapExactTokensForTokens(amountIn, amountOutMin, path, userAccount, deadline, {"from":userAccount}) 54 | 55 | # decoded input data for AaveMultiRouter 56 | routers = [SUSHI_ROUTER, UNI_ROUTER] 57 | path = [WETH_ADDRESS, OCEAN_ADDRESS, WETH_ADDRESS] 58 | amountIn = 1778282479425584991 59 | deadline = 1647876165 60 | 61 | print('Backrun arb') 62 | print('Platform pre-arb weth balance: ', WETH.balanceOf(platformAccount, {"from": platformAccount})) 63 | flashloanContract.call(routers, path, amountIn, deadline, {"from": platformAccount}) 64 | print('Platform post-arb weth balance: ', WETH.balanceOf(platformAccount, {"from": platformAccount})) 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env just --justfile 2 | # @title Foundry Justfile 3 | # @version: 0.4.2 4 | # @license Apache-2.0 OR MIT 5 | # @see {@link https://github.com/sambacha/foundry-scripts} 6 | 7 | bt := '0' 8 | export RUST_BACKTRACE := bt 9 | et := 'ethers=trace' 10 | export RUST_LOG := et 11 | log := "warn" 12 | export JUST_LOG := log 13 | 14 | _default: 15 | just --list 16 | 17 | tl: 18 | forge test --list 19 | 20 | sl: 21 | forge snapshot --list 22 | 23 | dumpbuild: 24 | ETHERS_SOLC_LOG=in=in.json,out=out.json; forge build --force 25 | 26 | # load .env file 27 | 28 | set dotenv-load := true 29 | 30 | # pass justfile recipe args as positional arguments to commands 31 | 32 | set positional-arguments := true 33 | 34 | # sourced from https://github.com/sense-finance/sense-v1 35 | 36 | DAPP_BUILD_OPTIMIZE := "1" 37 | DAPP_COVERAGE := "1" 38 | DAPP_TEST_FUZZ_RUNS := "100" 39 | 40 | # 1e18 decimals 41 | 42 | HEX_18 := "0x0000000000000000000000000000000000000000000000000000000000000012" 43 | HEX_12 := "0x000000000000000000000000000000000000000000000000000000000000000c" 44 | HEX_8 := "0x0000000000000000000000000000000000000000000000000000000000000008" 45 | HEX_6 := "0x0000000000000000000000000000000000000000000000000000000000000006" 46 | 47 | # set mock target to 18 decimals by default 48 | 49 | FORGE_MOCK_TARGET_DECIMALS := env_var_or_default("FORGE_MOCK_TARGET_DECIMALS", HEX_18) 50 | FORGE_MOCK_UNDERLYING_DECIMALS := env_var_or_default("FORGE_MOCK_UNDERLYING_DECIMALS", HEX_18) 51 | 52 | # Alchemy API Key is public 53 | # Mnemonic is hardhat's default 54 | 55 | ALCHEMY_KEY := env_var_or_default("ALCHEMY_KEY", "vI8OBZj4Wue9yNPSDVa7Klqt-UeRywrx") 56 | MAINNET_RPC := "https://eth-mainnet.alchemyapi.io/v2/" + ALCHEMY_KEY 57 | MNEMONIC := env_var_or_default("MNEMONIC", "test test test test test test test test test test test junk") 58 | 59 | # export just vars as env vars 60 | 61 | set export := true 62 | 63 | # Contract Size 64 | size: 65 | forge build --sizes --force 66 | 67 | # [DEPLOY]: Environemtn Config 68 | 69 | DEPLOYED_ADDRESS := "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" 70 | CONTRACT_NAME := '' 71 | ETHERSCAN_API_KEY := '' 72 | 73 | # [DEPLOY]: Deploy contract 74 | deploy-contract: 75 | forge create $(contract) \ 76 | --constructor-args $(constructorArgs) \ 77 | --rpc-url $(url) \ 78 | --private-key $(privateKey) 79 | 80 | # [DEPLOY]: Verify contract 81 | verify-contract: 82 | forge verify-contract \ 83 | --chain-id $(chainId) \ 84 | --constructor-args `cast abi-encode "$(constructorSig)" $(constructorArgs)` \ 85 | --compiler-version $(compilerVersion) \ 86 | --num-of-optimizations 200 \ 87 | {{ DEPLOYED_ADDRESS }} \ 88 | {{ CONTRACT_NAME }} \ 89 | {{ ETHERSCAN_API_KEY }} 90 | 91 | # [BUILD]: Timer 92 | build: && _timer 93 | cd {{ invocation_directory() }}; forge build --sizes --names --force 94 | 95 | # [TEST] mainnet test 96 | build-mainnet: && _timer 97 | cd {{ invocation_directory() }}; forge test --match-path "*.t.sol" --fork-url {{ MAINNET_RPC }} 98 | 99 | # [TEST] default test scripts 100 | test: test-local 101 | 102 | # [TEST] run local forge test using --match-path 103 | test-local *commands="": && _timer 104 | cd {{ invocation_directory() }}; forge test --match-path "*.t.sol" {{ commands }} 105 | 106 | # [TEST] run mainnet fork forge tests (all files with the extension .t.sol) 107 | test-mainnet *commands="": && _timer 108 | cd {{ invocation_directory() }}; forge test --rpc-url {{ MAINNET_RPC }} --match-path "*.t.sol" {{ commands }} 109 | 110 | # [TEST] run mainnet fork forge debug tests (all files with the extension .t.sol) 111 | test-debug *commands="": && _timer 112 | cd {{ invocation_directory() }}; forge test --rpc-url {{ MAINNET_RPC }} --match-path "*.t.sol" {{ commands }} 113 | 114 | gas-cov: 115 | forge test --gas-report 116 | 117 | # [GAS] default gas snapshot script 118 | gas-snapshot: gas-snapshot-local 119 | 120 | # [GAS] get gas snapshot from local tests and save it to file 121 | gas-snapshot-local: 122 | cd {{ invocation_directory() }}; \ 123 | just test-local | grep 'gas:' | cut -d " " -f 2-4 | sort > \ 124 | {{ justfile_directory() }}/gas-snapshots/.$( \ 125 | cat {{ invocation_directory() }}/package.json | jq .name | tr -d '"' | cut -d"/" -f2- \ 126 | ) 127 | 128 | # [GAS] get gas snapshot timer 129 | forge-gas-snapshot: && _timer 130 | @cd {{ invocation_directory() }}; forge snapshot --no-match-path ".*.*" 131 | 132 | forge-gas-snapshot-diff: && _timer 133 | @cd {{ invocation_directory() }}; forge snapshot --no-match-path ".*.*" --diff 134 | 135 | # Solidity test ffi callback to get Target decimals for the base Mock Target token 136 | _forge_mock_target_decimals: 137 | @printf {{ FORGE_MOCK_TARGET_DECIMALS }} 138 | 139 | _forge_mock_underlying_decimals: 140 | @printf {{ FORGE_MOCK_UNDERLYING_DECIMALS }} 141 | 142 | # [UTILS] utility functions 143 | 144 | start_time := `date +%s` 145 | 146 | _timer: 147 | @echo "[TASK]: Executed in $(($(date +%s) - {{ start_time }})) seconds" 148 | 149 | # mode: makefile 150 | # End: 151 | # vim: set ft=make : 152 | # vi: set ts=4 sw=4 noet : 153 | -------------------------------------------------------------------------------- /missing-pairs.txt: -------------------------------------------------------------------------------- 1 | ['0x09a3ecafa817268f77be1283176b946c4ff2e608', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 2 | ['0x1117ac6ad6cdf1a3bc543bad3b133724620522d5', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 3 | ['0x1117ac6ad6cdf1a3bc543bad3b133724620522d5', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x6b3595068778dd592e39a122f4f5a5cf09c90fe2'] 4 | ['0x1b890fd37cd50bea59346fc2f8ddb7cd9f5fabd5', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 5 | ['0x2034437801b62ede275210f76e2d4e77d0198bff', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 6 | ['0x2c0da41c89adb5a1d4430e5761b9b400911426b0', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x6b175474e89094c44da98b954eedeac495271d0f', '0x6b3595068778dd592e39a122f4f5a5cf09c90fe2'] 7 | ['0x31c2415c946928e9fd1af83cdfa38d3edbd4326f', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 8 | ['0x31c2415c946928e9fd1af83cdfa38d3edbd4326f', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xdac17f958d2ee523a2206206994597c13d831ec7'] 9 | ['0x3b484b82567a09e2588a13d54d032153f0c0aee0', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 10 | ['0x44709a920fccf795fbc57baa433cc3dd53c44dbe', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 11 | ['0x5b1d655c93185b06b00f7925791106132cb3ad75', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 12 | ['0x5b1d655c93185b06b00f7925791106132cb3ad75', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xe89c20096b636ffec9fd26d1a623f42a33ead309'] 13 | ['0x618679df9efcd19694bb1daa8d00718eacfa2883', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xdac17f958d2ee523a2206206994597c13d831ec7'] 14 | ['0x6b175474e89094c44da98b954eedeac495271d0f', '0xa4e27ea37d18bb0f483779f9e75a6024efa5e73e'] 15 | ['0x6b3595068778dd592e39a122f4f5a5cf09c90fe2', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xe89c20096b636ffec9fd26d1a623f42a33ead309'] 16 | ['0x6bba316c48b49bd1eac44573c5c871ff02958469', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 17 | ['0x70bef3bb2f001da2fddb207dae696cd9faff3f5d', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 18 | ['0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 19 | ['0x807a0774236a0fbe9e7f8e7df49edfed0e6777ea', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 20 | ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x0235a4fa8374fd49bb2f01ac953f99748756f3bd'] 21 | ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b'] 22 | ['0xb4dffa52fee44bd493f12d85829d775ec8017691', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', '0x6b3595068778dd592e39a122f4f5a5cf09c90fe2'] 23 | ['0xb4dffa52fee44bd493f12d85829d775ec8017691', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 24 | ['0xbb0e17ef65f82ab018d8edd776e8dd940327b28b', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 25 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x3b484b82567a09e2588a13d54d032153f0c0aee0'] 26 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x3b484b82567a09e2588a13d54d032153f0c0aee0'] 27 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x4e15361fd6b4bb609fa63c81a2be19d873717870'] 28 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b'] 29 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x5058b77cbd029f56a11bd56326519e3ec0081cd0'] 30 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x5b1d655c93185b06b00f7925791106132cb3ad75'] 31 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x5fe8c486b5f216b9ad83c12958d8a03eb3fd5060'] 32 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x618679df9efcd19694bb1daa8d00718eacfa2883'] 33 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x64aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d5'] 34 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x72b886d09c117654ab7da13a14d603001de0b777'] 35 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x7bef710a5759d197ec0bf621c3df802c2d60d848'] 36 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x853d955acef822db058eb8505911ed77f175b99e', '0x6b175474e89094c44da98b954eedeac495271d0f', '0x6b3595068778dd592e39a122f4f5a5cf09c90fe2'] 37 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x8b3192f5eebd8579568a2ed41e6feb402f93f73f'] 38 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3', '0x090185f2135308bad17527004364ebcc2d37e5f6'] 39 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xa0b73e1ff0b80914ab6fe0444e65848c4c34450b'] 40 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xdac17f958d2ee523a2206206994597c13d831ec7'] 41 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xe0a189c975e4928222978a74517442239a0b86ff'] 42 | ['0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xe89c20096b636ffec9fd26d1a623f42a33ead309'] 43 | ['0xda0c94c73d127ee191955fb46bacd7ff999b2bcd', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'] 44 | ['0xdac17f958d2ee523a2206206994597c13d831ec7', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 45 | ['0xdac17f958d2ee523a2206206994597c13d831ec7', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x64aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d5'] 46 | ['0xdb846f1cd31acc9a6db72a1c58dc1760485505f4', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 47 | ['0xe53ec727dbdeb9e2d5456c3be40cff031ab40a55', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0x64aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d5'] 48 | ['0xe80c0cd204d654cebe8dd64a4857cab6be8345a3', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', '0xdac17f958d2ee523a2206206994597c13d831ec7'] 49 | ['0xe89c20096b636ffec9fd26d1a623f42a33ead309', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] 50 | ['0xff20817765cb7f73d4bde2e66e067e58d11095c2', '0x6b175474e89094c44da98b954eedeac495271d0f', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'] -------------------------------------------------------------------------------- /contracts/flashloans/AaveFlashloanMultiRouter.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MPL-2.0 2 | // Creator: Manifold Finance 3 | // PackageName: @securerpc/simulate-bundle 4 | // PackageOriginator: ManifoldFinance 5 | // PackageHomePage: https://github.com/manifoldfinance/securerpc-simulate-bundle 6 | 7 | pragma solidity >=0.8.0 <0.9.0; 8 | 9 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 10 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 11 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 12 | import "@openzeppelin/contracts/utils/Address.sol"; 13 | import "@openzeppelin/contracts/utils/Strings.sol"; 14 | import "@openzeppelin/contracts/access/AccessControl.sol"; 15 | import "./aave/interfaces/ILendingPool.sol"; 16 | import { IUniswapV2Router02 } from "../IUniswapV2Router.sol"; 17 | 18 | contract AaveFlashloanMultiRouter is AccessControl { 19 | using SafeMath for uint256; 20 | using SafeERC20 for IERC20; 21 | 22 | bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); 23 | 24 | address public constant LENDING_POOL_ADDRESS = 0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9; 25 | 26 | constructor(address[] memory admins, address[] memory executors) { 27 | _grantAdminRole(admins); 28 | _grantExecutorRole(executors); 29 | } 30 | 31 | function call( 32 | address[] calldata routers, 33 | address[] calldata tokens, 34 | uint256 amount, 35 | uint256 deadline 36 | ) external onlyRole(EXECUTOR_ROLE) { 37 | require(tokens.length > 1, "AaveFlashloanMultiRouter: tokens.length <= 1"); 38 | require( 39 | routers.length == tokens.length - 1, 40 | "AaveFlashloanMultiRouter: routers.length != tokens.length - 1" 41 | ); 42 | require(amount > 0, "AaveFlashloanMultiRouter: amount == 0"); 43 | require(deadline >= block.timestamp, "AaveFlashloanMultiRouter: Expired deadline"); 44 | 45 | // address of the contract receiving the funds 46 | address receiverAddress = address(this); 47 | 48 | // addresses of the reserves to flashloan 49 | address[] memory assets = new address[](1); 50 | assets[0] = tokens[0]; 51 | 52 | // amounts of assets to flashloan. 53 | uint256[] memory amounts = new uint256[](1); 54 | amounts[0] = amount; 55 | 56 | // 0 = no debt (just revert), 1 = stable, 2 = variable 57 | uint256[] memory modes = new uint256[](1); 58 | modes[0] = 0; 59 | 60 | // if the associated mode is not 0 then the incurred debt will be applied to the onBehalfOf address 61 | address onBehalfOf = receiverAddress; 62 | 63 | // encode our extra params to struct Args 64 | bytes memory params = abi.encode(routers, tokens, deadline, msg.sender); 65 | 66 | // referral to nobody 67 | uint16 referralCode = 0; 68 | 69 | ILendingPool(LENDING_POOL_ADDRESS).flashLoan( 70 | receiverAddress, 71 | assets, 72 | amounts, 73 | modes, 74 | onBehalfOf, 75 | params, 76 | referralCode 77 | ); 78 | } 79 | 80 | // Called after your contract has received the flash loaned amount 81 | // Interface: @aave/protocol-v2/contracts/flashloan/interfaces/IFlashLoanReceiver.sol 82 | function executeOperation( 83 | address[] calldata assets, 84 | uint256[] calldata amounts, 85 | uint256[] calldata premiums, 86 | address initiator, 87 | bytes calldata params 88 | ) external returns (bool) { 89 | require( 90 | msg.sender == LENDING_POOL_ADDRESS, 91 | "AaveFlashloanMultiRouter: msg.sender != lendingPoolAddress" 92 | ); 93 | 94 | (address[] memory routers, address[] memory tokens, uint256 deadline, address sender) = abi 95 | .decode(params, (address[], address[], uint256, address)); 96 | 97 | // approve & swap 98 | _swapExactTokensForTokens(routers, tokens, amounts[0], initiator, deadline); 99 | 100 | // Approve the LendingPool contract allowance to *pull* the owed amount 101 | for (uint256 i = 0; i < assets.length; i++) { 102 | address asset = assets[i]; 103 | uint256 amountOwing = amounts[i] + premiums[i]; 104 | 105 | // approve loan re-payment and transfer amount left over back to sender 106 | uint256 amountOver = IERC20(asset).balanceOf(initiator); 107 | require( 108 | amountOver > amountOwing, 109 | "AaveFlashloanMultiRouter: Not enough to re-pay loan" 110 | ); 111 | 112 | IERC20(asset).safeApprove(LENDING_POOL_ADDRESS, amountOwing); 113 | 114 | // transfer remainder if any 115 | amountOver = amountOver - amountOwing; 116 | if (amountOver > 0) { 117 | IERC20(asset).safeTransfer(sender, amountOver); 118 | } 119 | } 120 | 121 | return true; 122 | } 123 | 124 | function withdraw(address payable to) external onlyRole(DEFAULT_ADMIN_ROLE) { 125 | require(to != address(0), "AaveFlashloanMultiRouter: to == address(0)"); 126 | uint256 amount = address(this).balance; 127 | (bool success, ) = to.call{ value: amount }(""); 128 | require(success, "AaveFlashloanMultiRouter: Failed to send Ether"); 129 | } 130 | 131 | function withdrawERC20(address token, address recipient) public onlyRole(DEFAULT_ADMIN_ROLE) { 132 | require(token != address(0), "AaveFlashloanMultiRouter: token address == invalid"); 133 | uint256 amount = IERC20(token).balanceOf(address(this)); 134 | IERC20(token).safeTransfer(recipient, amount); 135 | } 136 | 137 | function withdrawERC20s(address[] calldata tokens, address recipient) 138 | external 139 | onlyRole(DEFAULT_ADMIN_ROLE) 140 | { 141 | require(tokens.length > 0, "AaveFlashloanMultiRouter: tokens.length > 0"); 142 | for (uint256 i = 0; i < tokens.length; i++) { 143 | withdrawERC20(tokens[i], recipient); 144 | } 145 | } 146 | 147 | function destroy(address payable recipient) external onlyRole(DEFAULT_ADMIN_ROLE) { 148 | selfdestruct(recipient); 149 | } 150 | 151 | function _swapExactTokensForTokens( 152 | address[] memory routers, 153 | address[] memory tokens, 154 | uint256 amount, 155 | address to, 156 | uint256 deadline 157 | ) internal { 158 | uint256[] memory amounts = new uint256[](routers.length + 1); 159 | amounts[0] = amount; 160 | 161 | address[] memory path = new address[](2); 162 | 163 | for (uint256 i = 0; i < routers.length; i++) { 164 | require(amounts[i] > 0, "AaveFlashloanMultiRouter: No token balance"); 165 | IERC20(tokens[i]).safeApprove(routers[i], amounts[i]); 166 | 167 | uint256 allowance = IERC20(tokens[i]).allowance(to, routers[i]); 168 | require( 169 | allowance >= amounts[i], 170 | "AaveFlashloanMultiRouter: Not enough token allowance" 171 | ); 172 | 173 | path[0] = tokens[i]; 174 | path[1] = tokens[i + 1]; 175 | uint256[] memory amts = IUniswapV2Router02(routers[i]).swapExactTokensForTokens( 176 | amounts[i], 177 | 0, 178 | path, 179 | to, 180 | deadline 181 | ); 182 | amounts[i + 1] = amts[amts.length - 1]; 183 | } 184 | } 185 | 186 | function _grantAdminRole(address[] memory allowed) internal { 187 | _grantRole(allowed, DEFAULT_ADMIN_ROLE); 188 | } 189 | 190 | function _grantExecutorRole(address[] memory allowed) internal { 191 | _grantRole(allowed, EXECUTOR_ROLE); 192 | } 193 | 194 | function _grantRole(address[] memory allowed, bytes32 role) internal { 195 | require( 196 | allowed.length > 0, 197 | "AaveFlashloanMultiRouter: At least one address needs to be present to grant a role" 198 | ); 199 | for (uint256 i = 0; i < allowed.length; i++) { 200 | address a = allowed[i]; 201 | require( 202 | a != address(0), 203 | "AaveFlashloanMultiRouter: Empty address is invalid as to designate a role" 204 | ); 205 | _setupRole(role, a); 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /contracts/flashloans/aave/interfaces/ILendingPool.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MPL-2.0 2 | // Creator: Manifold Finance 3 | // PackageName: @securerpc/simulate-bundle 4 | // PackageOriginator: ManifoldFinance 5 | // PackageHomePage: https://github.com/manifoldfinance/securerpc-simulate-bundle 6 | 7 | pragma solidity >=0.8.0 <0.9.0; 8 | 9 | import "./ILendingPoolAddressesProvider.sol"; 10 | import "./../protocol/libraries/types/DataTypes.sol"; 11 | 12 | interface ILendingPool { 13 | /** 14 | * @dev Emitted on deposit() 15 | * @param reserve The address of the underlying asset of the reserve 16 | * @param user The address initiating the deposit 17 | * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens 18 | * @param amount The amount deposited 19 | * @param referral The referral code used 20 | **/ 21 | event Deposit( 22 | address indexed reserve, 23 | address user, 24 | address indexed onBehalfOf, 25 | uint256 amount, 26 | uint16 indexed referral 27 | ); 28 | 29 | /** 30 | * @dev Emitted on withdraw() 31 | * @param reserve The address of the underlyng asset being withdrawn 32 | * @param user The address initiating the withdrawal, owner of aTokens 33 | * @param to Address that will receive the underlying 34 | * @param amount The amount to be withdrawn 35 | **/ 36 | event Withdraw( 37 | address indexed reserve, 38 | address indexed user, 39 | address indexed to, 40 | uint256 amount 41 | ); 42 | 43 | /** 44 | * @dev Emitted on borrow() and flashLoan() when debt needs to be opened 45 | * @param reserve The address of the underlying asset being borrowed 46 | * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just 47 | * initiator of the transaction on flashLoan() 48 | * @param onBehalfOf The address that will be getting the debt 49 | * @param amount The amount borrowed out 50 | * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable 51 | * @param borrowRate The numeric rate at which the user has borrowed 52 | * @param referral The referral code used 53 | **/ 54 | event Borrow( 55 | address indexed reserve, 56 | address user, 57 | address indexed onBehalfOf, 58 | uint256 amount, 59 | uint256 borrowRateMode, 60 | uint256 borrowRate, 61 | uint16 indexed referral 62 | ); 63 | 64 | /** 65 | * @dev Emitted on repay() 66 | * @param reserve The address of the underlying asset of the reserve 67 | * @param user The beneficiary of the repayment, getting his debt reduced 68 | * @param repayer The address of the user initiating the repay(), providing the funds 69 | * @param amount The amount repaid 70 | **/ 71 | event Repay( 72 | address indexed reserve, 73 | address indexed user, 74 | address indexed repayer, 75 | uint256 amount 76 | ); 77 | 78 | /** 79 | * @dev Emitted on swapBorrowRateMode() 80 | * @param reserve The address of the underlying asset of the reserve 81 | * @param user The address of the user swapping his rate mode 82 | * @param rateMode The rate mode that the user wants to swap to 83 | **/ 84 | event Swap(address indexed reserve, address indexed user, uint256 rateMode); 85 | 86 | /** 87 | * @dev Emitted on setUserUseReserveAsCollateral() 88 | * @param reserve The address of the underlying asset of the reserve 89 | * @param user The address of the user enabling the usage as collateral 90 | **/ 91 | event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); 92 | 93 | /** 94 | * @dev Emitted on setUserUseReserveAsCollateral() 95 | * @param reserve The address of the underlying asset of the reserve 96 | * @param user The address of the user enabling the usage as collateral 97 | **/ 98 | event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); 99 | 100 | /** 101 | * @dev Emitted on rebalanceStableBorrowRate() 102 | * @param reserve The address of the underlying asset of the reserve 103 | * @param user The address of the user for which the rebalance has been executed 104 | **/ 105 | event RebalanceStableBorrowRate(address indexed reserve, address indexed user); 106 | 107 | /** 108 | * @dev Emitted on flashLoan() 109 | * @param target The address of the flash loan receiver contract 110 | * @param initiator The address initiating the flash loan 111 | * @param asset The address of the asset being flash borrowed 112 | * @param amount The amount flash borrowed 113 | * @param premium The fee flash borrowed 114 | * @param referralCode The referral code used 115 | **/ 116 | event FlashLoan( 117 | address indexed target, 118 | address indexed initiator, 119 | address indexed asset, 120 | uint256 amount, 121 | uint256 premium, 122 | uint16 referralCode 123 | ); 124 | 125 | /** 126 | * @dev Emitted when the pause is triggered. 127 | */ 128 | event Paused(); 129 | 130 | /** 131 | * @dev Emitted when the pause is lifted. 132 | */ 133 | event Unpaused(); 134 | 135 | /** 136 | * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via 137 | * LendingPoolCollateral manager using a DELEGATECALL 138 | * This allows to have the events in the generated ABI for LendingPool. 139 | * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation 140 | * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation 141 | * @param user The address of the borrower getting liquidated 142 | * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover 143 | * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator 144 | * @param liquidator The address of the liquidator 145 | * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants 146 | * to receive the underlying collateral asset directly 147 | **/ 148 | event LiquidationCall( 149 | address indexed collateralAsset, 150 | address indexed debtAsset, 151 | address indexed user, 152 | uint256 debtToCover, 153 | uint256 liquidatedCollateralAmount, 154 | address liquidator, 155 | bool receiveAToken 156 | ); 157 | 158 | /** 159 | * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared 160 | * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal, 161 | * the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it 162 | * gets added to the LendingPool ABI 163 | * @param reserve The address of the underlying asset of the reserve 164 | * @param liquidityRate The new liquidity rate 165 | * @param stableBorrowRate The new stable borrow rate 166 | * @param variableBorrowRate The new variable borrow rate 167 | * @param liquidityIndex The new liquidity index 168 | * @param variableBorrowIndex The new variable borrow index 169 | **/ 170 | event ReserveDataUpdated( 171 | address indexed reserve, 172 | uint256 liquidityRate, 173 | uint256 stableBorrowRate, 174 | uint256 variableBorrowRate, 175 | uint256 liquidityIndex, 176 | uint256 variableBorrowIndex 177 | ); 178 | 179 | /** 180 | * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. 181 | * - E.g. User deposits 100 USDC and gets in return 100 aUSDC 182 | * @param asset The address of the underlying asset to deposit 183 | * @param amount The amount to be deposited 184 | * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user 185 | * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens 186 | * is a different wallet 187 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 188 | * 0 if the action is executed directly by the user, without any middle-man 189 | **/ 190 | function deposit( 191 | address asset, 192 | uint256 amount, 193 | address onBehalfOf, 194 | uint16 referralCode 195 | ) external; 196 | 197 | /** 198 | * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned 199 | * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC 200 | * @param asset The address of the underlying asset to withdraw 201 | * @param amount The underlying amount to be withdrawn 202 | * - Send the value type(uint256).max in order to withdraw the whole aToken balance 203 | * @param to Address that will receive the underlying, same as msg.sender if the user 204 | * wants to receive it on his own wallet, or a different address if the beneficiary is a 205 | * different wallet 206 | **/ 207 | function withdraw( 208 | address asset, 209 | uint256 amount, 210 | address to 211 | ) external; 212 | 213 | /** 214 | * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower 215 | * already deposited enough collateral, or he was given enough allowance by a credit delegator on the 216 | * corresponding debt token (StableDebtToken or VariableDebtToken) 217 | * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet 218 | * and 100 stable/variable debt tokens, depending on the `interestRateMode` 219 | * @param asset The address of the underlying asset to borrow 220 | * @param amount The amount to be borrowed 221 | * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable 222 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 223 | * 0 if the action is executed directly by the user, without any middle-man 224 | * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself 225 | * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator 226 | * if he has been given credit delegation allowance 227 | **/ 228 | function borrow( 229 | address asset, 230 | uint256 amount, 231 | uint256 interestRateMode, 232 | uint16 referralCode, 233 | address onBehalfOf 234 | ) external; 235 | 236 | /** 237 | * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned 238 | * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address 239 | * @param asset The address of the borrowed underlying asset previously borrowed 240 | * @param amount The amount to repay 241 | * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` 242 | * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable 243 | * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the 244 | * user calling the function if he wants to reduce/remove his own debt, or the address of any other 245 | * other borrower whose debt should be removed 246 | **/ 247 | function repay( 248 | address asset, 249 | uint256 amount, 250 | uint256 rateMode, 251 | address onBehalfOf 252 | ) external; 253 | 254 | /** 255 | * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa 256 | * @param asset The address of the underlying asset borrowed 257 | * @param rateMode The rate mode that the user wants to swap to 258 | **/ 259 | function swapBorrowRateMode(address asset, uint256 rateMode) external; 260 | 261 | /** 262 | * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. 263 | * - Users can be rebalanced if the following conditions are satisfied: 264 | * 1. Usage ratio is above 95% 265 | * 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been 266 | * borrowed at a stable rate and depositors are not earning enough 267 | * @param asset The address of the underlying asset borrowed 268 | * @param user The address of the user to be rebalanced 269 | **/ 270 | function rebalanceStableBorrowRate(address asset, address user) external; 271 | 272 | /** 273 | * @dev Allows depositors to enable/disable a specific deposited asset as collateral 274 | * @param asset The address of the underlying asset deposited 275 | * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise 276 | **/ 277 | function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; 278 | 279 | /** 280 | * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 281 | * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives 282 | * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk 283 | * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation 284 | * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation 285 | * @param user The address of the borrower getting liquidated 286 | * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover 287 | * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants 288 | * to receive the underlying collateral asset directly 289 | **/ 290 | function liquidationCall( 291 | address collateralAsset, 292 | address debtAsset, 293 | address user, 294 | uint256 debtToCover, 295 | bool receiveAToken 296 | ) external; 297 | 298 | /** 299 | * @dev Allows smartcontracts to access the liquidity of the pool within one transaction, 300 | * as long as the amount taken plus a fee is returned. 301 | * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration. 302 | * For further details please visit https://developers.aave.com 303 | * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface 304 | * @param assets The addresses of the assets being flash-borrowed 305 | * @param amounts The amounts amounts being flash-borrowed 306 | * @param modes Types of the debt to open if the flash loan is not returned: 307 | * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver 308 | * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address 309 | * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address 310 | * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 311 | * @param params Variadic packed params to pass to the receiver as extra information 312 | * @param referralCode Code used to register the integrator originating the operation, for potential rewards. 313 | * 0 if the action is executed directly by the user, without any middle-man 314 | **/ 315 | function flashLoan( 316 | address receiverAddress, 317 | address[] calldata assets, 318 | uint256[] calldata amounts, 319 | uint256[] calldata modes, 320 | address onBehalfOf, 321 | bytes calldata params, 322 | uint16 referralCode 323 | ) external; 324 | 325 | /** 326 | * @dev Returns the user account data across all the reserves 327 | * @param user The address of the user 328 | * @return totalCollateralETH the total collateral in ETH of the user 329 | * @return totalDebtETH the total debt in ETH of the user 330 | * @return availableBorrowsETH the borrowing power left of the user 331 | * @return currentLiquidationThreshold the liquidation threshold of the user 332 | * @return ltv the loan to value of the user 333 | * @return healthFactor the current health factor of the user 334 | **/ 335 | function getUserAccountData(address user) 336 | external 337 | view 338 | returns ( 339 | uint256 totalCollateralETH, 340 | uint256 totalDebtETH, 341 | uint256 availableBorrowsETH, 342 | uint256 currentLiquidationThreshold, 343 | uint256 ltv, 344 | uint256 healthFactor 345 | ); 346 | 347 | function initReserve( 348 | address reserve, 349 | address aTokenAddress, 350 | address stableDebtAddress, 351 | address variableDebtAddress, 352 | address interestRateStrategyAddress 353 | ) external; 354 | 355 | function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress) 356 | external; 357 | 358 | function setConfiguration(address reserve, uint256 configuration) external; 359 | 360 | /** 361 | * @dev Returns the configuration of the reserve 362 | * @param asset The address of the underlying asset of the reserve 363 | * @return The configuration of the reserve 364 | **/ 365 | function getConfiguration(address asset) 366 | external 367 | view 368 | returns (DataTypes.ReserveConfigurationMap memory); 369 | 370 | /** 371 | * @dev Returns the configuration of the user across all the reserves 372 | * @param user The user address 373 | * @return The configuration of the user 374 | **/ 375 | function getUserConfiguration(address user) 376 | external 377 | view 378 | returns (DataTypes.UserConfigurationMap memory); 379 | 380 | /** 381 | * @dev Returns the normalized income normalized income of the reserve 382 | * @param asset The address of the underlying asset of the reserve 383 | * @return The reserve's normalized income 384 | */ 385 | function getReserveNormalizedIncome(address asset) external view returns (uint256); 386 | 387 | /** 388 | * @dev Returns the normalized variable debt per unit of asset 389 | * @param asset The address of the underlying asset of the reserve 390 | * @return The reserve normalized variable debt 391 | */ 392 | function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); 393 | 394 | /** 395 | * @dev Returns the state and configuration of the reserve 396 | * @param asset The address of the underlying asset of the reserve 397 | * @return The state of the reserve 398 | **/ 399 | function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); 400 | 401 | function finalizeTransfer( 402 | address asset, 403 | address from, 404 | address to, 405 | uint256 amount, 406 | uint256 balanceFromAfter, 407 | uint256 balanceToBefore 408 | ) external; 409 | 410 | function getReservesList() external view returns (address[] memory); 411 | 412 | function getAddressesProvider() external view returns (ILendingPoolAddressesProvider); 413 | 414 | function setPause(bool val) external; 415 | 416 | function paused() external view returns (bool); 417 | } 418 | --------------------------------------------------------------------------------