diff --git a/README.md b/README.md index 88bd68b0..381da85e 100644 --- a/README.md +++ b/README.md @@ -47,18 +47,3 @@ Deploy the contracts to Hardhat Network: ```sh $ npm run deploy ``` - -## Syntax Highlighting - -If you use VSCode, you can enjoy syntax highlighting for your Solidity code via the -[vscode-solidity](https://github.com/juanfranblanco/vscode-solidity) extension. The recommended approach to set the -compiler version is to add the following fields to your VSCode user settings: - -```json -{ - "solidity.compileUsingRemoteVersion": "v0.8.4+commit.c7e474f2", - "solidity.defaultCompiler": "remote" -} -``` - -Where of course `v0.8.4+commit.c7e474f2` can be replaced with any other version. diff --git a/contracts/aggregator/arbitrum/flashloan/helpers.sol b/contracts/aggregator/arbitrum/flashloan/helpers.sol index 1929b714..2ac4bd41 100644 --- a/contracts/aggregator/arbitrum/flashloan/helpers.sol +++ b/contracts/aggregator/arbitrum/flashloan/helpers.sol @@ -2,9 +2,10 @@ pragma solidity ^0.8.0; import "./variables.sol"; +import "../../common/helpers.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -contract Helper is Variables { +contract Helper is HelpersCommon, Variables { using SafeERC20 for IERC20; /** @@ -102,25 +103,6 @@ contract Helper is Variables { } } - /** - * @dev Calculates the balances.. - * @notice Calculates the balances of the account passed for the tokens. - * @param _tokens list of token addresses to calculate balance for. - * @param _account account to calculate balance for. - */ - function calculateBalances(address[] memory _tokens, address _account) - internal - view - returns (uint256[] memory) - { - uint256 _length = _tokens.length; - uint256[] memory balances_ = new uint256[](_length); - for (uint256 i = 0; i < _length; i++) { - IERC20 token = IERC20(_tokens[i]); - balances_[i] = token.balanceOf(_account); - } - return balances_; - } /** * @dev Validates if the receiver sent the correct amounts of funds. @@ -141,17 +123,6 @@ contract Helper is Variables { } } - /** - * @dev Validates if token addresses are unique. Just need to check adjacent tokens as the array was sorted first - * @notice Validates if token addresses are unique. - * @param _tokens list of token addresses. - */ - function validateTokens(address[] memory _tokens) internal pure { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - require(_tokens[i] != _tokens[i + 1], "non-unique-tokens"); - } - } - /** * @dev Returns fee for the passed route in BPS. * @notice Returns fee for the passed route in BPS. 1 BPS == 0.01%. @@ -179,56 +150,6 @@ contract Helper is Variables { } } - /** - * @dev Calculate fees for the respective amounts and fee in BPS passed. - * @notice Calculate fees for the respective amounts and fee in BPS passed. 1 BPS == 0.01%. - * @param _amounts list of amounts. - * @param _BPS fee in BPS. - */ - function calculateFees(uint256[] memory _amounts, uint256 _BPS) - internal - pure - returns (uint256[] memory) - { - uint256 length_ = _amounts.length; - uint256[] memory InstaFees = new uint256[](length_); - for (uint256 i = 0; i < length_; i++) { - InstaFees[i] = (_amounts[i] * _BPS) / (10**4); - } - return InstaFees; - } - - /** - * @dev Sort the tokens and amounts arrays according to token addresses. - * @notice Sort the tokens and amounts arrays according to token addresses. - * @param _tokens list of token addresses. - * @param _amounts list of respective amounts. - */ - function bubbleSort(address[] memory _tokens, uint256[] memory _amounts) - internal - pure - returns (address[] memory, uint256[] memory) - { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - for (uint256 j = 0; j < _tokens.length - i - 1; j++) { - if (_tokens[j] > _tokens[j + 1]) { - ( - _tokens[j], - _tokens[j + 1], - _amounts[j], - _amounts[j + 1] - ) = ( - _tokens[j + 1], - _tokens[j], - _amounts[j + 1], - _amounts[j] - ); - } - } - } - return (_tokens, _amounts); - } - /** * @dev Returns to true if the passed address is a DSA else returns false. * @notice Returns to true if the passed address is a DSA else returns false. diff --git a/contracts/aggregator/arbitrum/flashloan/implBalancer/main.sol b/contracts/aggregator/arbitrum/flashloan/implBalancer/main.sol new file mode 100644 index 00000000..934b3451 --- /dev/null +++ b/contracts/aggregator/arbitrum/flashloan/implBalancer/main.sol @@ -0,0 +1,120 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import "../helpers.sol"; + +contract BalancerImplementationArbitrum is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes memory _instadata + ) external reentrancy { + require(_route == 5 , "invalid-BALANCER-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + routeBalancer(_tokens, _amounts, _data); + } + + /** + * @dev Callback function for balancer flashloan. + * @notice Fallback function for balancer flashloan. + * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. + * @param _fees list of fees for the corresponding addresses for flashloan. + * @param _data extra data passed. + */ + function receiveFlashLoan( + IERC20[] memory _tokens, + uint256[] memory _amounts, + uint256[] memory _fees, + bytes memory _data + ) external verifyDataHash(_data) { + require(msg.sender == balancerLendingAddr, "not-balancer-sender"); + + FlashloanVariables memory instaLoanVariables_; + + uint256 length_ = _tokens.length; + instaLoanVariables_._tokens = new address[](length_); + for (uint256 i = 0; i < length_; i++) { + instaLoanVariables_._tokens[i] = address(_tokens[i]); + } + + (address sender_, bytes memory data_) = abi.decode( + _data, + (address, bytes) + ); + + instaLoanVariables_._amounts = _amounts; + instaLoanVariables_._iniBals = calculateBalances( + instaLoanVariables_._tokens, + address(this) + ); + instaLoanVariables_._instaFees = calculateFees( + _amounts, + calculateFeeBPS(5) + ); + + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + instaLoanVariables_._tokens, + _amounts, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + + instaLoanVariables_._finBals = calculateBalances( + instaLoanVariables_._tokens, + address(this) + ); + validateFlashloan(instaLoanVariables_); + + safeTransferWithFee(instaLoanVariables_, _fees, balancerLendingAddr); + } + + + /** + * @dev Middle function for route 5. + * @notice Middle function for route 5. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + */ + function routeBalancer( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + bytes memory data_ = abi.encode(msg.sender, _data); + uint256 length_ = _tokens.length; + IERC20[] memory tokens_ = new IERC20[](length_); + for (uint256 i = 0; i < length_; i++) { + tokens_[i] = IERC20(_tokens[i]); + } + dataHash = bytes32(keccak256(data_)); + balancerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + tokens_, + _amounts, + data_ + ); + } +} diff --git a/contracts/aggregator/arbitrum/flashloan/implUniswap/main.sol b/contracts/aggregator/arbitrum/flashloan/implUniswap/main.sol new file mode 100644 index 00000000..02b8f2c3 --- /dev/null +++ b/contracts/aggregator/arbitrum/flashloan/implUniswap/main.sol @@ -0,0 +1,176 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import "../helpers.sol"; + +contract UniswapImplementationArbitrum is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes memory _instadata + ) external reentrancy { + require(_route == 8, "invalid-UNISWAP-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + routeUniswap(_tokens, _amounts, _data, _instadata); + } + + struct UniswapFlashInfo { + address sender; + PoolKey key; + bytes data; + } + + /** + * @dev Callback function for uniswap flashloan. + * @notice Callback function for uniswap flashloan. + * @param fee0 The fee from calling flash for token0 + * @param fee1 The fee from calling flash for token1 + * @param data extra data passed(includes route info aswell). + */ + function uniswapV3FlashCallback( + uint256 fee0, + uint256 fee1, + bytes memory data + ) external verifyDataHash(data) { + FlashloanVariables memory instaLoanVariables_; + UniswapFlashInfo memory uniswapFlashData_; + + ( + instaLoanVariables_._tokens, + instaLoanVariables_._amounts, + uniswapFlashData_.sender, + uniswapFlashData_.key, + uniswapFlashData_.data + ) = abi.decode(data, (address[], uint256[], address, PoolKey, bytes)); + + address pool = computeAddress( + uniswapFactoryAddr, + uniswapFlashData_.key + ); + require(msg.sender == pool, "invalid-sender"); + + instaLoanVariables_._iniBals = calculateBalances( + instaLoanVariables_._tokens, + address(this) + ); + + uint256 feeBPS = uint256(uniswapFlashData_.key.fee / 100); + if (feeBPS < InstaFeeBPS) { + feeBPS = InstaFeeBPS; + } + + instaLoanVariables_._instaFees = calculateFees( + instaLoanVariables_._amounts, + feeBPS + ); + + safeTransfer(instaLoanVariables_, uniswapFlashData_.sender); + + if (checkIfDsa(uniswapFlashData_.sender)) { + Address.functionCall( + uniswapFlashData_.sender, + uniswapFlashData_.data, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(uniswapFlashData_.sender) + .executeOperation( + instaLoanVariables_._tokens, + instaLoanVariables_._amounts, + instaLoanVariables_._instaFees, + uniswapFlashData_.sender, + uniswapFlashData_.data + ); + } + + instaLoanVariables_._finBals = calculateBalances( + instaLoanVariables_._tokens, + address(this) + ); + + validateFlashloan(instaLoanVariables_); + + uint256[] memory fees_; + if (instaLoanVariables_._tokens.length == 2) { + fees_ = new uint256[](2); + fees_[0] = fee0; + fees_[1] = fee1; + } else if ( + instaLoanVariables_._tokens[0] == uniswapFlashData_.key.token0 + ) { + fees_ = new uint256[](1); + fees_[0] = fee0; + } else { + fees_ = new uint256[](1); + fees_[0] = fee1; + } + safeTransferWithFee(instaLoanVariables_, fees_, msg.sender); + } + + /** + * @dev Middle function for route 8. + * @notice Middle function for route 8. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + * @param _instadata pool key encoded + */ + function routeUniswap( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data, + bytes memory _instadata + ) internal { + PoolKey memory key = abi.decode(_instadata, (PoolKey)); + (key.token0, key.token1) = sortTokens(key.token0, key.token1); + + uint256 amount0_; + uint256 amount1_; + + if (_tokens.length == 1) { + require( + (_tokens[0] == key.token0 || _tokens[0] == key.token1), + "tokens-do-not-match-pool" + ); + if (_tokens[0] == key.token0) { + amount0_ = _amounts[0]; + } else { + amount1_ = _amounts[0]; + } + } else if (_tokens.length == 2) { + require( + (_tokens[0] == key.token0 && _tokens[1] == key.token1), + "tokens-do-not-match-pool" + ); + amount0_ = _amounts[0]; + amount1_ = _amounts[1]; + } else { + revert("Number of tokens do not match"); + } + + IUniswapV3Pool pool = IUniswapV3Pool( + computeAddress(uniswapFactoryAddr, key) + ); + + bytes memory data_ = abi.encode( + _tokens, + _amounts, + msg.sender, + key, + _data + ); + dataHash = bytes32(keccak256(data_)); + pool.flash(address(this), amount0_, amount1_, data_); + } +} diff --git a/contracts/aggregator/arbitrum/flashloan/interfaces.sol b/contracts/aggregator/arbitrum/flashloan/interfaces.sol index 7c6dbacb..333d9a63 100644 --- a/contracts/aggregator/arbitrum/flashloan/interfaces.sol +++ b/contracts/aggregator/arbitrum/flashloan/interfaces.sol @@ -12,38 +12,6 @@ interface InstaFlashReceiverInterface { ) external returns (bool); } -interface IndexInterface { - function master() external view returns (address); - - function list() external view returns (address); -} - -interface ListInterface { - function accountID(address) external view returns (uint64); -} - -interface TokenInterface { - function approve(address, uint256) external; - - function transfer(address, uint256) external; - - function transferFrom( - address, - address, - uint256 - ) external; - - function deposit() external payable; - - function withdraw(uint256) external; - - function balanceOf(address) external view returns (uint256); - - function decimals() external view returns (uint256); - - function totalSupply() external view returns (uint256); -} - interface ProtocolFeesCollector { function getFlashLoanFeePercentage() external view returns (uint256); } diff --git a/contracts/aggregator/arbitrum/flashloan/main.sol b/contracts/aggregator/arbitrum/flashloan/main.sol index 7f0470cc..93e89cdc 100644 --- a/contracts/aggregator/arbitrum/flashloan/main.sol +++ b/contracts/aggregator/arbitrum/flashloan/main.sol @@ -1,8 +1,11 @@ //SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +/** + * @title Flashloan. + * @dev Flashloan aggregator for Arbitrum. + */ import "./helpers.sol"; -import "@openzeppelin/contracts/utils/Address.sol"; contract FlashAggregatorArbitrum is Helper { using SafeERC20 for IERC20; @@ -26,63 +29,8 @@ contract FlashAggregatorArbitrum is Helper { uint256[] memory _amounts, uint256[] memory _fees, bytes memory _data - ) external verifyDataHash(_data) { - require(msg.sender == balancerLendingAddr, "not-balancer-sender"); - - FlashloanVariables memory instaLoanVariables_; - - uint256 length_ = _tokens.length; - instaLoanVariables_._tokens = new address[](length_); - for (uint256 i = 0; i < length_; i++) { - instaLoanVariables_._tokens[i] = address(_tokens[i]); - } - - (address sender_, bytes memory data_) = abi.decode( - _data, - (address, bytes) - ); - - instaLoanVariables_._amounts = _amounts; - instaLoanVariables_._iniBals = calculateBalances( - instaLoanVariables_._tokens, - address(this) - ); - instaLoanVariables_._instaFees = calculateFees( - _amounts, - calculateFeeBPS(5) - ); - - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - instaLoanVariables_._tokens, - _amounts, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - - instaLoanVariables_._finBals = calculateBalances( - instaLoanVariables_._tokens, - address(this) - ); - validateFlashloan(instaLoanVariables_); - - safeTransferWithFee(instaLoanVariables_, _fees, balancerLendingAddr); - } - - struct UniswapFlashInfo { - address sender; - PoolKey key; - bytes data; + ) external { + spell(BALANCER_IMPL, msg.data); } /** @@ -96,162 +44,8 @@ contract FlashAggregatorArbitrum is Helper { uint256 fee0, uint256 fee1, bytes memory data - ) external verifyDataHash(data) { - FlashloanVariables memory instaLoanVariables_; - UniswapFlashInfo memory uniswapFlashData_; - - ( - instaLoanVariables_._tokens, - instaLoanVariables_._amounts, - uniswapFlashData_.sender, - uniswapFlashData_.key, - uniswapFlashData_.data - ) = abi.decode(data, (address[], uint256[], address, PoolKey, bytes)); - - address pool = computeAddress( - uniswapFactoryAddr, - uniswapFlashData_.key - ); - require(msg.sender == pool, "invalid-sender"); - - instaLoanVariables_._iniBals = calculateBalances( - instaLoanVariables_._tokens, - address(this) - ); - - uint256 feeBPS = uint256(uniswapFlashData_.key.fee / 100); - if (feeBPS < InstaFeeBPS) { - feeBPS = InstaFeeBPS; - } - - instaLoanVariables_._instaFees = calculateFees( - instaLoanVariables_._amounts, - feeBPS - ); - - safeTransfer(instaLoanVariables_, uniswapFlashData_.sender); - - if (checkIfDsa(uniswapFlashData_.sender)) { - Address.functionCall( - uniswapFlashData_.sender, - uniswapFlashData_.data, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(uniswapFlashData_.sender) - .executeOperation( - instaLoanVariables_._tokens, - instaLoanVariables_._amounts, - instaLoanVariables_._instaFees, - uniswapFlashData_.sender, - uniswapFlashData_.data - ); - } - - instaLoanVariables_._finBals = calculateBalances( - instaLoanVariables_._tokens, - address(this) - ); - - validateFlashloan(instaLoanVariables_); - - uint256[] memory fees_; - if (instaLoanVariables_._tokens.length == 2) { - fees_ = new uint256[](2); - fees_[0] = fee0; - fees_[1] = fee1; - } else if ( - instaLoanVariables_._tokens[0] == uniswapFlashData_.key.token0 - ) { - fees_ = new uint256[](1); - fees_[0] = fee0; - } else { - fees_ = new uint256[](1); - fees_[0] = fee1; - } - safeTransferWithFee(instaLoanVariables_, fees_, msg.sender); - } - - /** - * @dev Middle function for route 5. - * @notice Middle function for route 5. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - */ - function routeBalancer( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - bytes memory data_ = abi.encode(msg.sender, _data); - uint256 length_ = _tokens.length; - IERC20[] memory tokens_ = new IERC20[](length_); - for (uint256 i = 0; i < length_; i++) { - tokens_[i] = IERC20(_tokens[i]); - } - dataHash = bytes32(keccak256(data_)); - balancerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - tokens_, - _amounts, - data_ - ); - } - - /** - * @dev Middle function for route 8. - * @notice Middle function for route 8. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - * @param _instadata pool key encoded - */ - function routeUniswap( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data, - bytes memory _instadata - ) internal { - PoolKey memory key = abi.decode(_instadata, (PoolKey)); - - uint256 amount0_; - uint256 amount1_; - - if (_tokens.length == 1) { - require( - (_tokens[0] == key.token0 || _tokens[0] == key.token1), - "tokens-do-not-match-pool" - ); - if (_tokens[0] == key.token0) { - amount0_ = _amounts[0]; - } else { - amount1_ = _amounts[0]; - } - } else if (_tokens.length == 2) { - require( - (_tokens[0] == key.token0 && _tokens[1] == key.token1), - "tokens-do-not-match-pool" - ); - amount0_ = _amounts[0]; - amount1_ = _amounts[1]; - } else { - revert("Number of tokens do not match"); - } - - IUniswapV3Pool pool = IUniswapV3Pool( - computeAddress(uniswapFactoryAddr, key) - ); - - bytes memory data_ = abi.encode( - _tokens, - _amounts, - msg.sender, - key, - _data - ); - dataHash = bytes32(keccak256(data_)); - pool.flash(address(this), amount0_, amount1_, data_); + ) external { + spell(UNISWAP_IMPL, msg.data); } /** @@ -268,16 +62,13 @@ contract FlashAggregatorArbitrum is Helper { uint256 _route, bytes calldata _data, bytes memory _instadata - ) external reentrancy { + ) external { require(_tokens.length == _amounts.length, "array-lengths-not-same"); - (_tokens, _amounts) = bubbleSort(_tokens, _amounts); - validateTokens(_tokens); - if (_route == 5) { - routeBalancer(_tokens, _amounts, _data); + spell(BALANCER_IMPL, msg.data); } else if (_route == 8) { - routeUniswap(_tokens, _amounts, _data, _instadata); + spell(UNISWAP_IMPL, msg.data); } else { revert("route-does-not-exist"); } @@ -327,5 +118,13 @@ contract InstaFlashAggregatorArbitrum is FlashAggregatorArbitrum { // status = 1; // } + /** + * @dev Function created for testing upgradable implementations + */ + // function initialize(address bImp, address uImp) public { + // BALANCER_IMPL = bImp; + // UNISWAP_IMPL = uImp; + // } + receive() external payable {} } diff --git a/contracts/aggregator/arbitrum/flashloan/variables.sol b/contracts/aggregator/arbitrum/flashloan/variables.sol index f790c033..5649b65c 100644 --- a/contracts/aggregator/arbitrum/flashloan/variables.sol +++ b/contracts/aggregator/arbitrum/flashloan/variables.sol @@ -1,6 +1,7 @@ //SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import "../../common/interface.sol"; import "./interfaces.sol"; contract ConstantVariables { @@ -43,4 +44,7 @@ contract Variables is ConstantVariables { address token1; uint24 fee; } + + address internal BALANCER_IMPL; + address internal UNISWAP_IMPL; } diff --git a/contracts/aggregator/avalanche/flashloan/helpers.sol b/contracts/aggregator/avalanche/flashloan/helpers.sol index 779c45f1..7392e3dd 100644 --- a/contracts/aggregator/avalanche/flashloan/helpers.sol +++ b/contracts/aggregator/avalanche/flashloan/helpers.sol @@ -1,17 +1,9 @@ //SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; +import "./variables.sol"; +import "../../common/helpers.sol"; -import {Variables} from "./variables.sol"; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; - -import { - TokenInterface, - InstaFlashReceiverInterface -} from "./interfaces.sol"; - -contract Helper is Variables { +contract Helper is HelpersCommon, Variables { using SafeERC20 for IERC20; /** @@ -70,25 +62,6 @@ contract Helper is Variables { } } - /** - * @dev Calculates the balances.. - * @notice Calculates the balances of the account passed for the tokens. - * @param _tokens list of token addresses to calculate balance for. - * @param _account account to calculate balance for. - */ - function calculateBalances( - address[] memory _tokens, - address _account - ) internal view returns (uint256[] memory) { - uint256 _length = _tokens.length; - uint256[] memory balances_ = new uint256[](_length); - for (uint i = 0; i < _length; i++) { - IERC20 token = IERC20(_tokens[i]); - balances_[i] = token.balanceOf(_account); - } - return balances_; - } - /** * @dev Validates if the receiver sent the correct amounts of funds. * @notice Validates if the receiver sent the correct amounts of funds. @@ -102,17 +75,6 @@ contract Helper is Variables { } } - /** - * @dev Validates if token addresses are unique. Just need to check adjacent tokens as the array was sorted first - * @notice Validates if token addresses are unique. - * @param _tokens list of token addresses. - */ - function validateTokens(address[] memory _tokens) internal pure { - for (uint i = 0; i < _tokens.length - 1; i++) { - require(_tokens[i] != _tokens[i+1], "non-unique-tokens"); - } - } - /** * @dev Returns fee for the passed route in BPS. * @notice Returns fee for the passed route in BPS. 1 BPS == 0.01%. @@ -130,38 +92,6 @@ contract Helper is Variables { } } - /** - * @dev Calculate fees for the respective amounts and fee in BPS passed. - * @notice Calculate fees for the respective amounts and fee in BPS passed. 1 BPS == 0.01%. - * @param _amounts list of amounts. - * @param _BPS fee in BPS. - */ - function calculateFees(uint256[] memory _amounts, uint256 _BPS) internal pure returns (uint256[] memory) { - uint256 length_ = _amounts.length; - uint256[] memory InstaFees = new uint256[](length_); - for (uint i = 0; i < length_; i++) { - InstaFees[i] = (_amounts[i] * _BPS) / (10 ** 4); - } - return InstaFees; - } - - /** - * @dev Sort the tokens and amounts arrays according to token addresses. - * @notice Sort the tokens and amounts arrays according to token addresses. - * @param _tokens list of token addresses. - * @param _amounts list of respective amounts. - */ - function bubbleSort(address[] memory _tokens, uint256[] memory _amounts) internal pure returns (address[] memory, uint256[] memory) { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - for( uint256 j = 0; j < _tokens.length - i - 1 ; j++) { - if(_tokens[j] > _tokens[j+1]) { - (_tokens[j], _tokens[j+1], _amounts[j], _amounts[j+1]) = (_tokens[j+1], _tokens[j], _amounts[j+1], _amounts[j]); - } - } - } - return (_tokens, _amounts); - } - /** * @dev Returns to true if the passed address is a DSA else returns false. * @notice Returns to true if the passed address is a DSA else returns false. diff --git a/contracts/aggregator/avalanche/flashloan/implAave/main.sol b/contracts/aggregator/avalanche/flashloan/implAave/main.sol new file mode 100644 index 00000000..7504067f --- /dev/null +++ b/contracts/aggregator/avalanche/flashloan/implAave/main.sol @@ -0,0 +1,91 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; +import "../helpers.sol"; + +contract AaveImplementationAvalanche is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes calldata // kept for future use by instadapp. Currently not used anywhere. + ) external reentrancy { + require(_route == 1, "invalid-AAVE-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + routeAave(_tokens, _amounts, _data); + } + + /** + * @dev Callback function for aave flashloan. + * @notice Callback function for aave flashloan. + * @param _assets list of asset addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets for flashloan. + * @param _premiums list of premiums/fees for the corresponding addresses for flashloan. + * @param _initiator initiator address for flashloan. + * @param _data extra data passed. + */ + function executeOperation( + address[] memory _assets, + uint256[] memory _amounts, + uint256[] memory _premiums, + address _initiator, + bytes memory _data + ) external verifyDataHash(_data) returns (bool) { + require(_initiator == address(this), "not-same-sender"); + require(msg.sender == aaveLendingAddr, "not-aave-sender"); + + FlashloanVariables memory instaLoanVariables_; + + (address sender_, bytes memory data_) = abi.decode( + _data, + (address, bytes) + ); + + instaLoanVariables_._tokens = _assets; + instaLoanVariables_._amounts = _amounts; + instaLoanVariables_._instaFees = calculateFees(_amounts, calculateFeeBPS(1)); + instaLoanVariables_._iniBals = calculateBalances(_assets, address(this)); + + safeApprove(instaLoanVariables_, _premiums, aaveLendingAddr); + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall(sender_, data_, "DSA-flashloan-fallback-failed"); + } else { + InstaFlashReceiverInterface(sender_).executeOperation(_assets, _amounts, instaLoanVariables_._instaFees, sender_, data_); + } + + instaLoanVariables_._finBals = calculateBalances(_assets, address(this)); + validateFlashloan(instaLoanVariables_); + + return true; + } + + /** + * @dev Middle function for route 1. + * @notice Middle function for route 1. + * @param _tokens list of token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. + * @param _data extra data passed. + */ + function routeAave(address[] memory _tokens, uint256[] memory _amounts, bytes memory _data) internal { + bytes memory data_ = abi.encode(msg.sender, _data); + uint length_ = _tokens.length; + uint[] memory _modes = new uint[](length_); + for (uint i = 0; i < length_; i++) { + _modes[i]=0; + } + dataHash = bytes32(keccak256(data_)); + aaveLending.flashLoan(address(this), _tokens, _amounts, _modes, address(0), data_, 3228); + } +} diff --git a/contracts/aggregator/avalanche/flashloan/interfaces.sol b/contracts/aggregator/avalanche/flashloan/interfaces.sol index 5c226c95..61279c6e 100644 --- a/contracts/aggregator/avalanche/flashloan/interfaces.sol +++ b/contracts/aggregator/avalanche/flashloan/interfaces.sol @@ -12,34 +12,6 @@ interface InstaFlashReceiverInterface { ) external returns (bool); } -interface IndexInterface { - function master() external view returns (address); - - function list() external view returns (address); -} - -interface ListInterface { - function accountID(address) external view returns (uint64); -} - -interface TokenInterface { - function approve(address, uint256) external; - - function transfer(address, uint) external; - - function transferFrom(address, address, uint) external; - - function deposit() external payable; - - function withdraw(uint) external; - - function balanceOf(address) external view returns (uint256); - - function decimals() external view returns (uint256); - - function totalSupply() external view returns (uint256); -} - interface IAaveLending { function flashLoan( address receiverAddress, diff --git a/contracts/aggregator/avalanche/flashloan/main.sol b/contracts/aggregator/avalanche/flashloan/main.sol index 18d56664..642a0cc0 100644 --- a/contracts/aggregator/avalanche/flashloan/main.sol +++ b/contracts/aggregator/avalanche/flashloan/main.sol @@ -3,18 +3,9 @@ pragma solidity ^0.8.0; /** * @title Flashloan. - * @dev Flashloan aggregator. + * @dev Flashloan aggregator for Avalanche. */ - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/Address.sol"; -import { Helper } from "./helpers.sol"; - -import { - TokenInterface, - InstaFlashReceiverInterface -} from "./interfaces.sol"; +import "./helpers.sol"; contract FlashAggregatorAvalanche is Helper { using SafeERC20 for IERC20; @@ -41,53 +32,9 @@ contract FlashAggregatorAvalanche is Helper { uint256[] memory _premiums, address _initiator, bytes memory _data - ) external verifyDataHash(_data) returns (bool) { - require(_initiator == address(this), "not-same-sender"); - require(msg.sender == aaveLendingAddr, "not-aave-sender"); - - FlashloanVariables memory instaLoanVariables_; - - (address sender_, bytes memory data_) = abi.decode( - _data, - (address, bytes) - ); - - instaLoanVariables_._tokens = _assets; - instaLoanVariables_._amounts = _amounts; - instaLoanVariables_._instaFees = calculateFees(_amounts, calculateFeeBPS(1)); - instaLoanVariables_._iniBals = calculateBalances(_assets, address(this)); - - safeApprove(instaLoanVariables_, _premiums, aaveLendingAddr); - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall(sender_, data_, "DSA-flashloan-fallback-failed"); - } else { - InstaFlashReceiverInterface(sender_).executeOperation(_assets, _amounts, instaLoanVariables_._instaFees, sender_, data_); - } - - instaLoanVariables_._finBals = calculateBalances(_assets, address(this)); - validateFlashloan(instaLoanVariables_); - - return true; - } - - /** - * @dev Middle function for route 1. - * @notice Middle function for route 1. - * @param _tokens list of token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. - * @param _data extra data passed. - */ - function routeAave(address[] memory _tokens, uint256[] memory _amounts, bytes memory _data) internal { - bytes memory data_ = abi.encode(msg.sender, _data); - uint length_ = _tokens.length; - uint[] memory _modes = new uint[](length_); - for (uint i = 0; i < length_; i++) { - _modes[i]=0; - } - dataHash = bytes32(keccak256(data_)); - aaveLending.flashLoan(address(this), _tokens, _amounts, _modes, address(0), data_, 3228); + ) external returns (bool) { + bytes memory response_ = spell(AAVE_IMPL, msg.data); + return (abi.decode(response_, (bool))); } /** @@ -104,15 +51,14 @@ contract FlashAggregatorAvalanche is Helper { uint256 _route, bytes calldata _data, bytes calldata // kept for future use by instadapp. Currently not used anywhere. - ) external reentrancy { - + ) external { require(_tokens.length == _amounts.length, "array-lengths-not-same"); (_tokens, _amounts) = bubbleSort(_tokens, _amounts); validateTokens(_tokens); if (_route == 1) { - routeAave(_tokens, _amounts, _data); + spell(AAVE_IMPL, msg.data); } else if (_route == 2) { revert("this route is only for mainnet"); } else if (_route == 3) { @@ -125,6 +71,8 @@ contract FlashAggregatorAvalanche is Helper { revert("this route is only for mainnet"); } else if (_route == 7) { revert("this route is only for mainnet and polygon"); + } else if (_route == 8) { + revert("this route is only for arbitrum, polygon and optimism"); } else { revert("route-does-not-exist"); } diff --git a/contracts/aggregator/avalanche/flashloan/variables.sol b/contracts/aggregator/avalanche/flashloan/variables.sol index 4fa2dbc5..9e75fd6a 100644 --- a/contracts/aggregator/avalanche/flashloan/variables.sol +++ b/contracts/aggregator/avalanche/flashloan/variables.sol @@ -1,11 +1,8 @@ //SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; -import { - IndexInterface, - ListInterface, - IAaveLending -} from "./interfaces.sol"; +import "./interfaces.sol"; +import "../../common/interface.sol"; contract ConstantVariables { @@ -34,4 +31,6 @@ contract Variables is ConstantVariables { uint256[] _instaFees; } + address internal AAVE_IMPL; + } \ No newline at end of file diff --git a/contracts/aggregator/common/helpers.sol b/contracts/aggregator/common/helpers.sol new file mode 100644 index 00000000..e1ba1740 --- /dev/null +++ b/contracts/aggregator/common/helpers.sol @@ -0,0 +1,131 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +contract HelpersCommon { + using SafeERC20 for IERC20; + + /** + * @dev Delegate the calls to Connector. + * @param _target Connector address + * @param _data CallData of function. + */ + function spell(address _target, bytes memory _data) internal returns (bytes memory response) { + require(_target != address(0), "target-invalid"); + assembly { + let succeeded := delegatecall(gas(), _target, add(_data, 0x20), mload(_data), 0, 0) + let size := returndatasize() + + response := mload(0x40) + mstore(0x40, add(response, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + mstore(response, size) + returndatacopy(add(response, 0x20), 0, size) + + switch iszero(succeeded) + case 1 { + // throw if delegatecall failed + returndatacopy(0x00, 0x00, size) + revert(0x00, size) + } + } + } + + /** + * @dev Calculates the balances.. + * @notice Calculates the balances of the account passed for the tokens. + * @param _tokens list of token addresses to calculate balance for. + * @param _account account to calculate balance for. + */ + function calculateBalances(address[] memory _tokens, address _account) + internal + view + returns (uint256[] memory) + { + uint256 _length = _tokens.length; + uint256[] memory balances_ = new uint256[](_length); + for (uint256 i = 0; i < _length; i++) { + IERC20 token = IERC20(_tokens[i]); + balances_[i] = token.balanceOf(_account); + } + return balances_; + } + + /** + * @dev Validates if token addresses are unique. Just need to check adjacent tokens as the array was sorted first + * @notice Validates if token addresses are unique. + * @param _tokens list of token addresses. + */ + function validateTokens(address[] memory _tokens) internal pure { + for (uint256 i = 0; i < _tokens.length - 1; i++) { + require(_tokens[i] != _tokens[i + 1], "non-unique-tokens"); + } + } + + /** + * @dev Calculate fees for the respective amounts and fee in BPS passed. + * @notice Calculate fees for the respective amounts and fee in BPS passed. 1 BPS == 0.01%. + * @param _amounts list of amounts. + * @param _BPS fee in BPS. + */ + function calculateFees(uint256[] memory _amounts, uint256 _BPS) + internal + pure + returns (uint256[] memory) + { + uint256 length_ = _amounts.length; + uint256[] memory InstaFees = new uint256[](length_); + for (uint256 i = 0; i < length_; i++) { + InstaFees[i] = (_amounts[i] * _BPS) / (10**4); + } + return InstaFees; + } + + /** + * @dev Sort the tokens and amounts arrays according to token addresses. + * @notice Sort the tokens and amounts arrays according to token addresses. + * @param _tokens list of token addresses. + * @param _amounts list of respective amounts. + */ + function bubbleSort(address[] memory _tokens, uint256[] memory _amounts) + internal + pure + returns (address[] memory, uint256[] memory) + { + for (uint256 i = 0; i < _tokens.length - 1; i++) { + for (uint256 j = 0; j < _tokens.length - i - 1; j++) { + if (_tokens[j] > _tokens[j + 1]) { + ( + _tokens[j], + _tokens[j + 1], + _amounts[j], + _amounts[j + 1] + ) = ( + _tokens[j + 1], + _tokens[j], + _amounts[j + 1], + _amounts[j] + ); + } + } + } + return (_tokens, _amounts); + } + + /** + * @dev Sort the tokens and amounts arrays according to token addresses. + * @notice Sort the tokens and amounts arrays according to token addresses. + * @param _token0 address of token0. + * @param _token1 address of token1. + */ + function sortTokens(address _token0, address _token1) + internal + pure + returns (address, address) + { + if(_token1 < _token0) { + (_token0, _token1) = (_token1, _token0); + } + return (_token0 , _token1); + } +} diff --git a/contracts/aggregator/common/interface.sol b/contracts/aggregator/common/interface.sol new file mode 100644 index 00000000..b800be8a --- /dev/null +++ b/contracts/aggregator/common/interface.sol @@ -0,0 +1,35 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; +pragma experimental ABIEncoderV2; + +interface IndexInterface { + function master() external view returns (address); + + function list() external view returns (address); +} + +interface ListInterface { + function accountID(address) external view returns (uint64); +} + +interface TokenInterface { + function approve(address, uint256) external; + + function transfer(address, uint256) external; + + function transferFrom( + address, + address, + uint256 + ) external; + + function deposit() external payable; + + function withdraw(uint256) external; + + function balanceOf(address) external view returns (uint256); + + function decimals() external view returns (uint256); + + function totalSupply() external view returns (uint256); +} diff --git a/contracts/aggregator/mainnet/flashloan/helpers.sol b/contracts/aggregator/mainnet/flashloan/helpers.sol index ddf5369e..6fb8ae4d 100644 --- a/contracts/aggregator/mainnet/flashloan/helpers.sol +++ b/contracts/aggregator/mainnet/flashloan/helpers.sol @@ -2,9 +2,10 @@ pragma solidity ^0.8.0; import "./variables.sol"; +import "../../common/helpers.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -contract Helper is Variables { +contract Helper is HelpersCommon, Variables { using SafeERC20 for IERC20; /** @@ -13,14 +14,12 @@ contract Helper is Variables { * @param token_ token for which allowance is to be given. * @param spender_ the address to which the allowance is to be given. * @param amount_ amount of token. - */ - function approve( - address token_, - address spender_, - uint256 amount_ - ) internal { + */ + function approve(address token_, address spender_, uint256 amount_) internal { TokenInterface tokenContract_ = TokenInterface(token_); - try tokenContract_.approve(spender_, amount_) {} catch { + try tokenContract_.approve(spender_, amount_) { + + } catch { IERC20 token = IERC20(token_); token.safeApprove(spender_, 0); token.safeApprove(spender_, amount_); @@ -102,26 +101,6 @@ contract Helper is Variables { } } - /** - * @dev Calculates the balances.. - * @notice Calculates the balances of the account passed for the tokens. - * @param _tokens list of token addresses to calculate balance for. - * @param _account account to calculate balance for. - */ - function calculateBalances(address[] memory _tokens, address _account) - internal - view - returns (uint256[] memory) - { - uint256 _length = _tokens.length; - uint256[] memory balances_ = new uint256[](_length); - for (uint256 i = 0; i < _length; i++) { - IERC20 token = IERC20(_tokens[i]); - balances_[i] = token.balanceOf(_account); - } - return balances_; - } - /** * @dev Validates if the receiver sent the correct amounts of funds. * @notice Validates if the receiver sent the correct amounts of funds. @@ -141,17 +120,6 @@ contract Helper is Variables { } } - /** - * @dev Validates if token addresses are unique. Just need to check adjacent tokens as the array was sorted first - * @notice Validates if token addresses are unique. - * @param _tokens list of token addresses. - */ - function validateTokens(address[] memory _tokens) internal pure { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - require(_tokens[i] != _tokens[i + 1], "non-unique-tokens"); - } - } - /** * @dev Supply tokens for the amounts to compound. * @notice Supply tokens for the amounts to compound. @@ -363,56 +331,6 @@ contract Helper is Variables { } } - /** - * @dev Calculate fees for the respective amounts and fee in BPS passed. - * @notice Calculate fees for the respective amounts and fee in BPS passed. 1 BPS == 0.01%. - * @param _amounts list of amounts. - * @param _BPS fee in BPS. - */ - function calculateFees(uint256[] memory _amounts, uint256 _BPS) - internal - pure - returns (uint256[] memory) - { - uint256 length_ = _amounts.length; - uint256[] memory InstaFees = new uint256[](length_); - for (uint256 i = 0; i < length_; i++) { - InstaFees[i] = (_amounts[i] * _BPS) / (10**4); - } - return InstaFees; - } - - /** - * @dev Sort the tokens and amounts arrays according to token addresses. - * @notice Sort the tokens and amounts arrays according to token addresses. - * @param _tokens list of token addresses. - * @param _amounts list of respective amounts. - */ - function bubbleSort(address[] memory _tokens, uint256[] memory _amounts) - internal - pure - returns (address[] memory, uint256[] memory) - { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - for (uint256 j = 0; j < _tokens.length - i - 1; j++) { - if (_tokens[j] > _tokens[j + 1]) { - ( - _tokens[j], - _tokens[j + 1], - _amounts[j], - _amounts[j + 1] - ) = ( - _tokens[j + 1], - _tokens[j], - _amounts[j + 1], - _amounts[j] - ); - } - } - } - return (_tokens, _amounts); - } - /** * @dev Returns to wEth amount to be borrowed. * @notice Returns to wEth amount to be borrowed. diff --git a/contracts/aggregator/mainnet/flashloan/implAave/main.sol b/contracts/aggregator/mainnet/flashloan/implAave/main.sol new file mode 100644 index 00000000..cc14dcd3 --- /dev/null +++ b/contracts/aggregator/mainnet/flashloan/implAave/main.sol @@ -0,0 +1,122 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; +import "../helpers.sol"; + +contract AaveImplementation is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes calldata // kept for future use by instadapp. Currently not used anywhere. + ) external reentrancy { + require(_route == 1, "invalid-AAVE-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + routeAave(_tokens, _amounts, _data); + } + + /** + * @dev Callback function for aave flashloan. + * @notice Callback function for aave flashloan. + * @param _assets list of asset addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets for flashloan. + * @param _premiums list of premiums/fees for the corresponding addresses for flashloan. + * @param _initiator initiator address for flashloan. + * @param _data extra data passed. + */ + function executeOperation( + address[] memory _assets, + uint256[] memory _amounts, + uint256[] memory _premiums, + address _initiator, + bytes memory _data + ) external verifyDataHash(_data) returns (bool) { + require(_initiator == address(this), "not-same-sender"); + require(msg.sender == address(aaveLending), "not-aave-sender"); + + FlashloanVariables memory instaLoanVariables_; + + (address sender_, bytes memory data_) = abi.decode( + _data, + (address, bytes) + ); + + instaLoanVariables_._tokens = _assets; + instaLoanVariables_._amounts = _amounts; + instaLoanVariables_._instaFees = calculateFees( + _amounts, + calculateFeeBPS(1, sender_) + ); + instaLoanVariables_._iniBals = calculateBalances( + _assets, + address(this) + ); + + safeApprove(instaLoanVariables_, _premiums, address(aaveLending)); + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + _assets, + _amounts, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + + instaLoanVariables_._finBals = calculateBalances( + _assets, + address(this) + ); + validateFlashloan(instaLoanVariables_); + + return true; + } + + /** + * @dev Middle function for route 1. + * @notice Middle function for route 1. + * @param _tokens list of token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. + * @param _data extra data passed. + */ + function routeAave( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + bytes memory data_ = abi.encode(msg.sender, _data); + uint256 length_ = _tokens.length; + uint256[] memory _modes = new uint256[](length_); + for (uint256 i = 0; i < length_; i++) { + _modes[i] = 0; + } + dataHash = bytes32(keccak256(data_)); + aaveLending.flashLoan( + address(this), + _tokens, + _amounts, + _modes, + address(0), + data_, + 3228 + ); + } +} diff --git a/contracts/aggregator/mainnet/flashloan/implBalancer/main.sol b/contracts/aggregator/mainnet/flashloan/implBalancer/main.sol new file mode 100644 index 00000000..6ee1f141 --- /dev/null +++ b/contracts/aggregator/mainnet/flashloan/implBalancer/main.sol @@ -0,0 +1,270 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; +import "../helpers.sol"; + +contract BalancerImplementation is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes calldata // kept for future use by instadapp. Currently not used anywhere. + ) external reentrancy { + require(_route == 5 || _route == 6 || _route == 7, "invalid-BALANCER-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + + if (_route == 5) { + routeBalancer(_tokens, _amounts, _data); + } else if (_route == 6) { + routeBalancerCompound(_tokens, _amounts, _data); + } else if (_route == 7) { + routeBalancerAave(_tokens, _amounts, _data); + } + } + + /** + * @dev Fallback function for balancer flashloan. + * @notice Fallback function for balancer flashloan. + * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. + * @param _fees list of fees for the corresponding addresses for flashloan. + * @param _data extra data passed(includes route info aswell). + */ + function receiveFlashLoan( + IERC20[] memory, + uint256[] memory _amounts, + uint256[] memory _fees, + bytes memory _data + ) external verifyDataHash(_data) { + require(msg.sender == address(balancerLending), "not-balancer-sender"); + + FlashloanVariables memory instaLoanVariables_; + + ( + uint256 route_, + address[] memory tokens_, + uint256[] memory amounts_, + address sender_, + bytes memory data_ + ) = abi.decode(_data, (uint256, address[], uint256[], address, bytes)); + + instaLoanVariables_._tokens = tokens_; + instaLoanVariables_._amounts = amounts_; + instaLoanVariables_._iniBals = calculateBalances( + tokens_, + address(this) + ); + instaLoanVariables_._instaFees = calculateFees( + amounts_, + calculateFeeBPS(route_, sender_) + ); + + if (route_ == 5) { + if (tokens_[0] == stEthTokenAddr) { + wstEthToken.unwrap(_amounts[0]); + } + safeTransfer(instaLoanVariables_, sender_); + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + tokens_, + amounts_, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + if (tokens_[0] == stEthTokenAddr) { + wstEthToken.wrap(amounts_[0]); + } + + instaLoanVariables_._finBals = calculateBalances( + tokens_, + address(this) + ); + if (tokens_[0] == stEthTokenAddr) { + // adding 10 wei to avoid any possible decimal errors in final calculations + instaLoanVariables_._finBals[0] = + instaLoanVariables_._finBals[0] + + 10; + instaLoanVariables_._tokens[0] = address(wstEthToken); + instaLoanVariables_._amounts[0] = _amounts[0]; + } + validateFlashloan(instaLoanVariables_); + safeTransferWithFee( + instaLoanVariables_, + _fees, + address(balancerLending) + ); + } else if (route_ == 6 || route_ == 7) { + require(_fees[0] == 0, "flash-ETH-fee-not-0"); + + address[] memory wEthTokenList = new address[](1); + wEthTokenList[0] = address(wethToken); + + if (route_ == 6) { + compoundSupply(wEthTokenList, _amounts); + compoundBorrow(tokens_, amounts_); + } else { + aaveSupply(wEthTokenList, _amounts); + aaveBorrow(tokens_, amounts_); + } + + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + tokens_, + amounts_, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + + if (route_ == 6) { + compoundPayback(tokens_, amounts_); + compoundWithdraw(wEthTokenList, _amounts); + } else { + aavePayback(tokens_, amounts_); + aaveWithdraw(wEthTokenList, _amounts); + } + instaLoanVariables_._finBals = calculateBalances( + tokens_, + address(this) + ); + validateFlashloan(instaLoanVariables_); + instaLoanVariables_._tokens = wEthTokenList; + instaLoanVariables_._amounts = _amounts; + safeTransferWithFee( + instaLoanVariables_, + _fees, + address(balancerLending) + ); + } else { + revert("wrong-route"); + } + } + + /** + * @dev Middle function for route 5. + * @notice Middle function for route 5. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + */ + function routeBalancer( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + uint256 length_ = _tokens.length; + IERC20[] memory tokens_ = new IERC20[](length_); + for (uint256 i = 0; i < length_; i++) { + tokens_[i] = IERC20(_tokens[i]); + } + bytes memory data_ = abi.encode( + 5, + _tokens, + _amounts, + msg.sender, + _data + ); + dataHash = bytes32(keccak256(data_)); + if (_tokens[0] == stEthTokenAddr) { + require(length_ == 1, "steth-length-should-be-1"); + tokens_[0] = IERC20(address(wstEthToken)); + _amounts[0] = wstEthToken.getWstETHByStETH(_amounts[0]); + } + balancerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + tokens_, + _amounts, + data_ + ); + } + + /** + * @dev Middle function for route 6. + * @notice Middle function for route 6. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + */ + function routeBalancerCompound( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + bytes memory data_ = abi.encode( + 6, + _tokens, + _amounts, + msg.sender, + _data + ); + IERC20[] memory wethTokenList_ = new IERC20[](1); + uint256[] memory wethAmountList_ = new uint256[](1); + wethTokenList_[0] = IERC20(wethToken); + wethAmountList_[0] = getWEthBorrowAmount(); + dataHash = bytes32(keccak256(data_)); + balancerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + wethTokenList_, + wethAmountList_, + data_ + ); + } + + /** + * @dev Middle function for route 7. + * @notice Middle function for route 7. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + */ + function routeBalancerAave( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + bytes memory data_ = abi.encode( + 7, + _tokens, + _amounts, + msg.sender, + _data + ); + IERC20[] memory wethTokenList_ = new IERC20[](1); + uint256[] memory wethAmountList_ = new uint256[](1); + wethTokenList_[0] = wethToken; + wethAmountList_[0] = getWEthBorrowAmount(); + dataHash = bytes32(keccak256(data_)); + balancerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + wethTokenList_, + wethAmountList_, + data_ + ); + } +} diff --git a/contracts/aggregator/mainnet/flashloan/implMaker/main.sol b/contracts/aggregator/mainnet/flashloan/implMaker/main.sol new file mode 100644 index 00000000..90c23e4d --- /dev/null +++ b/contracts/aggregator/mainnet/flashloan/implMaker/main.sol @@ -0,0 +1,233 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; +import "../helpers.sol"; + +contract MakerImplementation is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes calldata // kept for future use by instadapp. Currently not used anywhere. + ) external reentrancy { + require((_route == 2 || _route == 3 || _route == 4), "invalid-MAKER-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + + if (_route == 2) { + routeMaker(_tokens[0], _amounts[0], _data); + } else if (_route == 3) { + routeMakerCompound(_tokens, _amounts, _data); + } else if (_route == 4) { + routeMakerAave(_tokens, _amounts, _data); + } + } + + /** + * @dev Fallback function for makerdao flashloan. + * @notice Fallback function for makerdao flashloan. + * @param _initiator initiator address for flashloan. + * @param _amount DAI amount for flashloan. + * @param _fee fee for the flashloan. + * @param _data extra data passed(includes route info aswell). + */ + function onFlashLoan( + address _initiator, + address, + uint256 _amount, + uint256 _fee, + bytes calldata _data + ) external verifyDataHash(_data) returns (bytes32) { + require(_initiator == address(this), "not-same-sender"); + require(msg.sender == address(makerLending), "not-maker-sender"); + + FlashloanVariables memory instaLoanVariables_; + + ( + uint256 route_, + address[] memory tokens_, + uint256[] memory amounts_, + address sender_, + bytes memory data_ + ) = abi.decode(_data, (uint256, address[], uint256[], address, bytes)); + + instaLoanVariables_._tokens = tokens_; + instaLoanVariables_._amounts = amounts_; + instaLoanVariables_._iniBals = calculateBalances( + tokens_, + address(this) + ); + instaLoanVariables_._instaFees = calculateFees( + amounts_, + calculateFeeBPS(route_, sender_) + ); + + if (route_ == 2) { + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + tokens_, + amounts_, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + } else if (route_ == 3 || route_ == 4) { + require(_fee == 0, "flash-DAI-fee-not-0"); + + address[] memory _daiTokenList = new address[](1); + uint256[] memory _daiTokenAmountsList = new uint256[](1); + _daiTokenList[0] = daiTokenAddr; + _daiTokenAmountsList[0] = _amount; + + if (route_ == 3) { + compoundSupply(_daiTokenList, _daiTokenAmountsList); + compoundBorrow(tokens_, amounts_); + } else { + aaveSupply(_daiTokenList, _daiTokenAmountsList); + aaveBorrow(tokens_, amounts_); + } + + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + tokens_, + amounts_, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + + if (route_ == 3) { + compoundPayback(tokens_, amounts_); + compoundWithdraw(_daiTokenList, _daiTokenAmountsList); + } else { + aavePayback(tokens_, amounts_); + aaveWithdraw(_daiTokenList, _daiTokenAmountsList); + } + } else { + revert("wrong-route"); + } + + instaLoanVariables_._finBals = calculateBalances( + tokens_, + address(this) + ); + validateFlashloan(instaLoanVariables_); + + return keccak256("ERC3156FlashBorrower.onFlashLoan"); + } + + /** + * @dev Middle function for route 2. + * @notice Middle function for route 2. + * @param _token token address for flashloan(DAI). + * @param _amount DAI amount for flashloan. + * @param _data extra data passed. + */ + function routeMaker( + address _token, + uint256 _amount, + bytes memory _data + ) internal { + address[] memory tokens_ = new address[](1); + uint256[] memory amounts_ = new uint256[](1); + tokens_[0] = _token; + amounts_[0] = _amount; + bytes memory data_ = abi.encode( + 2, + tokens_, + amounts_, + msg.sender, + _data + ); + dataHash = bytes32(keccak256(data_)); + makerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + _token, + _amount, + data_ + ); + } + + /** + * @dev Middle function for route 3. + * @notice Middle function for route 3. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + */ + function routeMakerCompound( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + bytes memory data_ = abi.encode( + 3, + _tokens, + _amounts, + msg.sender, + _data + ); + dataHash = bytes32(keccak256(data_)); + makerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + daiTokenAddr, + daiBorrowAmount, + data_ + ); + } + + /** + * @dev Middle function for route 4. + * @notice Middle function for route 4. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + */ + function routeMakerAave( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + bytes memory data_ = abi.encode( + 4, + _tokens, + _amounts, + msg.sender, + _data + ); + dataHash = bytes32(keccak256(data_)); + makerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + daiTokenAddr, + daiBorrowAmount, + data_ + ); + } +} \ No newline at end of file diff --git a/contracts/aggregator/mainnet/flashloan/interfaces.sol b/contracts/aggregator/mainnet/flashloan/interfaces.sol index 9516f055..4d3f4d70 100644 --- a/contracts/aggregator/mainnet/flashloan/interfaces.sol +++ b/contracts/aggregator/mainnet/flashloan/interfaces.sol @@ -13,38 +13,6 @@ interface InstaFlashReceiverInterface { ) external returns (bool); } -interface IndexInterface { - function master() external view returns (address); - - function list() external view returns (address); -} - -interface ListInterface { - function accountID(address) external view returns (uint64); -} - -interface TokenInterface { - function approve(address, uint256) external; - - function transfer(address, uint256) external; - - function transferFrom( - address, - address, - uint256 - ) external; - - function deposit() external payable; - - function withdraw(uint256) external; - - function balanceOf(address) external view returns (uint256); - - function decimals() external view returns (uint256); - - function totalSupply() external view returns (uint256); -} - interface CTokenInterface { function mint(uint256) external returns (uint256); diff --git a/contracts/aggregator/mainnet/flashloan/main.sol b/contracts/aggregator/mainnet/flashloan/main.sol index 4c66f5d3..c57a33df 100644 --- a/contracts/aggregator/mainnet/flashloan/main.sol +++ b/contracts/aggregator/mainnet/flashloan/main.sol @@ -9,6 +9,7 @@ pragma solidity ^0.8.0; import "./helpers.sol"; import "@openzeppelin/contracts/utils/Address.sol"; + contract AdminModule is Helper { event updateOwnerLog(address indexed oldOwner, address indexed newOwner); @@ -97,54 +98,9 @@ contract FlashAggregator is Setups { uint256[] memory _premiums, address _initiator, bytes memory _data - ) external verifyDataHash(_data) returns (bool) { - require(_initiator == address(this), "not-same-sender"); - require(msg.sender == address(aaveLending), "not-aave-sender"); - - FlashloanVariables memory instaLoanVariables_; - - (address sender_, bytes memory data_) = abi.decode( - _data, - (address, bytes) - ); - - instaLoanVariables_._tokens = _assets; - instaLoanVariables_._amounts = _amounts; - instaLoanVariables_._instaFees = calculateFees( - _amounts, - calculateFeeBPS(1, sender_) - ); - instaLoanVariables_._iniBals = calculateBalances( - _assets, - address(this) - ); - - safeApprove(instaLoanVariables_, _premiums, address(aaveLending)); - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - _assets, - _amounts, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - - instaLoanVariables_._finBals = calculateBalances( - _assets, - address(this) - ); - validateFlashloan(instaLoanVariables_); - - return true; + ) external returns (bool) { + bytes memory response_ = spell(AAVE_IMPL, msg.data); + return (abi.decode(response_, (bool))); } /** @@ -161,101 +117,9 @@ contract FlashAggregator is Setups { uint256 _amount, uint256 _fee, bytes calldata _data - ) external verifyDataHash(_data) returns (bytes32) { - require(_initiator == address(this), "not-same-sender"); - require(msg.sender == address(makerLending), "not-maker-sender"); - - FlashloanVariables memory instaLoanVariables_; - - ( - uint256 route_, - address[] memory tokens_, - uint256[] memory amounts_, - address sender_, - bytes memory data_ - ) = abi.decode(_data, (uint256, address[], uint256[], address, bytes)); - - instaLoanVariables_._tokens = tokens_; - instaLoanVariables_._amounts = amounts_; - instaLoanVariables_._iniBals = calculateBalances( - tokens_, - address(this) - ); - instaLoanVariables_._instaFees = calculateFees( - amounts_, - calculateFeeBPS(route_, sender_) - ); - - if (route_ == 2) { - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - tokens_, - amounts_, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - } else if (route_ == 3 || route_ == 4) { - require(_fee == 0, "flash-DAI-fee-not-0"); - - address[] memory _daiTokenList = new address[](1); - uint256[] memory _daiTokenAmountsList = new uint256[](1); - _daiTokenList[0] = daiTokenAddr; - _daiTokenAmountsList[0] = _amount; - - if (route_ == 3) { - compoundSupply(_daiTokenList, _daiTokenAmountsList); - compoundBorrow(tokens_, amounts_); - } else { - aaveSupply(_daiTokenList, _daiTokenAmountsList); - aaveBorrow(tokens_, amounts_); - } - - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - tokens_, - amounts_, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - - if (route_ == 3) { - compoundPayback(tokens_, amounts_); - compoundWithdraw(_daiTokenList, _daiTokenAmountsList); - } else { - aavePayback(tokens_, amounts_); - aaveWithdraw(_daiTokenList, _daiTokenAmountsList); - } - } else { - revert("wrong-route"); - } - - instaLoanVariables_._finBals = calculateBalances( - tokens_, - address(this) - ); - validateFlashloan(instaLoanVariables_); - - return keccak256("ERC3156FlashBorrower.onFlashLoan"); + ) external returns (bytes32) { + bytes memory response_ = spell(MAKER_IMPL, msg.data); + return (abi.decode(response_, (bytes32))); } /** @@ -270,346 +134,8 @@ contract FlashAggregator is Setups { uint256[] memory _amounts, uint256[] memory _fees, bytes memory _data - ) external verifyDataHash(_data) { - require(msg.sender == address(balancerLending), "not-balancer-sender"); - - FlashloanVariables memory instaLoanVariables_; - - ( - uint256 route_, - address[] memory tokens_, - uint256[] memory amounts_, - address sender_, - bytes memory data_ - ) = abi.decode(_data, (uint256, address[], uint256[], address, bytes)); - - instaLoanVariables_._tokens = tokens_; - instaLoanVariables_._amounts = amounts_; - instaLoanVariables_._iniBals = calculateBalances( - tokens_, - address(this) - ); - instaLoanVariables_._instaFees = calculateFees( - amounts_, - calculateFeeBPS(route_, sender_) - ); - - if (route_ == 5) { - if (tokens_[0] == stEthTokenAddr) { - wstEthToken.unwrap(_amounts[0]); - } - safeTransfer(instaLoanVariables_, sender_); - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - tokens_, - amounts_, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - if (tokens_[0] == stEthTokenAddr) { - wstEthToken.wrap(amounts_[0]); - } - - instaLoanVariables_._finBals = calculateBalances( - tokens_, - address(this) - ); - if (tokens_[0] == stEthTokenAddr) { - // adding 10 wei to avoid any possible decimal errors in final calculations - instaLoanVariables_._finBals[0] = - instaLoanVariables_._finBals[0] + - 10; - instaLoanVariables_._tokens[0] = address(wstEthToken); - instaLoanVariables_._amounts[0] = _amounts[0]; - } - validateFlashloan(instaLoanVariables_); - safeTransferWithFee( - instaLoanVariables_, - _fees, - address(balancerLending) - ); - } else if (route_ == 6 || route_ == 7) { - require(_fees[0] == 0, "flash-ETH-fee-not-0"); - - address[] memory wEthTokenList = new address[](1); - wEthTokenList[0] = address(wethToken); - - if (route_ == 6) { - compoundSupply(wEthTokenList, _amounts); - compoundBorrow(tokens_, amounts_); - } else { - aaveSupply(wEthTokenList, _amounts); - aaveBorrow(tokens_, amounts_); - } - - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - tokens_, - amounts_, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - - if (route_ == 6) { - compoundPayback(tokens_, amounts_); - compoundWithdraw(wEthTokenList, _amounts); - } else { - aavePayback(tokens_, amounts_); - aaveWithdraw(wEthTokenList, _amounts); - } - instaLoanVariables_._finBals = calculateBalances( - tokens_, - address(this) - ); - validateFlashloan(instaLoanVariables_); - instaLoanVariables_._tokens = wEthTokenList; - instaLoanVariables_._amounts = _amounts; - safeTransferWithFee( - instaLoanVariables_, - _fees, - address(balancerLending) - ); - } else { - revert("wrong-route"); - } - } - - /** - * @dev Middle function for route 1. - * @notice Middle function for route 1. - * @param _tokens list of token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. - * @param _data extra data passed. - */ - function routeAave( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - bytes memory data_ = abi.encode(msg.sender, _data); - uint256 length_ = _tokens.length; - uint256[] memory _modes = new uint256[](length_); - for (uint256 i = 0; i < length_; i++) { - _modes[i] = 0; - } - dataHash = bytes32(keccak256(data_)); - aaveLending.flashLoan( - address(this), - _tokens, - _amounts, - _modes, - address(0), - data_, - 3228 - ); - } - - /** - * @dev Middle function for route 2. - * @notice Middle function for route 2. - * @param _token token address for flashloan(DAI). - * @param _amount DAI amount for flashloan. - * @param _data extra data passed. - */ - function routeMaker( - address _token, - uint256 _amount, - bytes memory _data - ) internal { - address[] memory tokens_ = new address[](1); - uint256[] memory amounts_ = new uint256[](1); - tokens_[0] = _token; - amounts_[0] = _amount; - bytes memory data_ = abi.encode( - 2, - tokens_, - amounts_, - msg.sender, - _data - ); - dataHash = bytes32(keccak256(data_)); - makerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - _token, - _amount, - data_ - ); - } - - /** - * @dev Middle function for route 3. - * @notice Middle function for route 3. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - */ - function routeMakerCompound( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - bytes memory data_ = abi.encode( - 3, - _tokens, - _amounts, - msg.sender, - _data - ); - dataHash = bytes32(keccak256(data_)); - makerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - daiTokenAddr, - daiBorrowAmount, - data_ - ); - } - - /** - * @dev Middle function for route 4. - * @notice Middle function for route 4. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - */ - function routeMakerAave( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - bytes memory data_ = abi.encode( - 4, - _tokens, - _amounts, - msg.sender, - _data - ); - dataHash = bytes32(keccak256(data_)); - makerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - daiTokenAddr, - daiBorrowAmount, - data_ - ); - } - - /** - * @dev Middle function for route 5. - * @notice Middle function for route 5. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - */ - function routeBalancer( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - uint256 length_ = _tokens.length; - IERC20[] memory tokens_ = new IERC20[](length_); - for (uint256 i = 0; i < length_; i++) { - tokens_[i] = IERC20(_tokens[i]); - } - bytes memory data_ = abi.encode( - 5, - _tokens, - _amounts, - msg.sender, - _data - ); - dataHash = bytes32(keccak256(data_)); - if (_tokens[0] == stEthTokenAddr) { - require(length_ == 1, "steth-length-should-be-1"); - tokens_[0] = IERC20(address(wstEthToken)); - _amounts[0] = wstEthToken.getWstETHByStETH(_amounts[0]); - } - balancerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - tokens_, - _amounts, - data_ - ); - } - - /** - * @dev Middle function for route 6. - * @notice Middle function for route 6. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - */ - function routeBalancerCompound( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - bytes memory data_ = abi.encode( - 6, - _tokens, - _amounts, - msg.sender, - _data - ); - IERC20[] memory wethTokenList_ = new IERC20[](1); - uint256[] memory wethAmountList_ = new uint256[](1); - wethTokenList_[0] = IERC20(wethToken); - wethAmountList_[0] = getWEthBorrowAmount(); - dataHash = bytes32(keccak256(data_)); - balancerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - wethTokenList_, - wethAmountList_, - data_ - ); - } - - /** - * @dev Middle function for route 7. - * @notice Middle function for route 7. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - */ - function routeBalancerAave( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - bytes memory data_ = abi.encode( - 7, - _tokens, - _amounts, - msg.sender, - _data - ); - IERC20[] memory wethTokenList_ = new IERC20[](1); - uint256[] memory wethAmountList_ = new uint256[](1); - wethTokenList_[0] = wethToken; - wethAmountList_[0] = getWEthBorrowAmount(); - dataHash = bytes32(keccak256(data_)); - balancerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - wethTokenList_, - wethAmountList_, - data_ - ); + ) external { + spell(BALANCER_IMPL, msg.data); } /** @@ -626,26 +152,23 @@ contract FlashAggregator is Setups { uint256 _route, bytes calldata _data, bytes calldata // kept for future use by instadapp. Currently not used anywhere. - ) external reentrancy { + ) external { require(_tokens.length == _amounts.length, "array-lengths-not-same"); - (_tokens, _amounts) = bubbleSort(_tokens, _amounts); - validateTokens(_tokens); - if (_route == 1) { - routeAave(_tokens, _amounts, _data); + spell(AAVE_IMPL, msg.data); } else if (_route == 2) { - routeMaker(_tokens[0], _amounts[0], _data); + spell(MAKER_IMPL, msg.data); } else if (_route == 3) { - routeMakerCompound(_tokens, _amounts, _data); + spell(MAKER_IMPL, msg.data); } else if (_route == 4) { - routeMakerAave(_tokens, _amounts, _data); + spell(MAKER_IMPL, msg.data); } else if (_route == 5) { - routeBalancer(_tokens, _amounts, _data); + spell(BALANCER_IMPL, msg.data); } else if (_route == 6) { - routeBalancerCompound(_tokens, _amounts, _data); + spell(BALANCER_IMPL, msg.data); } else if (_route == 7) { - routeBalancerAave(_tokens, _amounts, _data); + spell(BALANCER_IMPL, msg.data); } else { revert("route-does-not-exist"); } diff --git a/contracts/aggregator/mainnet/flashloan/variables.sol b/contracts/aggregator/mainnet/flashloan/variables.sol index 61497a81..483b3dbc 100644 --- a/contracts/aggregator/mainnet/flashloan/variables.sol +++ b/contracts/aggregator/mainnet/flashloan/variables.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import "./interfaces.sol"; +import "../../common/interface.sol"; contract ConstantVariables { IWeth internal constant wethToken = @@ -56,4 +57,8 @@ contract Variables is ConstantVariables { uint256 internal ownerStatus; mapping(address => bool) public isWhitelisted; + + address internal AAVE_IMPL; + address internal MAKER_IMPL; + address internal BALANCER_IMPL; } diff --git a/contracts/aggregator/optimism/flashloan/helpers.sol b/contracts/aggregator/optimism/flashloan/helpers.sol index ebb04218..a4d92c3e 100644 --- a/contracts/aggregator/optimism/flashloan/helpers.sol +++ b/contracts/aggregator/optimism/flashloan/helpers.sol @@ -2,9 +2,10 @@ pragma solidity ^0.8.0; import "./variables.sol"; +import "../../common/helpers.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -contract Helper is Variables { +contract Helper is HelpersCommon, Variables { using SafeERC20 for IERC20; /** @@ -102,26 +103,6 @@ contract Helper is Variables { } } - /** - * @dev Calculates the balances.. - * @notice Calculates the balances of the account passed for the tokens. - * @param _tokens list of token addresses to calculate balance for. - * @param _account account to calculate balances for. - */ - function calculateBalances(address[] memory _tokens, address _account) - internal - view - returns (uint256[] memory) - { - uint256 _length = _tokens.length; - uint256[] memory balances_ = new uint256[](_length); - for (uint256 i = 0; i < _length; i++) { - IERC20 token = IERC20(_tokens[i]); - balances_[i] = token.balanceOf(_account); - } - return balances_; - } - /** * @dev Validates if the receiver sent the correct amounts of funds. * @notice Validates if the receiver sent the correct amounts of funds. @@ -141,67 +122,6 @@ contract Helper is Variables { } } - /** - * @dev Validates if token addresses are unique. Just need to check adjacent tokens as the array was sorted first - * @notice Validates if token addresses are unique. - * @param _tokens list of token addresses. - */ - function validateTokens(address[] memory _tokens) internal pure { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - require(_tokens[i] != _tokens[i + 1], "non-unique-tokens"); - } - } - - /** - * @dev Calculate fees for the respective amounts and fee in BPS passed. - * @notice Calculate fees for the respective amounts and fee in BPS passed. 1 BPS == 0.01%. - * @param _amounts list of amounts. - * @param _BPS fee in BPS. - */ - function calculateFees(uint256[] memory _amounts, uint256 _BPS) - internal - pure - returns (uint256[] memory) - { - uint256 length_ = _amounts.length; - uint256[] memory InstaFees = new uint256[](length_); - for (uint256 i = 0; i < length_; i++) { - InstaFees[i] = (_amounts[i] * _BPS) / (10**4); - } - return InstaFees; - } - - /** - * @dev Sort the tokens and amounts arrays according to token addresses. - * @notice Sort the tokens and amounts arrays according to token addresses. - * @param _tokens list of token addresses. - * @param _amounts list of respective amounts. - */ - function bubbleSort(address[] memory _tokens, uint256[] memory _amounts) - internal - pure - returns (address[] memory, uint256[] memory) - { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - for (uint256 j = 0; j < _tokens.length - i - 1; j++) { - if (_tokens[j] > _tokens[j + 1]) { - ( - _tokens[j], - _tokens[j + 1], - _amounts[j], - _amounts[j + 1] - ) = ( - _tokens[j + 1], - _tokens[j], - _amounts[j + 1], - _amounts[j] - ); - } - } - } - return (_tokens, _amounts); - } - /** * @dev Returns to true if the passed address is a DSA else returns false. * @notice Returns to true if the passed address is a DSA else returns false. diff --git a/contracts/aggregator/optimism/flashloan/implUniswap/main.sol b/contracts/aggregator/optimism/flashloan/implUniswap/main.sol new file mode 100644 index 00000000..33c08aa4 --- /dev/null +++ b/contracts/aggregator/optimism/flashloan/implUniswap/main.sol @@ -0,0 +1,177 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../helpers.sol"; + +contract UniswapImplementationOptimism is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes calldata _instadata + ) external reentrancy { + require(_route == 8, "invalid-UNISWAP-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + routeUniswap(_tokens, _amounts, _data, _instadata); + } + + /** + * @dev Middle function for route 8. + * @notice Middle function for route 8. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + * @param _instadata pool key encoded + */ + function routeUniswap( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data, + bytes memory _instadata + ) internal { + PoolKey memory key = abi.decode(_instadata, (PoolKey)); + (key.token0, key.token1) = sortTokens(key.token0, key.token1); + + uint256 amount0_; + uint256 amount1_; + + if (_tokens.length == 1) { + require( + (_tokens[0] == key.token0 || _tokens[0] == key.token1), + "tokens-do-not-match-pool" + ); + if (_tokens[0] == key.token0) { + amount0_ = _amounts[0]; + } else { + amount1_ = _amounts[0]; + } + } else if (_tokens.length == 2) { + require( + (_tokens[0] == key.token0 && _tokens[1] == key.token1), + "tokens-do-not-match-pool" + ); + amount0_ = _amounts[0]; + amount1_ = _amounts[1]; + } else { + revert("Number of tokens do not match"); + } + + IUniswapV3Pool pool = IUniswapV3Pool( + computeAddress(uniswapFactoryAddr, key) + ); + + bytes memory data_ = abi.encode( + _tokens, + _amounts, + msg.sender, + key, + _data + ); + dataHash = bytes32(keccak256(data_)); + pool.flash(address(this), amount0_, amount1_, data_); + } + + struct UniswapFlashInfo { + address sender; + PoolKey key; + bytes data; + } + + /** + * @dev Callback function for uniswap flashloan. + * @notice Callback function for uniswap flashloan. + * @param fee0 The fee from calling flash for token0 + * @param fee1 The fee from calling flash for token1 + * @param data extra data passed(includes route info aswell). + */ + function uniswapV3FlashCallback( + uint256 fee0, + uint256 fee1, + bytes memory data + ) external verifyDataHash(data) { + FlashloanVariables memory instaLoanVariables_; + UniswapFlashInfo memory uniswapFlashData_; + ( + instaLoanVariables_._tokens, + instaLoanVariables_._amounts, + uniswapFlashData_.sender, + uniswapFlashData_.key, + uniswapFlashData_.data + ) = abi.decode(data, (address[], uint256[], address, PoolKey, bytes)); + + address pool = computeAddress( + uniswapFactoryAddr, + uniswapFlashData_.key + ); + require(msg.sender == pool, "invalid-sender"); + instaLoanVariables_._iniBals = calculateBalances( + instaLoanVariables_._tokens, + address(this) + ); + + uint256 feeBPS = uint256(uniswapFlashData_.key.fee / 100); + if (feeBPS < InstaFeeBPS) { + feeBPS = InstaFeeBPS; + } + + instaLoanVariables_._instaFees = calculateFees( + instaLoanVariables_._amounts, + feeBPS + ); + + safeTransfer(instaLoanVariables_, uniswapFlashData_.sender); + + if (checkIfDsa(uniswapFlashData_.sender)) { + Address.functionCall( + uniswapFlashData_.sender, + uniswapFlashData_.data, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(uniswapFlashData_.sender) + .executeOperation( + instaLoanVariables_._tokens, + instaLoanVariables_._amounts, + instaLoanVariables_._instaFees, + uniswapFlashData_.sender, + uniswapFlashData_.data + ); + } + + instaLoanVariables_._finBals = calculateBalances( + instaLoanVariables_._tokens, + address(this) + ); + + validateFlashloan(instaLoanVariables_); + uint256[] memory fees_; + if (instaLoanVariables_._tokens.length == 2) { + fees_ = new uint256[](2); + fees_[0] = fee0; + fees_[1] = fee1; + } else if ( + instaLoanVariables_._tokens[0] == uniswapFlashData_.key.token0 + ) { + fees_ = new uint256[](1); + fees_[0] = fee0; + } else { + fees_ = new uint256[](1); + fees_[0] = fee1; + } + safeTransferWithFee(instaLoanVariables_, fees_, msg.sender); + } + + + +} \ No newline at end of file diff --git a/contracts/aggregator/optimism/flashloan/interfaces.sol b/contracts/aggregator/optimism/flashloan/interfaces.sol index 0a8c4c3d..5e63eebb 100644 --- a/contracts/aggregator/optimism/flashloan/interfaces.sol +++ b/contracts/aggregator/optimism/flashloan/interfaces.sol @@ -12,38 +12,6 @@ interface InstaFlashReceiverInterface { ) external returns (bool); } -interface IndexInterface { - function master() external view returns (address); - - function list() external view returns (address); -} - -interface ListInterface { - function accountID(address) external view returns (uint64); -} - -interface TokenInterface { - function approve(address, uint256) external; - - function transfer(address, uint256) external; - - function transferFrom( - address, - address, - uint256 - ) external; - - function deposit() external payable; - - function withdraw(uint256) external; - - function balanceOf(address) external view returns (uint256); - - function decimals() external view returns (uint256); - - function totalSupply() external view returns (uint256); -} - interface IUniswapV3Pool { function flash( address recipient, diff --git a/contracts/aggregator/optimism/flashloan/main.sol b/contracts/aggregator/optimism/flashloan/main.sol index 3198ed3b..6a91dc5f 100644 --- a/contracts/aggregator/optimism/flashloan/main.sol +++ b/contracts/aggregator/optimism/flashloan/main.sol @@ -31,132 +31,8 @@ contract FlashAggregatorOptimism is Helper { uint256 fee0, uint256 fee1, bytes memory data - ) external verifyDataHash(data) { - FlashloanVariables memory instaLoanVariables_; - UniswapFlashInfo memory uniswapFlashData_; - ( - instaLoanVariables_._tokens, - instaLoanVariables_._amounts, - uniswapFlashData_.sender, - uniswapFlashData_.key, - uniswapFlashData_.data - ) = abi.decode(data, (address[], uint256[], address, PoolKey, bytes)); - - address pool = computeAddress( - uniswapFactoryAddr, - uniswapFlashData_.key - ); - require(msg.sender == pool, "invalid-sender"); - instaLoanVariables_._iniBals = calculateBalances( - instaLoanVariables_._tokens, - address(this) - ); - - uint256 feeBPS = uint256(uniswapFlashData_.key.fee / 100); - if (feeBPS < InstaFeeBPS) { - feeBPS = InstaFeeBPS; - } - - instaLoanVariables_._instaFees = calculateFees( - instaLoanVariables_._amounts, - feeBPS - ); - - safeTransfer(instaLoanVariables_, uniswapFlashData_.sender); - - if (checkIfDsa(uniswapFlashData_.sender)) { - Address.functionCall( - uniswapFlashData_.sender, - uniswapFlashData_.data, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(uniswapFlashData_.sender) - .executeOperation( - instaLoanVariables_._tokens, - instaLoanVariables_._amounts, - instaLoanVariables_._instaFees, - uniswapFlashData_.sender, - uniswapFlashData_.data - ); - } - - instaLoanVariables_._finBals = calculateBalances( - instaLoanVariables_._tokens, - address(this) - ); - - validateFlashloan(instaLoanVariables_); - uint256[] memory fees_; - if (instaLoanVariables_._tokens.length == 2) { - fees_ = new uint256[](2); - fees_[0] = fee0; - fees_[1] = fee1; - } else if ( - instaLoanVariables_._tokens[0] == uniswapFlashData_.key.token0 - ) { - fees_ = new uint256[](1); - fees_[0] = fee0; - } else { - fees_ = new uint256[](1); - fees_[0] = fee1; - } - safeTransferWithFee(instaLoanVariables_, fees_, msg.sender); - } - - /** - * @dev Middle function for route 8. - * @notice Middle function for route 8. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - * @param _instadata pool key encoded - */ - function routeUniswap( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data, - bytes memory _instadata - ) internal { - PoolKey memory key = abi.decode(_instadata, (PoolKey)); - - uint256 amount0_; - uint256 amount1_; - - if (_tokens.length == 1) { - require( - (_tokens[0] == key.token0 || _tokens[0] == key.token1), - "tokens-do-not-match-pool" - ); - if (_tokens[0] == key.token0) { - amount0_ = _amounts[0]; - } else { - amount1_ = _amounts[0]; - } - } else if (_tokens.length == 2) { - require( - (_tokens[0] == key.token0 && _tokens[1] == key.token1), - "tokens-do-not-match-pool" - ); - amount0_ = _amounts[0]; - amount1_ = _amounts[1]; - } else { - revert("Number of tokens do not match"); - } - - IUniswapV3Pool pool = IUniswapV3Pool( - computeAddress(uniswapFactoryAddr, key) - ); - - bytes memory data_ = abi.encode( - _tokens, - _amounts, - msg.sender, - key, - _data - ); - dataHash = bytes32(keccak256(data_)); - pool.flash(address(this), amount0_, amount1_, data_); + ) external { + spell(UNISWAP_IMPL, msg.data); } /** @@ -173,17 +49,9 @@ contract FlashAggregatorOptimism is Helper { uint256 _route, bytes calldata _data, bytes calldata _instadata - ) external reentrancy { + ) external { require(_tokens.length == _amounts.length, "array-lengths-not-same"); - - (_tokens, _amounts) = bubbleSort(_tokens, _amounts); - validateTokens(_tokens); - - if (_route == 8) { - routeUniswap(_tokens, _amounts, _data, _instadata); - } else { - revert("route-does-not-exist"); - } + spell(UNISWAP_IMPL, msg.data); emit LogFlashloan(msg.sender, _route, _tokens, _amounts); } @@ -221,10 +89,17 @@ contract FlashAggregatorOptimism is Helper { } contract InstaFlashAggregatorOptimism is FlashAggregatorOptimism { - function initialize() public { - require(status == 0, "cannot-call-again"); - status = 1; - } + // function initialize() public { + // require(status == 0, "cannot-call-again"); + // status = 1; + // } + + /** + * @dev Function created for testing upgradable implementations + */ + // function initialize(address uniswap) public { + // UNISWAP_IMPL = uniswap; + // } receive() external payable {} } diff --git a/contracts/aggregator/optimism/flashloan/variables.sol b/contracts/aggregator/optimism/flashloan/variables.sol index 0cd3b06e..6541ae2a 100644 --- a/contracts/aggregator/optimism/flashloan/variables.sol +++ b/contracts/aggregator/optimism/flashloan/variables.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import "./interfaces.sol"; +import "../../common/interface.sol"; contract ConstantVariables { address public constant treasuryAddr = @@ -37,4 +38,6 @@ contract Variables is ConstantVariables { address token1; uint24 fee; } + + address internal UNISWAP_IMPL; } diff --git a/contracts/aggregator/polygon/flashloan/helpers.sol b/contracts/aggregator/polygon/flashloan/helpers.sol index 2f18ce0d..d1eeb83f 100644 --- a/contracts/aggregator/polygon/flashloan/helpers.sol +++ b/contracts/aggregator/polygon/flashloan/helpers.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.0; import "./variables.sol"; +import "../../common/helpers.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -contract Helper is Variables { +contract Helper is HelpersCommon, Variables { using SafeERC20 for IERC20; /** @@ -103,26 +104,6 @@ contract Helper is Variables { } } - /** - * @dev Calculates the balances.. - * @notice Calculates the balances of the account passed for the tokens. - * @param _tokens list of token addresses to calculate balance for. - * @param _account account to calculate balance for. - */ - function calculateBalances(address[] memory _tokens, address _account) - internal - view - returns (uint256[] memory) - { - uint256 _length = _tokens.length; - uint256[] memory balances_ = new uint256[](_length); - for (uint256 i = 0; i < _length; i++) { - IERC20 token = IERC20(_tokens[i]); - balances_[i] = token.balanceOf(_account); - } - return balances_; - } - /** * @dev Validates if the receiver sent the correct amounts of funds. * @notice Validates if the receiver sent the correct amounts of funds. @@ -142,17 +123,6 @@ contract Helper is Variables { } } - /** - * @dev Validates if token addresses are unique. Just need to check adjacent tokens as the array was sorted first - * @notice Validates if token addresses are unique. - * @param _tokens list of token addresses. - */ - function validateTokens(address[] memory _tokens) internal pure { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - require(_tokens[i] != _tokens[i + 1], "non-unique-tokens"); - } - } - /** * @dev Supply tokens to aave. * @notice Supply tokens to aave. @@ -249,56 +219,6 @@ contract Helper is Variables { } } - /** - * @dev Calculate fees for the respective amounts and fee in BPS passed. - * @notice Calculate fees for the respective amounts and fee in BPS passed. 1 BPS == 0.01%. - * @param _amounts list of amounts. - * @param _BPS fee in BPS. - */ - function calculateFees(uint256[] memory _amounts, uint256 _BPS) - internal - pure - returns (uint256[] memory) - { - uint256 length_ = _amounts.length; - uint256[] memory InstaFees = new uint256[](length_); - for (uint256 i = 0; i < length_; i++) { - InstaFees[i] = (_amounts[i] * _BPS) / (10**4); - } - return InstaFees; - } - - /** - * @dev Sort the tokens and amounts arrays according to token addresses. - * @notice Sort the tokens and amounts arrays according to token addresses. - * @param _tokens list of token addresses. - * @param _amounts list of respective amounts. - */ - function bubbleSort(address[] memory _tokens, uint256[] memory _amounts) - internal - pure - returns (address[] memory, uint256[] memory) - { - for (uint256 i = 0; i < _tokens.length - 1; i++) { - for (uint256 j = 0; j < _tokens.length - i - 1; j++) { - if (_tokens[j] > _tokens[j + 1]) { - ( - _tokens[j], - _tokens[j + 1], - _amounts[j], - _amounts[j + 1] - ) = ( - _tokens[j + 1], - _tokens[j], - _amounts[j + 1], - _amounts[j] - ); - } - } - } - return (_tokens, _amounts); - } - /** * @dev Returns to wEth amount to be borrowed. * @notice Returns to wEth amount to be borrowed. diff --git a/contracts/aggregator/polygon/flashloan/implAave/main.sol b/contracts/aggregator/polygon/flashloan/implAave/main.sol new file mode 100644 index 00000000..8ceb737b --- /dev/null +++ b/contracts/aggregator/polygon/flashloan/implAave/main.sol @@ -0,0 +1,124 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../helpers.sol"; + +contract AaveImplementationPolygon is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes calldata _instadata + ) external reentrancy { + require(_route == 1, "invalid-AAVE-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + routeAave(_tokens, _amounts, _data); + } + + /** + * @dev Callback function for aave flashloan. + * @notice Callback function for aave flashloan. + * @param _assets list of asset addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets for flashloan. + * @param _premiums list of premiums/fees for the corresponding addresses for flashloan. + * @param _initiator initiator address for flashloan. + * @param _data extra data passed. + */ + function executeOperation( + address[] memory _assets, + uint256[] memory _amounts, + uint256[] memory _premiums, + address _initiator, + bytes memory _data + ) external verifyDataHash(_data) returns (bool) { + require(_initiator == address(this), "not-same-sender"); + require(msg.sender == aaveLendingAddr, "not-aave-sender"); + + FlashloanVariables memory instaLoanVariables_; + + (address sender_, bytes memory data_) = abi.decode( + _data, + (address, bytes) + ); + + instaLoanVariables_._tokens = _assets; + instaLoanVariables_._amounts = _amounts; + instaLoanVariables_._instaFees = calculateFees( + _amounts, + calculateFeeBPS(1) + ); + instaLoanVariables_._iniBals = calculateBalances( + _assets, + address(this) + ); + + safeApprove(instaLoanVariables_, _premiums, aaveLendingAddr); + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + _assets, + _amounts, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + + instaLoanVariables_._finBals = calculateBalances( + _assets, + address(this) + ); + validateFlashloan(instaLoanVariables_); + + return true; + } + + /** + * @dev Middle function for route 1. + * @notice Middle function for route 1. + * @param _tokens list of token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. + * @param _data extra data passed. + */ + function routeAave( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + bytes memory data_ = abi.encode(msg.sender, _data); + uint256 length_ = _tokens.length; + uint256[] memory _modes = new uint256[](length_); + for (uint256 i = 0; i < length_; i++) { + _modes[i] = 0; + } + dataHash = bytes32(keccak256(data_)); + aaveLending.flashLoan( + address(this), + _tokens, + _amounts, + _modes, + address(0), + data_, + 3228 + ); + } + +} \ No newline at end of file diff --git a/contracts/aggregator/polygon/flashloan/implBalancer/main.sol b/contracts/aggregator/polygon/flashloan/implBalancer/main.sol new file mode 100644 index 00000000..e2cd6573 --- /dev/null +++ b/contracts/aggregator/polygon/flashloan/implBalancer/main.sol @@ -0,0 +1,209 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../helpers.sol"; + +contract BalancerImplementationPolygon is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes calldata _instadata + ) external reentrancy { + require(_route == 5 || _route == 7, "invalid-BALANCER-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + + if (_route == 5) { + routeBalancer(_tokens, _amounts, _data); + } else if (_route == 7) { + routeBalancerAave(_tokens, _amounts, _data); + } + } + + /** + * @dev Callback function for balancer flashloan. + * @notice Callback function for balancer flashloan. + * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. + * @param _fees list of fees for the corresponding addresses for flashloan. + * @param _data extra data passed(includes route info aswell). + */ + function receiveFlashLoan( + IERC20[] memory, + uint256[] memory _amounts, + uint256[] memory _fees, + bytes memory _data + ) external verifyDataHash(_data) { + require(msg.sender == balancerLendingAddr, "not-balancer-sender"); + + FlashloanVariables memory instaLoanVariables_; + + ( + uint256 route_, + address[] memory tokens_, + uint256[] memory amounts_, + address sender_, + bytes memory data_ + ) = abi.decode(_data, (uint256, address[], uint256[], address, bytes)); + + instaLoanVariables_._tokens = tokens_; + instaLoanVariables_._amounts = amounts_; + instaLoanVariables_._iniBals = calculateBalances( + tokens_, + address(this) + ); + instaLoanVariables_._instaFees = calculateFees( + amounts_, + calculateFeeBPS(route_) + ); + + if (route_ == 5) { + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + tokens_, + amounts_, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + + instaLoanVariables_._finBals = calculateBalances( + tokens_, + address(this) + ); + validateFlashloan(instaLoanVariables_); + safeTransferWithFee( + instaLoanVariables_, + _fees, + balancerLendingAddr + ); + } else if (route_ == 7) { + require(_fees[0] == 0, "flash-ETH-fee-not-0"); + + address[] memory wEthTokenList = new address[](1); + wEthTokenList[0] = wEthToken; + + aaveSupply(wEthTokenList, _amounts); + aaveBorrow(tokens_, amounts_); + safeTransfer(instaLoanVariables_, sender_); + + if (checkIfDsa(sender_)) { + Address.functionCall( + sender_, + data_, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(sender_).executeOperation( + tokens_, + amounts_, + instaLoanVariables_._instaFees, + sender_, + data_ + ); + } + + aavePayback(tokens_, amounts_); + aaveWithdraw(wEthTokenList, _amounts); + instaLoanVariables_._finBals = calculateBalances( + tokens_, + address(this) + ); + validateFlashloan(instaLoanVariables_); + instaLoanVariables_._amounts = _amounts; + instaLoanVariables_._tokens = wEthTokenList; + safeTransferWithFee( + instaLoanVariables_, + _fees, + balancerLendingAddr + ); + } else { + revert("wrong-route"); + } + } + + /** + * @dev Middle function for route 5. + * @notice Middle function for route 5. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + */ + function routeBalancer( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + uint256 length_ = _tokens.length; + IERC20[] memory tokens_ = new IERC20[](length_); + for (uint256 i = 0; i < length_; i++) { + tokens_[i] = IERC20(_tokens[i]); + } + bytes memory data_ = abi.encode( + 5, + _tokens, + _amounts, + msg.sender, + _data + ); + dataHash = bytes32(keccak256(data_)); + balancerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + tokens_, + _amounts, + data_ + ); + } + + /** + * @dev Middle function for route 7. + * @notice Middle function for route 7. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + */ + function routeBalancerAave( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data + ) internal { + bytes memory data_ = abi.encode( + 7, + _tokens, + _amounts, + msg.sender, + _data + ); + IERC20[] memory wethTokenList_ = new IERC20[](1); + uint256[] memory wethAmountList_ = new uint256[](1); + wethTokenList_[0] = IERC20(wEthToken); + wethAmountList_[0] = getWEthBorrowAmount(); + dataHash = bytes32(keccak256(data_)); + balancerLending.flashLoan( + InstaFlashReceiverInterface(address(this)), + wethTokenList_, + wethAmountList_, + data_ + ); + } + +} \ No newline at end of file diff --git a/contracts/aggregator/polygon/flashloan/implUniswap/main.sol b/contracts/aggregator/polygon/flashloan/implUniswap/main.sol new file mode 100644 index 00000000..d807ecad --- /dev/null +++ b/contracts/aggregator/polygon/flashloan/implUniswap/main.sol @@ -0,0 +1,178 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../helpers.sol"; + +contract UniswapImplementationPolygon is Helper { + + /** + * @dev Main function for flashloan for all routes. Calls the middle functions according to routes. + * @notice Main function for flashloan for all routes. Calls the middle functions according to routes. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _route route for flashloan. + * @param _data extra data passed. + */ + function flashLoan( + address[] memory _tokens, + uint256[] memory _amounts, + uint256 _route, + bytes calldata _data, + bytes calldata _instadata + ) external reentrancy { + require(_route == 8, "invalid-UNISWAP-route"); + (_tokens, _amounts) = bubbleSort(_tokens, _amounts); + validateTokens(_tokens); + routeUniswap(_tokens, _amounts, _data, _instadata); + } + + struct UniswapFlashInfo { + address sender; + PoolKey key; + bytes data; + } + + /** + * @dev Callback function for uniswap flashloan. + * @notice Callback function for uniswap flashloan. + * @param fee0 The fee from calling flash for token0 + * @param fee1 The fee from calling flash for token1 + * @param data extra data passed(includes route info aswell). + */ + function uniswapV3FlashCallback( + uint256 fee0, + uint256 fee1, + bytes memory data + ) external verifyDataHash(data) { + FlashloanVariables memory instaLoanVariables_; + UniswapFlashInfo memory uniswapFlashData_; + + ( + instaLoanVariables_._tokens, + instaLoanVariables_._amounts, + uniswapFlashData_.sender, + uniswapFlashData_.key, + uniswapFlashData_.data + ) = abi.decode(data, (address[], uint256[], address, PoolKey, bytes)); + + address pool = computeAddress( + uniswapFactoryAddr, + uniswapFlashData_.key + ); + require(msg.sender == pool, "invalid-sender"); + + instaLoanVariables_._iniBals = calculateBalances( + instaLoanVariables_._tokens, + address(this) + ); + + uint256 feeBPS = uint256(uniswapFlashData_.key.fee / 100); + if (feeBPS < InstaFeeBPS) { + feeBPS = InstaFeeBPS; + } + + instaLoanVariables_._instaFees = calculateFees( + instaLoanVariables_._amounts, + feeBPS + ); + + safeTransfer(instaLoanVariables_, uniswapFlashData_.sender); + + if (checkIfDsa(uniswapFlashData_.sender)) { + Address.functionCall( + uniswapFlashData_.sender, + uniswapFlashData_.data, + "DSA-flashloan-fallback-failed" + ); + } else { + InstaFlashReceiverInterface(uniswapFlashData_.sender) + .executeOperation( + instaLoanVariables_._tokens, + instaLoanVariables_._amounts, + instaLoanVariables_._instaFees, + uniswapFlashData_.sender, + uniswapFlashData_.data + ); + } + + instaLoanVariables_._finBals = calculateBalances( + instaLoanVariables_._tokens, + address(this) + ); + + validateFlashloan(instaLoanVariables_); + + uint256[] memory fees_; + if (instaLoanVariables_._tokens.length == 2) { + fees_ = new uint256[](2); + fees_[0] = fee0; + fees_[1] = fee1; + } else if ( + instaLoanVariables_._tokens[0] == uniswapFlashData_.key.token0 + ) { + fees_ = new uint256[](1); + fees_[0] = fee0; + } else { + fees_ = new uint256[](1); + fees_[0] = fee1; + } + safeTransferWithFee(instaLoanVariables_, fees_, msg.sender); + } + + /** + * @dev Middle function for route 8. + * @notice Middle function for route 8. + * @param _tokens token addresses for flashloan. + * @param _amounts list of amounts for the corresponding assets. + * @param _data extra data passed. + *@param _instadata pool key encoded + */ + function routeUniswap( + address[] memory _tokens, + uint256[] memory _amounts, + bytes memory _data, + bytes memory _instadata + ) internal { + PoolKey memory key = abi.decode(_instadata, (PoolKey)); + (key.token0, key.token1) = sortTokens(key.token0, key.token1); + + uint256 amount0_; + uint256 amount1_; + + if (_tokens.length == 1) { + require( + (_tokens[0] == key.token0 ), + "tokens-do-not-match-pool" + ); + if (_tokens[0] == key.token0) { + amount0_ = _amounts[0]; + } else { + amount1_ = _amounts[0]; + } + } else if (_tokens.length == 2) { + require( + (_tokens[0] == key.token0 && _tokens[1] == key.token1), + "tokens-do-not-match-pool" + ); + amount0_ = _amounts[0]; + amount1_ = _amounts[1]; + } else { + revert("Number of tokens do not match"); + } + + IUniswapV3Pool pool = IUniswapV3Pool( + computeAddress(uniswapFactoryAddr, key) + ); + + bytes memory data_ = abi.encode( + _tokens, + _amounts, + msg.sender, + key, + _data + ); + dataHash = bytes32(keccak256(data_)); + pool.flash(address(this), amount0_, amount1_, data_); + } + +} \ No newline at end of file diff --git a/contracts/aggregator/polygon/flashloan/interfaces.sol b/contracts/aggregator/polygon/flashloan/interfaces.sol index 866c7d12..94cae8b6 100644 --- a/contracts/aggregator/polygon/flashloan/interfaces.sol +++ b/contracts/aggregator/polygon/flashloan/interfaces.sol @@ -12,38 +12,6 @@ interface InstaFlashReceiverInterface { ) external returns (bool); } -interface IndexInterface { - function master() external view returns (address); - - function list() external view returns (address); -} - -interface ListInterface { - function accountID(address) external view returns (uint64); -} - -interface TokenInterface { - function approve(address, uint256) external; - - function transfer(address, uint256) external; - - function transferFrom( - address, - address, - uint256 - ) external; - - function deposit() external payable; - - function withdraw(uint256) external; - - function balanceOf(address) external view returns (uint256); - - function decimals() external view returns (uint256); - - function totalSupply() external view returns (uint256); -} - interface IAaveLending { function flashLoan( address receiverAddress, diff --git a/contracts/aggregator/polygon/flashloan/main.sol b/contracts/aggregator/polygon/flashloan/main.sol index b4323e61..61a642a8 100644 --- a/contracts/aggregator/polygon/flashloan/main.sol +++ b/contracts/aggregator/polygon/flashloan/main.sol @@ -1,6 +1,11 @@ //SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +/** + * @title Flashloan. + * @dev Flashloan aggregator for Polygon. + */ + import "./helpers.sol"; import "@openzeppelin/contracts/utils/Address.sol"; @@ -29,54 +34,9 @@ contract FlashAggregatorPolygon is Helper { uint256[] memory _premiums, address _initiator, bytes memory _data - ) external verifyDataHash(_data) returns (bool) { - require(_initiator == address(this), "not-same-sender"); - require(msg.sender == aaveLendingAddr, "not-aave-sender"); - - FlashloanVariables memory instaLoanVariables_; - - (address sender_, bytes memory data_) = abi.decode( - _data, - (address, bytes) - ); - - instaLoanVariables_._tokens = _assets; - instaLoanVariables_._amounts = _amounts; - instaLoanVariables_._instaFees = calculateFees( - _amounts, - calculateFeeBPS(1) - ); - instaLoanVariables_._iniBals = calculateBalances( - _assets, - address(this) - ); - - safeApprove(instaLoanVariables_, _premiums, aaveLendingAddr); - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - _assets, - _amounts, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - - instaLoanVariables_._finBals = calculateBalances( - _assets, - address(this) - ); - validateFlashloan(instaLoanVariables_); - - return true; + ) external returns (bool) { + bytes memory response_ = spell(AAVE_IMPL, msg.data); + return (abi.decode(response_, (bool))); } /** @@ -91,108 +51,8 @@ contract FlashAggregatorPolygon is Helper { uint256[] memory _amounts, uint256[] memory _fees, bytes memory _data - ) external verifyDataHash(_data) { - require(msg.sender == balancerLendingAddr, "not-balancer-sender"); - - FlashloanVariables memory instaLoanVariables_; - - ( - uint256 route_, - address[] memory tokens_, - uint256[] memory amounts_, - address sender_, - bytes memory data_ - ) = abi.decode(_data, (uint256, address[], uint256[], address, bytes)); - - instaLoanVariables_._tokens = tokens_; - instaLoanVariables_._amounts = amounts_; - instaLoanVariables_._iniBals = calculateBalances( - tokens_, - address(this) - ); - instaLoanVariables_._instaFees = calculateFees( - amounts_, - calculateFeeBPS(route_) - ); - - if (route_ == 5) { - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - tokens_, - amounts_, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - - instaLoanVariables_._finBals = calculateBalances( - tokens_, - address(this) - ); - validateFlashloan(instaLoanVariables_); - safeTransferWithFee( - instaLoanVariables_, - _fees, - balancerLendingAddr - ); - } else if (route_ == 7) { - require(_fees[0] == 0, "flash-ETH-fee-not-0"); - - address[] memory wEthTokenList = new address[](1); - wEthTokenList[0] = wEthToken; - - aaveSupply(wEthTokenList, _amounts); - aaveBorrow(tokens_, amounts_); - safeTransfer(instaLoanVariables_, sender_); - - if (checkIfDsa(sender_)) { - Address.functionCall( - sender_, - data_, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(sender_).executeOperation( - tokens_, - amounts_, - instaLoanVariables_._instaFees, - sender_, - data_ - ); - } - - aavePayback(tokens_, amounts_); - aaveWithdraw(wEthTokenList, _amounts); - instaLoanVariables_._finBals = calculateBalances( - tokens_, - address(this) - ); - validateFlashloan(instaLoanVariables_); - instaLoanVariables_._amounts = _amounts; - instaLoanVariables_._tokens = wEthTokenList; - safeTransferWithFee( - instaLoanVariables_, - _fees, - balancerLendingAddr - ); - } else { - revert("wrong-route"); - } - } - - struct UniswapFlashInfo { - address sender; - PoolKey key; - bytes data; + ) external { + spell(BALANCER_IMPL, msg.data); } /** @@ -206,230 +66,8 @@ contract FlashAggregatorPolygon is Helper { uint256 fee0, uint256 fee1, bytes memory data - ) external verifyDataHash(data) { - FlashloanVariables memory instaLoanVariables_; - UniswapFlashInfo memory uniswapFlashData_; - - ( - instaLoanVariables_._tokens, - instaLoanVariables_._amounts, - uniswapFlashData_.sender, - uniswapFlashData_.key, - uniswapFlashData_.data - ) = abi.decode(data, (address[], uint256[], address, PoolKey, bytes)); - - address pool = computeAddress( - uniswapFactoryAddr, - uniswapFlashData_.key - ); - require(msg.sender == pool, "invalid-sender"); - - instaLoanVariables_._iniBals = calculateBalances( - instaLoanVariables_._tokens, - address(this) - ); - - uint256 feeBPS = uint256(uniswapFlashData_.key.fee / 100); - if (feeBPS < InstaFeeBPS) { - feeBPS = InstaFeeBPS; - } - - instaLoanVariables_._instaFees = calculateFees( - instaLoanVariables_._amounts, - feeBPS - ); - - safeTransfer(instaLoanVariables_, uniswapFlashData_.sender); - - if (checkIfDsa(uniswapFlashData_.sender)) { - Address.functionCall( - uniswapFlashData_.sender, - uniswapFlashData_.data, - "DSA-flashloan-fallback-failed" - ); - } else { - InstaFlashReceiverInterface(uniswapFlashData_.sender) - .executeOperation( - instaLoanVariables_._tokens, - instaLoanVariables_._amounts, - instaLoanVariables_._instaFees, - uniswapFlashData_.sender, - uniswapFlashData_.data - ); - } - - instaLoanVariables_._finBals = calculateBalances( - instaLoanVariables_._tokens, - address(this) - ); - - validateFlashloan(instaLoanVariables_); - - uint256[] memory fees_; - if (instaLoanVariables_._tokens.length == 2) { - fees_ = new uint256[](2); - fees_[0] = fee0; - fees_[1] = fee1; - } else if ( - instaLoanVariables_._tokens[0] == uniswapFlashData_.key.token0 - ) { - fees_ = new uint256[](1); - fees_[0] = fee0; - } else { - fees_ = new uint256[](1); - fees_[0] = fee1; - } - safeTransferWithFee(instaLoanVariables_, fees_, msg.sender); - } - - /** - * @dev Middle function for route 1. - * @notice Middle function for route 1. - * @param _tokens list of token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets or amount of ether to borrow as collateral for flashloan. - * @param _data extra data passed. - */ - function routeAave( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - bytes memory data_ = abi.encode(msg.sender, _data); - uint256 length_ = _tokens.length; - uint256[] memory _modes = new uint256[](length_); - for (uint256 i = 0; i < length_; i++) { - _modes[i] = 0; - } - dataHash = bytes32(keccak256(data_)); - aaveLending.flashLoan( - address(this), - _tokens, - _amounts, - _modes, - address(0), - data_, - 3228 - ); - } - - /** - * @dev Middle function for route 5. - * @notice Middle function for route 5. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - */ - function routeBalancer( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - uint256 length_ = _tokens.length; - IERC20[] memory tokens_ = new IERC20[](length_); - for (uint256 i = 0; i < length_; i++) { - tokens_[i] = IERC20(_tokens[i]); - } - bytes memory data_ = abi.encode( - 5, - _tokens, - _amounts, - msg.sender, - _data - ); - dataHash = bytes32(keccak256(data_)); - balancerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - tokens_, - _amounts, - data_ - ); - } - - /** - * @dev Middle function for route 7. - * @notice Middle function for route 7. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - */ - function routeBalancerAave( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data - ) internal { - bytes memory data_ = abi.encode( - 7, - _tokens, - _amounts, - msg.sender, - _data - ); - IERC20[] memory wethTokenList_ = new IERC20[](1); - uint256[] memory wethAmountList_ = new uint256[](1); - wethTokenList_[0] = IERC20(wEthToken); - wethAmountList_[0] = getWEthBorrowAmount(); - dataHash = bytes32(keccak256(data_)); - balancerLending.flashLoan( - InstaFlashReceiverInterface(address(this)), - wethTokenList_, - wethAmountList_, - data_ - ); - } - - /** - * @dev Middle function for route 8. - * @notice Middle function for route 8. - * @param _tokens token addresses for flashloan. - * @param _amounts list of amounts for the corresponding assets. - * @param _data extra data passed. - *@param _instadata pool key encoded - */ - function routeUniswap( - address[] memory _tokens, - uint256[] memory _amounts, - bytes memory _data, - bytes memory _instadata - ) internal { - PoolKey memory key = abi.decode(_instadata, (PoolKey)); - - uint256 amount0_; - uint256 amount1_; - - if (_tokens.length == 1) { - require( - (_tokens[0] == key.token0 || _tokens[0] == key.token1), - "tokens-do-not-match-pool" - ); - if (_tokens[0] == key.token0) { - amount0_ = _amounts[0]; - } else { - amount1_ = _amounts[0]; - } - } else if (_tokens.length == 2) { - require( - (_tokens[0] == key.token0 && _tokens[1] == key.token1), - "tokens-do-not-match-pool" - ); - amount0_ = _amounts[0]; - amount1_ = _amounts[1]; - } else { - revert("Number of tokens do not match"); - } - - IUniswapV3Pool pool = IUniswapV3Pool( - computeAddress(uniswapFactoryAddr, key) - ); - - bytes memory data_ = abi.encode( - _tokens, - _amounts, - msg.sender, - key, - _data - ); - dataHash = bytes32(keccak256(data_)); - pool.flash(address(this), amount0_, amount1_, data_); + ) external { + spell(UNISWAP_IMPL, msg.data); } /** @@ -446,20 +84,17 @@ contract FlashAggregatorPolygon is Helper { uint256 _route, bytes calldata _data, bytes calldata _instadata - ) external reentrancy { + ) external { require(_tokens.length == _amounts.length, "array-lengths-not-same"); - (_tokens, _amounts) = bubbleSort(_tokens, _amounts); - validateTokens(_tokens); - if (_route == 1) { - routeAave(_tokens, _amounts, _data); - } else if (_route == 5) { - routeBalancer(_tokens, _amounts, _data); - } else if (_route == 7) { - routeBalancerAave(_tokens, _amounts, _data); + spell(AAVE_IMPL, msg.data); + } else if (_route == 5 || _route == 7) { + spell(BALANCER_IMPL, msg.data); } else if (_route == 8) { - routeUniswap(_tokens, _amounts, _data, _instadata); + spell(UNISWAP_IMPL, msg.data); + } else if (_route == 2 || _route == 3 || _route == 4 || _route == 6) { + revert("this route is only for mainnet"); } else { revert("route-does-not-exist"); } @@ -511,5 +146,14 @@ contract InstaFlashAggregatorPolygon is FlashAggregatorPolygon { // status = 1; // } + /** + * @dev Function created for testing upgradable implementations + */ + // function initialize(address aave, address balancer, address uniswap) public { + // AAVE_IMPL = aave; + // BALANCER_IMPL = balancer; + // UNISWAP_IMPL = uniswap; + // } + receive() external payable {} } diff --git a/contracts/aggregator/polygon/flashloan/variables.sol b/contracts/aggregator/polygon/flashloan/variables.sol index 9d533e3c..999bda49 100644 --- a/contracts/aggregator/polygon/flashloan/variables.sol +++ b/contracts/aggregator/polygon/flashloan/variables.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import "./interfaces.sol"; +import "../../common/interface.sol"; contract ConstantVariables { address public constant aaveLendingAddr = @@ -50,4 +51,8 @@ contract Variables is ConstantVariables { address token1; uint24 fee; } + + address internal AAVE_IMPL; + address internal BALANCER_IMPL; + address internal UNISWAP_IMPL; } diff --git a/test/arbitrum/newFlashloan.ts b/test/arbitrum/newFlashloan.ts new file mode 100644 index 00000000..11b0b53b --- /dev/null +++ b/test/arbitrum/newFlashloan.ts @@ -0,0 +1,203 @@ +const hre = require('hardhat') +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +const { ethers } = hre + +import { + BalancerImplementationArbitrum__factory, + UniswapImplementationArbitrum__factory, + InstaFlashAggregatorProxy__factory, + IERC20__factory, + InstaFlashReceiver__factory, + InstaFlashReceiver, + InstaFlashAggregatorArbitrum__factory, + } from '../../typechain' + + describe('FlashLoan', function () { + let Aggregator, + aggregator, + Receiver, + receiver: InstaFlashReceiver, + BalancerImp, + UniswapImp, + balancerImpl, + uniswapImpl, + proxyAddr = "0x1f882522DF99820dF8e586b6df8bAae2b91a782d", + admin = "0x82D57efa1cE59A0cA3492e189c72B360c7a1Dcdd", + adminSigner; + + let signer: SignerWithAddress + + const master = '0xa8c31E39e40E6765BEdBd83D92D6AA0B33f1CCC5' + const aaveLendingAddr = '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9' + + let iface = new ethers.utils.Interface(["function initialize(address bImp,address uImp)"]); + + const USDC = "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8"; + const USDT = "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9"; + const ACC_USDC = "0xce2cc46682e9c6d5f174af598fb4931a9c0be68e"; + const ACC_USDT = "0x0db3fe3b770c95a0b99d1ed6f2627933466c0dd8"; + //usdt < usdc + + const usdc = ethers.utils.parseUnits("10", 6); + const usdt = ethers.utils.parseUnits("10", 6); + const Usdc = ethers.utils.parseUnits("5000", 6); + const Usdt = ethers.utils.parseUnits("5000", 6); + + const _data = '0x' + + let _instaData = '0x' + + beforeEach('Should set up', async function () { + ;[signer] = await ethers.getSigners() + + Aggregator = new InstaFlashAggregatorArbitrum__factory(signer) + aggregator = await Aggregator.deploy() + await aggregator.deployed() + console.log("aggregator: ", aggregator.address) + + BalancerImp = new BalancerImplementationArbitrum__factory(signer) + balancerImpl = await BalancerImp.deploy() + await balancerImpl.deployed() + console.log("balancerImpl: ", balancerImpl.address) + + UniswapImp = new UniswapImplementationArbitrum__factory(signer) + uniswapImpl = await UniswapImp.deploy() + await uniswapImpl.deployed() + console.log("uniswapImpl: ", uniswapImpl.address) + + const proxy = new ethers.Contract( + proxyAddr, + InstaFlashAggregatorProxy__factory.abi, + ethers.provider, + ) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [admin], + }) + + adminSigner = await ethers.getSigner(admin); + + await hre.network.provider.send('hardhat_setBalance', [ + admin, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + const dataNew = await iface.encodeFunctionData('initialize', [balancerImpl.address,uniswapImpl.address]) + console.log("dataNew: ", dataNew) + await proxy.connect(adminSigner).upgradeToAndCall(aggregator.address, dataNew); + + Receiver = new InstaFlashReceiver__factory(signer); + receiver = await Receiver.deploy(proxyAddr); + await receiver.deployed(); + console.log("receiver: ", receiver.address) + + const token_usdc = new ethers.Contract( + USDC, + IERC20__factory.abi, + ethers.provider + ); + + await hre.network.provider.send("hardhat_setBalance", [ + ACC_USDC, + ethers.utils.parseEther("10.0").toHexString(), + ]); + + await hre.network.provider.request({ + method: "hardhat_impersonateAccount", + params: [ACC_USDC], + }); + + const signer_usdc = await ethers.getSigner(ACC_USDC); + await token_usdc.connect(signer_usdc).transfer(receiver.address, usdc); + + await hre.network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [ACC_USDC], + }); + _instaData = "0x"; + }) + + describe("Single token", async function () { + it("Should be able to take flashLoan of a single token from Balancer", async function () { + await receiver.flashBorrow([USDC], [Usdc], 5, _data, _instaData); + }); + }); + + describe("Uniswap Route", async function () { + beforeEach(async function () { + _instaData = await ethers.utils.defaultAbiCoder.encode( + ["tuple(address, address, uint24)"], + [[USDT, USDC, "500"]] + ); + }); + it("Should be able to take flashLoan of a single token from Uniswap", async function () { + await receiver.flashBorrow([USDC], [Usdc], 8, _data, _instaData); + }); + }); + + describe("Multi token", async function () { + beforeEach(async function () { + const token = new ethers.Contract( + USDT, + IERC20__factory.abi, + ethers.provider + ); + + await hre.network.provider.send("hardhat_setBalance", [ + ACC_USDT, + ethers.utils.parseEther("10.0").toHexString(), + ]); + + await hre.network.provider.request({ + method: "hardhat_impersonateAccount", + params: [ACC_USDT], + }); + + const signer_usdt = await ethers.getSigner(ACC_USDT); + await token.connect(signer_usdt).transfer(receiver.address, usdt); + + await hre.network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [ACC_USDT], + }); + _instaData = "0x"; + }); + it("Should be able to take flashLoan of multiple sorted tokens together from Balancer", async function () { + await receiver.flashBorrow( + [USDT, USDC], + [Usdt, Usdc], + 5, + _data, + _instaData + ); + }); + it("Should be able to take flashLoan of multiple unsorted tokens together from Balancer", async function () { + await receiver.flashBorrow( + [USDC, USDT], + [Usdc, Usdt], + 5, + _data, + _instaData + ); + }); + + describe("Uniswap Route", async function () { + beforeEach(async function () { + _instaData = await ethers.utils.defaultAbiCoder.encode( + ["tuple(address, address, uint24)"], + [[USDT, USDC, "500"]] + ); + }); + it("Should be able to take flashLoan of multiple tokens together from Uniswap", async function () { + await receiver.flashBorrow( + [USDT, USDC], + [Usdt, Usdc], + 8, + _data, + _instaData + ); + }); + }); + }); + }) diff --git a/test/avalanche/newFlashloan.ts b/test/avalanche/newFlashloan.ts new file mode 100644 index 00000000..54e58fcf --- /dev/null +++ b/test/avalanche/newFlashloan.ts @@ -0,0 +1,137 @@ +const hre = require('hardhat') +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +const { ethers } = hre + +import { + InstaFlashAggregatorAvalanche__factory, + IERC20__factory, + InstaFlashReceiver__factory, + InstaFlashReceiver, + InstaFlashAggregatorProxy__factory, + AaveImplementationAvalanche, + AaveImplementationAvalanche__factory +} from '../../typechain' + +describe('FlashLoan', function () { + let Aggregator, + aggregator, + Receiver, + receiver: InstaFlashReceiver, + Proxy, + proxy, + ImplAave, + implAave, + proxyAddr = "0x2b65731A085B55DBe6c7DcC8D717Ac36c00F6d19", + admin = "0x7b0990a249a215c9a88ebec3849920e29725f2d0", + adminSigner + + let signer: SignerWithAddress + + const master = '0xa9061100d29C3C562a2e2421eb035741C1b42137' + + let ABI = ['function initialize(address aave)'] + let iface = new ethers.utils.Interface(ABI) + + const DAI = '0xd586e7f844cea2f87f50152665bcbc2c279d8d70' + const USDT = '0xc7198437980c041c805a1edcba50c1ce5db95118' + const ACC_DAI = '0xed2a7edd7413021d440b09d654f3b87712abab66' + const ACC_USDT = '0xed2a7edd7413021d440b09d654f3b87712abab66' + + const dai = ethers.utils.parseUnits('10', 18) + const usdt = ethers.utils.parseUnits('10', 6) + const Dai = ethers.utils.parseUnits('5000', 18) + const Usdt = ethers.utils.parseUnits('5000', 6) + + const zeroAddr = + '0x0000000000000000000000000000000000000000000000000000000000000000' + let _instaData = '' + + + beforeEach(async function () { + ;[signer] = await ethers.getSigners() + Aggregator = new InstaFlashAggregatorAvalanche__factory(signer) + aggregator = await Aggregator.deploy() + await aggregator.deployed() + console.log("aggregator: ", aggregator.address) + + ImplAave = new AaveImplementationAvalanche__factory(signer) + implAave = await ImplAave.deploy() + await implAave.deployed() + console.log("implAave: ", implAave.address) + + const data = iface.encodeFunctionData('initialize',[implAave.address]) + + Proxy = new InstaFlashAggregatorProxy__factory(signer) + proxy = await Proxy.deploy(aggregator.address, master, data) + await proxy.deployed() + console.log("proxy: ", proxy.address) + + Receiver = new InstaFlashReceiver__factory(signer) + receiver = await Receiver.deploy(proxy.address) + await receiver.deployed() + console.log("receiver: ", receiver.address) + + const token_dai = new ethers.Contract( + DAI, + IERC20__factory.abi, + ethers.provider, + ) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_DAI, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_DAI], + }) + + const signer_dai = await ethers.getSigner(ACC_DAI) + await token_dai.connect(signer_dai).transfer(receiver.address, dai) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_DAI], + }) + _instaData = '0x' + }) + + describe('Single token', async function () { + it('Should be able to take flashLoan of a single token from AAVE', async function () { + await receiver.flashBorrow([DAI], [Dai], 1, zeroAddr,_instaData) + }) + }) + + describe('Multi token', async function () { + beforeEach(async function () { + const token = new ethers.Contract( + USDT, + IERC20__factory.abi, + ethers.provider, + ) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_USDT, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_USDT], + }) + + const signer_usdt = await ethers.getSigner(ACC_USDT) + await token.connect(signer_usdt).transfer(receiver.address, usdt) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_USDT], + }) + _instaData = '0x' + }) + it('Should be able to take flashLoan of multiple tokens together from AAVE', async function () { + await receiver.flashBorrow([DAI, USDT], [Dai, Usdt], 1, zeroAddr,_instaData ) + }) + }) +}) diff --git a/test/mainnet/newFlash.ts b/test/mainnet/newFlash.ts new file mode 100644 index 00000000..dbba0eca --- /dev/null +++ b/test/mainnet/newFlash.ts @@ -0,0 +1,360 @@ +const hre = require('hardhat') +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +const { ethers } = hre + +import { + InstaFlashAggregator, + InstaFlashAggregator__factory, + IERC20__factory, + IERC20, + InstaFlashReceiver__factory, + InstaFlashReceiver, + InstaFlashAggregatorProxy, + InstaFlashAggregatorProxy__factory, + AaveImplementation__factory, + AaveImplementation, + BalancerImplementation, + MakerImplementation, + BalancerImplementation__factory, + MakerImplementation__factory +} from '../../typechain' + +describe('FlashLoan', function () { + let Aggregator, + aggregator, + Receiver, + receiver: InstaFlashReceiver, + Proxy, + proxy: InstaFlashAggregatorProxy, + proxyA : AaveImplementation, + proxyB : BalancerImplementation, + proxyM : MakerImplementation, + ProxyA, + ProxyB, + ProxyM, + admin = "0xb208CDF8e1c319d0019397dceC8E0bA3Fb9A149F", + proxyAddr = "0x619Ad2D02dBeE6ebA3CDbDA3F98430410e892882", + adminSigner + + let signer: SignerWithAddress + + const master = '0xa8c31E39e40E6765BEdBd83D92D6AA0B33f1CCC5' + const aaveLendingAddr = '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9' + + let ABI = ['function initialize(address[],address,address,address,address)'] + let iface = new ethers.utils.Interface(ABI) + + const DAI = '0x6b175474e89094c44da98b954eedeac495271d0f' + const USDT = '0xdac17f958d2ee523a2206206994597c13d831ec7' + const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' + const ACC_DAI = '0x9a7a9d980ed6239b89232c012e21f4c210f4bef1' + const ACC_USDT = '0x6D5Be15f9Aa170e207C043CDf8E0BaDbF2A48ed0' + const ACC_WETH = '0xe78388b4ce79068e89bf8aa7f218ef6b9ab0e9d0' + + const STETH = '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84' + const ACC_STETH = '0xdc24316b9ae028f1497c275eb9192a3ea0f67022' + + const dai = ethers.utils.parseUnits('10', 18) + const usdt = ethers.utils.parseUnits('10', 6) + const weth = ethers.utils.parseUnits('10', 18) + const Dai = ethers.utils.parseUnits('5000', 18) + const Usdt = ethers.utils.parseUnits('5000', 6) + const Weth = ethers.utils.parseUnits('1000', 18) + const steth = ethers.utils.parseUnits('1', 18) + const Steth = ethers.utils.parseUnits('100', 18) + + const _data = '0x' + + let _instaData = '0x' + + beforeEach(async function () { + ;[signer] = await ethers.getSigners() + + ProxyA = new AaveImplementation__factory(signer) + proxyA = await ProxyA.deploy() + await proxyA.deployed() + console.log("Aave proxy deployed at: ", proxyA.address); + + ProxyB = new BalancerImplementation__factory(signer) + proxyB = await ProxyB.deploy() + await proxyB.deployed() + console.log("Balancer proxy deployed at: ", proxyB.address); + + + ProxyM = new MakerImplementation__factory(signer) + proxyM = await ProxyM.deploy() + await proxyM.deployed() + console.log("Maker proxy deployed at: ", proxyM.address); + + + Aggregator = new InstaFlashAggregator__factory(signer) + aggregator = await Aggregator.deploy() + await aggregator.deployed() + console.log("aggregator deployed at: ", aggregator.address); + + const data = iface.encodeFunctionData('initialize', [ + [ + '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643', // DAI + '0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9', // USDT + '0x39AA39c021dfbaE8faC545936693aC917d5E7563', // USDC + '0xe65cdb6479bac1e22340e4e755fae7e509ecd06c', // AAVE + '0x6c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e', // BAT + '0x70e36f6bf80a52b3b46b3af8e106cc0ed743e8e4', // COMP + '0xface851a4921ce59e912d19329929ce6da6eb0c7', // LINK + '0x95b4ef2869ebd94beb4eee400a99824bf5dc325b', // MKR + '0x158079ee67fce2f58472a96584a73c7ab9ac95c1', // REP + '0x4b0181102a0112a2ef11abee5563bb4a3176c9d7', // SUSHI + '0x12392f67bdf24fae0af363c24ac620a2f67dad86', // TUSD + '0x35a18000230da775cac24873d00ff85bccded550', // UNI + '0xccf4429db6322d5c611ee964527d42e5d685dd6a', // WBTC2 + '0x80a2ae356fc9ef4305676f7a3e2ed04e12c33946', // YFI + '0xb3319f5d18bc0d84dd1b4825dcde5d5f7266d407', // ZRX + ],master,proxyA.address,proxyB.address,proxyM.address + ]) + + Proxy = new InstaFlashAggregatorProxy__factory(signer) + proxy = await Proxy.deploy(aggregator.address, master, data) + await proxy.deployed() + console.log("Proxy deployed at: ", proxy.address); + + + Receiver = new InstaFlashReceiver__factory(signer) + receiver = await Receiver.deploy(proxy.address) + await receiver.deployed() + console.log("receiver deployed at: ", receiver.address); + + const token_steth = new ethers.Contract( + STETH, + IERC20__factory.abi, + ethers.provider, + ) + + const token_dai = new ethers.Contract( + DAI, + IERC20__factory.abi, + ethers.provider, + ) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_DAI, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_STETH, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.send('hardhat_setBalance', [ + proxy.address, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_DAI], + }) + + const signer_dai = await ethers.getSigner(ACC_DAI) + await token_dai.connect(signer_dai).transfer(receiver.address, dai) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_DAI], + }) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_STETH], + }) + + const signer_steth = await ethers.getSigner(ACC_STETH) + await token_steth.connect(signer_steth).transfer(receiver.address, steth) + await token_steth.connect(signer_steth).transfer(proxy.address, steth) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_STETH], + }) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [proxy.address], + }) + + const signer_fla = await ethers.getSigner(proxy.address) + await token_dai.connect(signer_fla).approve(aaveLendingAddr, 100) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [proxy.address], + }) + _instaData = '0x' + }) + + describe('Single token', async function () { + it('Should be able to take flashLoan of a single token from AAVE', async function () { + await receiver.flashBorrow([DAI], [Dai], 1, _data, _instaData) + }) + it('Should be able to take flashLoan of a single token from MakerDAO', async function () { + await receiver.flashBorrow([DAI], [Dai], 2, _data, _instaData) + }) + it('Should be able to take flashLoan of a single token from Compound(MakerDAO)', async function () { + await receiver.flashBorrow([DAI], [Dai], 3, _data, _instaData) + }) + it('Should be able to take flashLoan of a single token from AAVE(MakerDAO)', async function () { + await receiver.flashBorrow([DAI], [Dai], 4, _data, _instaData) + }) + it('Should be able to take flashLoan of a single token from Balancer', async function () { + await receiver.flashBorrow([DAI], [Dai], 5, _data, _instaData) + }) + it('Should be able to take flashLoan of a single token from Compound(Balancer)', async function () { + await receiver.flashBorrow([DAI], [Dai], 6, _data, _instaData) + }) + it('Should be able to take flashLoan of a single token from AAVE(Balancer)', async function () { + await receiver.flashBorrow([DAI], [Dai], 7, _data, _instaData) + }) + it('Should be able to take flashLoan of a steth token from AAVE(Balancer)', async function () { + await receiver.flashBorrow([STETH], [Steth], 5, _data, _instaData) + }) + }) + + describe('Multi token', async function () { + beforeEach(async function () { + const token_usdt = new ethers.Contract( + USDT, + IERC20__factory.abi, + ethers.provider, + ) + + const token_weth = new ethers.Contract( + WETH, + IERC20__factory.abi, + ethers.provider, + ) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_USDT, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_WETH, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_USDT], + }) + + const signer_usdt = await ethers.getSigner(ACC_USDT) + await token_usdt.connect(signer_usdt).transfer(receiver.address, usdt) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_USDT], + }) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_WETH], + }) + + const signer_weth = await ethers.getSigner(ACC_WETH) + await token_weth.connect(signer_weth).transfer(receiver.address, weth) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_WETH], + }) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [proxy.address], + }) + + const signer_fla = await ethers.getSigner(proxy.address) + await token_usdt.connect(signer_fla).approve(aaveLendingAddr, 100) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [proxy.address], + }) + _instaData = '0x' + }) + + it('Should be able to take flashLoan of multiple tokens together from AAVE', async function () { + await receiver.flashBorrow( + [DAI, USDT, WETH], + [Dai, Usdt, Weth], + 1, + _data, + _instaData, + ) + }) + it('Should be able to take flashLoan of multiple tokens together from MakerDAO', async function () { + await receiver.flashBorrow( + [DAI, USDT, WETH], + [Dai, Usdt, Weth], + 2, + _data, + _instaData, + ) + }) + it('Should be able to take flashLoan of multiple tokens together from Compound(MakerDAO)', async function () { + await receiver.flashBorrow( + [DAI, USDT, WETH], + [Dai, Usdt, Weth], + 3, + _data, + _instaData, + ) + }) + it('Should be able to take flashLoan of multiple tokens together from AAVE(MakerDAO)', async function () { + await receiver.flashBorrow( + [DAI, USDT, WETH], + [Dai, Usdt, Weth], + 4, + _data, + _instaData, + ) + }) + it('Should be able to take flashLoan of multiple sorted tokens together from Balancer', async function () { + await receiver.flashBorrow( + [DAI, USDT, WETH], + [Dai, Usdt, Weth], + 5, + _data, + _instaData, + ) + }) + it('Should be able to take flashLoan of multiple unsorted tokens together from Balancer', async function () { + await receiver.flashBorrow( + [USDT, DAI, WETH], + [Usdt, Dai, Weth], + 5, + _data, + _instaData, + ) + }) + it('Should be able to take flashLoan of multiple tokens together from Compound(Balancer)', async function () { + await receiver.flashBorrow( + [DAI, USDT, WETH], + [Dai, Usdt, Weth], + 6, + _data, + _instaData, + ) + }) + it('Should be able to take flashLoan of multiple tokens together from AAVE(Balancer)', async function () { + await receiver.flashBorrow( + [DAI, USDT, WETH], + [Dai, Usdt, Weth], + 7, + _data, + _instaData, + ) + }) + }) +}) diff --git a/test/optimism/newFlash.ts b/test/optimism/newFlash.ts new file mode 100644 index 00000000..6ced1dc8 --- /dev/null +++ b/test/optimism/newFlash.ts @@ -0,0 +1,153 @@ +const hre = require('hardhat') +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +const { ethers } = hre + +import { + InstaFlashAggregatorOptimism__factory, + IERC20__factory, + InstaFlashReceiver__factory, + InstaFlashReceiver, + InstaFlashAggregatorProxy__factory, + UniswapImplementationOptimism, + UniswapImplementationOptimism__factory +} from '../../typechain' + +describe('FlashLoan', function () { + let Aggregator, + aggregator, + Receiver, + receiver: InstaFlashReceiver, + implUniswap : UniswapImplementationOptimism, + ImplUniswap, + proxyAddr = "0x84E6b05A089d5677A702cF61dc14335b4bE5b282", + admin = "0xd4e5e20ef32b4750d4cd185a8e970b89851e7775", + adminSigner + + let signer: SignerWithAddress + + const master = '0xa9061100d29C3C562a2e2421eb035741C1b42137' + + let ABI = ['function initialize(address)'] + let iface = new ethers.utils.Interface(ABI) + + const DAI = '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1' + const USDT = '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58' + const ACC_DAI = '0xadb35413ec50e0afe41039eac8b930d313e94fa4' + const ACC_USDT = '0x9d39fc627a6d9d9f8c831c16995b209548cc3401' + + const dai = ethers.utils.parseUnits('1000', 18) + const usdt = ethers.utils.parseUnits('1000', 6) + const Dai = ethers.utils.parseUnits('5000', 18) + const Usdt = ethers.utils.parseUnits('5000', 6) + + const _data = '0x' + + let _instaData = '0x' + + beforeEach(async function () { + ;[signer] = await ethers.getSigners() + Aggregator = new InstaFlashAggregatorOptimism__factory(signer) + aggregator = await Aggregator.deploy() + await aggregator.deployed() + + ImplUniswap = new UniswapImplementationOptimism__factory(signer) + implUniswap = await ImplUniswap.deploy() + await implUniswap.deployed() + + const proxy = new ethers.Contract( + proxyAddr, + InstaFlashAggregatorProxy__factory.abi, + ethers.provider, + ) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [admin], + }) + + adminSigner = await ethers.getSigner(admin); + + await hre.network.provider.send('hardhat_setBalance', [ + admin, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + const data = iface.encodeFunctionData('initialize',[implUniswap.address]) + console.log("data: ", data) + await proxy.connect(adminSigner).upgradeToAndCall(aggregator.address, data); + + Receiver = new InstaFlashReceiver__factory(signer) + receiver = await Receiver.deploy(proxy.address) + await receiver.deployed() + + const token_dai = new ethers.Contract( + DAI, + IERC20__factory.abi, + ethers.provider, + ) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_DAI, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_DAI], + }) + + const signer_dai = await ethers.getSigner(ACC_DAI) + await token_dai.connect(signer_dai).transfer(receiver.address, dai) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_DAI], + }) + + _instaData = await ethers.utils.defaultAbiCoder.encode( + ['tuple(address, address, uint24)'], + [[USDT, DAI, '500']], + ) + }) + + describe('Single token', async function () { + it('Should be able to take flashLoan of a single token from Uniswap', async function () { + await receiver.flashBorrow([DAI], [Dai], 8, _data, _instaData) + }) + }) + + describe('Multi token', async function () { + beforeEach(async function () { + const token = new ethers.Contract( + USDT, + IERC20__factory.abi, + ethers.provider, + ) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_USDT, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_USDT], + }) + + const signer_usdt = await ethers.getSigner(ACC_USDT) + await token.connect(signer_usdt).transfer(receiver.address, usdt) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_USDT], + }) + _instaData = await ethers.utils.defaultAbiCoder.encode( + ['tuple(address, address, uint24)'], + [[USDT, DAI, '500']], + ) + }) + it('Should be able to take flashLoan of multiple tokens together from Uniswap', async function () { + await receiver.flashBorrow([DAI, USDT], [Dai, Usdt], 8, _data, _instaData) + }) + }) +}) diff --git a/test/polygon/flashloan.ts b/test/polygon/flashloan.ts index fb675053..64be98e5 100644 --- a/test/polygon/flashloan.ts +++ b/test/polygon/flashloan.ts @@ -48,14 +48,19 @@ describe('FlashLoan', function () { Aggregator = new InstaFlashAggregatorPolygon__factory(signer) aggregator = await Aggregator.deploy() await aggregator.deployed() + console.log("aggregator deployed at: ", aggregator.address); + Proxy = new InstaFlashAggregatorProxy__factory(signer) proxy = await Proxy.deploy(aggregator.address, master, data) await proxy.deployed() + console.log("proxy deployed at: ", proxy.address); + Receiver = new InstaFlashReceiver__factory(signer) receiver = await Receiver.deploy(proxy.address) await receiver.deployed() + console.log("receiver deployed at: ", receiver.address); const token_dai = new ethers.Contract( DAI, diff --git a/test/polygon/newFlashloan.ts b/test/polygon/newFlashloan.ts new file mode 100644 index 00000000..f25a4e0e --- /dev/null +++ b/test/polygon/newFlashloan.ts @@ -0,0 +1,218 @@ +const hre = require('hardhat') +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +const { ethers } = hre + +import { + InstaFlashAggregatorPolygon__factory, + IERC20__factory, + InstaFlashReceiver__factory, + InstaFlashReceiver, + InstaFlashAggregatorProxy__factory, + UniswapImplementationPolygon__factory, + BalancerImplementationPolygon__factory, + AaveImplementationPolygon__factory +} from '../../typechain' + +describe('FlashLoan', function () { + let Aggregator, + aggregator, + Receiver, + receiver: InstaFlashReceiver, + implUniswap, + ImplUniswap, + implBalancer, + ImplBalancer, + implAave, + ImplAave, + proxyAddr = "0xB2A7F20D10A006B0bEA86Ce42F2524Fde5D6a0F4", + admin = "0x90cf378a297c7ef6dabed36ea5e112c6646bb3a4", + adminSigner + + let signer: SignerWithAddress + + const master = '0xa9061100d29C3C562a2e2421eb035741C1b42137' + + let ABI = ['function initialize(address aave, address balancer, address uniswap)'] + let iface = new ethers.utils.Interface(ABI) + + const DAI = '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063' + const USDT = '0xc2132d05d31c914a87c6611c10748aeb04b58e8f' + const ACC_DAI = '0x4a35582a710e1f4b2030a3f826da20bfb6703c09' + const ACC_USDT = '0x0d0707963952f2fba59dd06f2b425ace40b492fe' + //dai < usdt + + const dai = ethers.utils.parseUnits('1000', 18) + const usdt = ethers.utils.parseUnits('1000', 6) + const Dai = ethers.utils.parseUnits('5000', 18) + const Usdt = ethers.utils.parseUnits('5000', 6) + + const _data = '0x' + + let _instaData = '0x' + + beforeEach(async function () { + ;[signer] = await ethers.getSigners() + Aggregator = new InstaFlashAggregatorPolygon__factory(signer) + aggregator = await Aggregator.deploy() + await aggregator.deployed() + console.log("aggregator deployed at: ", aggregator.address); + + ImplAave = new AaveImplementationPolygon__factory(signer) + implAave = await ImplAave.deploy() + await implAave.deployed() + console.log("implAave deployed at: ", implAave.address); + + ImplBalancer = new BalancerImplementationPolygon__factory(signer) + implBalancer = await ImplBalancer.deploy() + await implBalancer.deployed() + console.log("implBalancer deployed at: ", implBalancer.address); + + ImplUniswap = new UniswapImplementationPolygon__factory(signer) + implUniswap = await ImplUniswap.deploy() + await implUniswap.deployed() + console.log("implUniswap deployed at: ", implUniswap.address); + + const proxy = new ethers.Contract( + proxyAddr, + InstaFlashAggregatorProxy__factory.abi, + ethers.provider, + ) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [admin], + }) + + adminSigner = await ethers.getSigner(admin); + + await hre.network.provider.send('hardhat_setBalance', [ + admin, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + const data = iface.encodeFunctionData('initialize', [implAave.address, implBalancer.address,implUniswap.address]) + await proxy.connect(adminSigner).upgradeToAndCall(aggregator.address, data); + + Receiver = new InstaFlashReceiver__factory(signer) + receiver = await Receiver.deploy(proxy.address) + await receiver.deployed() + console.log("receiver deployed at: ", receiver.address); + + const token_dai = new ethers.Contract( + DAI, + IERC20__factory.abi, + ethers.provider, + ) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_DAI, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_DAI], + }) + + const signer_dai = await ethers.getSigner(ACC_DAI) + await token_dai.connect(signer_dai).transfer(receiver.address, dai) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_DAI], + }) + _instaData = '0x' + }) + + describe('Single token', async function () { + it('Should be able to take flashLoan of a single token from AAVE', async function () { + await receiver.flashBorrow([DAI], [Dai], 1, _data, _instaData) + }) + it('Should be able to take flashLoan of a single token from Balancer', async function () { + await receiver.flashBorrow([DAI], [Dai], 5, _data, _instaData) + }) + it('Should be able to take flashLoan of a single token from AAVE(Balancer)', async function () { + await receiver.flashBorrow([DAI], [Dai], 7, _data, _instaData) + }) + + describe('Uniswap Route', async function () { + beforeEach(async function () { + _instaData = await ethers.utils.defaultAbiCoder.encode( + ['tuple(address, address, uint24)'], + [[DAI, USDT, '500']], + ) + }) + it('Should be able to take flashLoan of a single token from Uniswap', async function () { + await receiver.flashBorrow([DAI], [Dai], 8, _data, _instaData) + }) + }) + }) + + describe('Multi token', async function () { + beforeEach(async function () { + const token = new ethers.Contract( + USDT, + IERC20__factory.abi, + ethers.provider, + ) + + await hre.network.provider.send('hardhat_setBalance', [ + ACC_USDT, + ethers.utils.parseEther('10.0').toHexString(), + ]) + + await hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [ACC_USDT], + }) + + const signer_usdt = await ethers.getSigner(ACC_USDT) + await token.connect(signer_usdt).transfer(receiver.address, usdt) + + await hre.network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [ACC_USDT], + }) + _instaData = '0x' + }) + it('Should be able to take flashLoan of multiple tokens together from AAVE', async function () { + await receiver.flashBorrow([DAI, USDT], [Dai, Usdt], 1, _data, _instaData) + }) + it('Should be able to take flashLoan of multiple sorted tokens together from Balancer', async function () { + await receiver.flashBorrow([DAI, USDT], [Dai, Usdt], 5, _data, _instaData) + }) + it('Should be able to take flashLoan of multiple unsorted tokens together from Balancer', async function () { + await receiver.flashBorrow([USDT, DAI], [Usdt, Dai], 5, _data, _instaData) + }) + it('Should be able to take flashLoan of multiple tokens together from AAVE(Balancer)', async function () { + await receiver.flashBorrow([DAI, USDT], [Dai, Usdt], 7, _data, _instaData) + }) + + describe('Uniswap Route', async function () { + beforeEach(async function () { + _instaData = await ethers.utils.defaultAbiCoder.encode( + ['tuple(address, address, uint24)'], + [[USDT, DAI, '500']], + ) + }) + it('Should be able to take flashLoan of multiple unsorted tokens together from Uniswap', async function () { + await receiver.flashBorrow( + [USDT, DAI], + [Usdt, Dai], + 8, + _data, + _instaData, + ) + }) + it('Should be able to take flashLoan of multiple tokens sorted together from Uniswap', async function () { + await receiver.flashBorrow( + [DAI, USDT], + [Dai, Usdt], + 8, + _data, + _instaData, + ) + }) + }) + }) +})