From 2213f120582520a6cbbc7b7115b142ad2baea195 Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Thu, 8 Apr 2021 05:15:00 +0530 Subject: [PATCH] many updates at once --- .../common/{stores.sol => stores-mainnet.sol} | 2 - contracts/common/stores-polygon.sol | 37 +++++++ .../aave-v2-migrator/helpers.sol | 2 +- .../receivers2/aave-v2-receiver/helpers.sol | 40 ++++---- .../receivers2/aave-v2-receiver/main.sol | 98 +++++++++++-------- .../receivers2/aave-v2-receiver/variables.sol | 35 +++++++ .../senders/aave-v2-connector/helpers.sol | 2 +- .../senders/aave-v2-migrator/helpers.sol | 2 +- .../senders2/aave-v2-migrator/helpers.sol | 83 +++++----------- contracts/senders2/aave-v2-migrator/main.sol | 72 +++++++++----- .../senders2/aave-v2-migrator/variables.sol | 65 ++++++++++++ 11 files changed, 290 insertions(+), 148 deletions(-) rename contracts/common/{stores.sol => stores-mainnet.sol} (95%) create mode 100644 contracts/common/stores-polygon.sol create mode 100644 contracts/receivers2/aave-v2-receiver/variables.sol create mode 100644 contracts/senders2/aave-v2-migrator/variables.sol diff --git a/contracts/common/stores.sol b/contracts/common/stores-mainnet.sol similarity index 95% rename from contracts/common/stores.sol rename to contracts/common/stores-mainnet.sol index 03afef2..5f48d1f 100644 --- a/contracts/common/stores.sol +++ b/contracts/common/stores-mainnet.sol @@ -7,8 +7,6 @@ abstract contract Stores { /** * @dev Return ethereum address - * ETH on Mainnet - * MATIC on Polygon */ address constant internal ethAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; diff --git a/contracts/common/stores-polygon.sol b/contracts/common/stores-polygon.sol new file mode 100644 index 0000000..c2dab87 --- /dev/null +++ b/contracts/common/stores-polygon.sol @@ -0,0 +1,37 @@ +pragma solidity ^0.7.0; + +import { MemoryInterface } from "./interfaces.sol"; + + +abstract contract Stores { + + /** + * @dev Return matic address + */ + address constant internal maticAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + /** + * @dev Return Wrapped MATIC address + */ + address constant internal wmaticAddr = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270; + + /** + * @dev Return memory variable address + */ + MemoryInterface constant internal instaMemory = MemoryInterface(address(0)); // TODO: memory address on Polygon + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint getId, uint val) internal returns (uint returnVal) { + returnVal = getId == 0 ? val : instaMemory.getUint(getId); + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint setId, uint val) virtual internal { + if (setId != 0) instaMemory.setUint(setId, val); + } + +} diff --git a/contracts/implementations/aave-v2-migrator/helpers.sol b/contracts/implementations/aave-v2-migrator/helpers.sol index 0652c58..8958567 100644 --- a/contracts/implementations/aave-v2-migrator/helpers.sol +++ b/contracts/implementations/aave-v2-migrator/helpers.sol @@ -1,7 +1,7 @@ pragma solidity ^0.7.0; import { DSMath } from "../../common/math.sol"; -import { Stores } from "../../common/stores.sol"; +import { Stores } from "../../common/stores-polygon.sol"; import { AaveLendingPoolProviderInterface, diff --git a/contracts/receivers2/aave-v2-receiver/helpers.sol b/contracts/receivers2/aave-v2-receiver/helpers.sol index e3b494a..c0dccf9 100644 --- a/contracts/receivers2/aave-v2-receiver/helpers.sol +++ b/contracts/receivers2/aave-v2-receiver/helpers.sol @@ -3,31 +3,19 @@ pragma solidity >=0.7.0; import { DSMath } from "../../common/math.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Stores } from "../../common/stores-polygon.sol"; +import { Variables } from "./variables.sol"; import { TokenMappingInterface, AaveData, - AaveLendingPoolProviderInterface, AaveDataProviderInterface, AaveInterface } from "./interfaces.sol"; -abstract contract Helpers is DSMath { +abstract contract Helpers is Stores, DSMath, Variables { using SafeERC20 for IERC20; - // This will be used to have debt/collateral ratio always 20% less than liquidation - // TODO: Is this number correct for it? - uint public safeRatioGap = 200000000000000000; // 20%? 2e17 - - // TODO: Add function for flash deposits and withdraw - mapping(address => mapping(address => uint)) flashDeposits; // Flash deposits of particular token - mapping(address => uint) flashAmts; // token amount for flashloan usage (these token will always stay raw in this contract) - - // TODO: Replace this - TokenMappingInterface tokenMapping = TokenMappingInterface(address(2)); - - AaveLendingPoolProviderInterface constant internal aaveProvider = AaveLendingPoolProviderInterface(0xd05e3E715d945B59290df0ae8eF85c1BdB684744); - function remapTokens(AaveData memory data) internal view returns (AaveData memory) { for (uint i = 0; i < data.supplyTokens.length; i++) { data.supplyTokens[i] = tokenMapping.getMapping(data.supplyTokens[i]); @@ -45,8 +33,7 @@ abstract contract Helpers is DSMath { require(isOk, "position-at-risk"); } - function transferAtokens(address dsa, address[] memory supplyTokens, uint[] memory supplyAmts) internal { - AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); + function transferAtokens(AaveInterface aave, address dsa, address[] memory supplyTokens, uint[] memory supplyAmts) internal { for (uint i = 0; i < supplyTokens.length; i++) { address _token = supplyTokens[i]; IERC20 _atokenContract = IERC20(_token); // TODO: Fetch atoken from Aave mapping (change _token to atoken address) @@ -63,8 +50,7 @@ abstract contract Helpers is DSMath { if (tokenLiq < _reqAmt) { _flashAmt = flashAmts[_token]; if (_flashAmt > 0) { - // TODO: deposit _flashAmt to Aave - aave.deposit(_token, _flashAmt, address(this), 3288); + aave.deposit(_token, _flashAmt, address(this), 3288); // TODO: what is our ID on Polygon? tokenLiq += _flashAmt; isFlash = true; } @@ -93,16 +79,20 @@ abstract contract Helpers is DSMath { } } - function borrowAndTransferSpells(address dsa, address[] memory borrowTokens, uint[] memory borrowAmts) internal { + function borrowAndTransferSpells(AaveInterface aave, address dsa, address[] memory borrowTokens, uint[] memory borrowAmts) internal { for (uint i = 0; i < borrowTokens.length; i++) { address _token = borrowTokens[i]; address _atoken = address(0); // TODO: Fetch atoken address // get Aave liquidity of token uint tokenLiq = uint(0); uint _borrowAmt = borrowAmts[i]; + + uint _flashAmt; + bool isFlash; if (tokenLiq < _borrowAmt) { - uint _flashAmt = flashAmts[_token]; - // TODO: deposit _flashAmt in Aave + _flashAmt = flashAmts[_token]; + aave.deposit(_token, _flashAmt, address(this), 3288); // TODO: what is our ID on Polygon? + isFlash = true; tokenLiq += _flashAmt; } // TODO: Check number of loops needed. Borrow and supply on user's account. @@ -128,10 +118,16 @@ abstract contract Helpers is DSMath { castData[k+1] = abi.encode("ce88b439", _token, finalSplit, 2, 0, 0); // TODO: verify this & is rate mode right? } } + + if (isFlash) { + aave.withdraw(_token, _flashAmt, address(this)); + } + targets[spellsAmt] = "BASIC-A"; // TODO: right spell? castData[spellsAmt] = abi.encode("4bd3ab82", _atoken, _borrowAmt, address(this), 0, 0); // encode the data of atoken withdrawal // TODO: Call DSAs cast and borrow (maybe create a new implementation which only this contract can run?) } + } } \ No newline at end of file diff --git a/contracts/receivers2/aave-v2-receiver/main.sol b/contracts/receivers2/aave-v2-receiver/main.sol index e24923e..80aeecd 100644 --- a/contracts/receivers2/aave-v2-receiver/main.sol +++ b/contracts/receivers2/aave-v2-receiver/main.sol @@ -3,21 +3,14 @@ pragma experimental ABIEncoderV2; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { AccountInterface, AaveData, IndexInterface } from "./interfaces.sol"; +import { TokenInterface } from "../../common/interfaces.sol"; +import { AccountInterface, AaveData, AaveInterface, IndexInterface } from "./interfaces.sol"; import { Events } from "./events.sol"; import { Helpers } from "./helpers.sol"; contract MigrateResolver is Helpers, Events { using SafeERC20 for IERC20; - // dsa => position - mapping(uint => bytes) public positions; - mapping(address => mapping(address => uint)) public deposits; - - // InstaIndex Address. - IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); - function spell(address _target, bytes memory _data) external { require(msg.sender == instaIndex.master(), "not-master"); require(_target != address(0), "target-invalid"); @@ -34,35 +27,50 @@ contract MigrateResolver is Helpers, Events { } } - // TODO: Deposit in Aave - function deposit(address[] calldata tokens, uint[] calldata amts) external { + // TODO: @mubaris Make this similar to L1 migrator. Have to change ETH by MATIC + function deposit(address[] calldata tokens, uint[] calldata amts) external payable { uint _length = tokens.length; require(_length == amts.length, "invalid-length"); + AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); + uint[] memory _amts = new uint[](_length); for (uint256 i = 0; i < _length; i++) { + require(isSupportedToken[tokens[i]], "token-not-enabled"); + uint _amt; address _token = tokens[i]; - - IERC20 tokenContract = IERC20(_token); - uint _amt = amts[i] == uint(-1) ? tokenContract.balanceOf(msg.sender) : amts[i]; - tokenContract.safeTransferFrom(msg.sender, address(this), _amt); + if (_token == maticAddr) { + require(msg.value == amts[i]); + _amt = msg.value; + TokenInterface(wmaticAddr).deposit{value: msg.value}(); + aave.deposit(wmaticAddr, _amt, address(this), 3288); + } else { + IERC20 tokenContract = IERC20(_token); + _amt = amts[i] == uint(-1) ? tokenContract.balanceOf(msg.sender) : amts[i]; + tokenContract.safeTransferFrom(msg.sender, address(this), _amt); + aave.deposit(_token, _amt, address(this), 3288); + } + + _amts[i] = _amt; deposits[msg.sender][_token] += _amt; - _amts[i] = _amt; } emit LogDeposit(msg.sender, tokens, _amts); } - // TODO: Withdraw from Aave + // TODO: @mubaris Make this similar to L1 migrator. Have to change ETH by MATIC function withdraw(address[] calldata tokens, uint[] calldata amts) external { uint _length = tokens.length; require(_length == amts.length, "invalid-length"); + AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); + uint[] memory _amts = new uint[](_length); for (uint256 i = 0; i < _length; i++) { + require(isSupportedToken[tokens[i]], "token-not-enabled"); uint _amt = amts[i]; address _token = tokens[i]; uint maxAmt = deposits[msg.sender][_token]; @@ -71,11 +79,27 @@ contract MigrateResolver is Helpers, Events { _amt = maxAmt; } - IERC20(_token).safeTransfer(msg.sender, _amt); - - deposits[msg.sender][_token] = sub(maxAmt, _amt); + if (_token == maticAddr) { + TokenInterface _tokenContract = TokenInterface(wmaticAddr); + uint _maticBal = address(this).balance; + uint _tknBal = _tokenContract.balanceOf(address(this)); + if ((_maticBal + _tknBal) < _amt) { + aave.withdraw(wmaticAddr, sub(_amt, (_tknBal + _maticBal)), address(this)); + } + _tokenContract.withdraw((sub(_amt, _maticBal))); + msg.sender.call{value: _amt}(""); + } else { + IERC20 _tokenContract = IERC20(_token); + uint _tknBal = _tokenContract.balanceOf(address(this)); + if (_tknBal < _amt) { + aave.withdraw(_token, sub(_amt, _tknBal), address(this)); + } + _tokenContract.safeTransfer(msg.sender, _amt); + } _amts[i] = _amt; + + deposits[msg.sender][_token] = sub(maxAmt, _amt); } isPositionSafe(); @@ -83,9 +107,10 @@ contract MigrateResolver is Helpers, Events { emit LogWithdraw(msg.sender, tokens, _amts); } - // TODO: Things to factor + // TODO: @mubaris Things to factor // If there is same token supply and borrow, then close the smaller one - // If there is ideal token then payback or deposit according to the position + // If there is ideal token (other than flashAmt) then payback or deposit according to the position + // Keep flashAmt tokens as ideal // Object is the decrease the ratio and pay as less interest function settle() external { @@ -107,43 +132,34 @@ contract AaveV2Migrator is MigrateResolver { address[] memory supplyTokens = _data.supplyTokens; address[] memory borrowTokens = _data.borrowTokens; - transferAtokens(dsa, supplyTokens, supplyAmts); + AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); - // Have to borrow from user's account - borrowAndTransferSpells(dsa, borrowTokens, borrowAmts); + transferAtokens(aave, dsa, supplyTokens, supplyAmts); + + // Have to borrow from user's account & transfer + borrowAndTransferSpells(aave, dsa, borrowTokens, borrowAmts); isPositionSafe(); } - // function getPosition(address owner) public view returns (AaveData memory data) { - // data = positions[owner]; - // } - - // TODO: have to add more conditions + // TODO: @mubaris - Do we need this? function canMigrate(AaveData memory data) public view returns (bool can) { - // can = true; - // AaveData memory data = getPosition(owner); - - // for (uint i = 0; i < data.supplyTokens.length; i++) { - // IERC20 token = IERC20(data.supplyTokens[i]); - // if (token.balanceOf(address(this)) < data.supplyAmts[i]) { - // can = false; - // } - // } } function onStateReceive(uint256 stateId, bytes calldata receivedData) external { require(stateId > lastStateId, "wrong-data"); lastStateId = stateId; - // (AaveData memory data) = abi.decode(receivedData, (AaveData)); - positions[stateId] = receivedData; // TODO: what's the best way to store user's data to create position later + // TODO: what's the best way to store user's data to create position later. + // Can't do it via any address as user can migrate 2 times + positions[stateId] = receivedData; } function migrate(uint _id) external { bytes memory _data = positions[_id]; + require(_data != bytes(0), "already-migrated"); // TODO: How to resolve this AaveData memory data = abi.decode(_data, (AaveData)); diff --git a/contracts/receivers2/aave-v2-receiver/variables.sol b/contracts/receivers2/aave-v2-receiver/variables.sol new file mode 100644 index 0000000..aa11486 --- /dev/null +++ b/contracts/receivers2/aave-v2-receiver/variables.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.7.0; + +import { + TokenMappingInterface, + AaveLendingPoolProviderInterface, + IndexInterface +} from "./interfaces.sol"; + +contract Variables { + + // This will be used to have debt/collateral ratio always 20% less than liquidation + // TODO: Is this number correct for it? + uint public safeRatioGap = 200000000000000000; // 20%? 2e17 + + // TODO: Add function for flash deposits and withdraw + mapping(address => mapping(address => uint)) flashDeposits; // Flash deposits of particular token + mapping(address => uint) flashAmts; // token amount for flashloan usage (these token will always stay raw in this contract) + + // TODO: Replace this + TokenMappingInterface tokenMapping = TokenMappingInterface(address(2)); + + AaveLendingPoolProviderInterface constant internal aaveProvider = AaveLendingPoolProviderInterface(0xd05e3E715d945B59290df0ae8eF85c1BdB684744); + + // dsa => position + mapping(uint => bytes) public positions; + mapping(address => mapping(address => uint)) public deposits; + + // InstaIndex Address. + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + + // TODO: Set by construtor? + mapping(address => bool) public isSupportedToken; + address[] public supportedTokens; + +} \ No newline at end of file diff --git a/contracts/senders/aave-v2-connector/helpers.sol b/contracts/senders/aave-v2-connector/helpers.sol index 92c5c35..24e57fd 100644 --- a/contracts/senders/aave-v2-connector/helpers.sol +++ b/contracts/senders/aave-v2-connector/helpers.sol @@ -1,7 +1,7 @@ pragma solidity ^0.7.0; import { DSMath } from "../../common/math.sol"; -import { Stores } from "../../common/stores.sol"; +import { Stores } from "../../common/stores-mainnet.sol"; import { AaveLendingPoolProviderInterface, AaveDataProviderInterface, AaveMigratorInterface } from "./interfaces.sol"; abstract contract Helpers is DSMath, Stores { diff --git a/contracts/senders/aave-v2-migrator/helpers.sol b/contracts/senders/aave-v2-migrator/helpers.sol index 77dfab6..5b6b462 100644 --- a/contracts/senders/aave-v2-migrator/helpers.sol +++ b/contracts/senders/aave-v2-migrator/helpers.sol @@ -1,7 +1,7 @@ pragma solidity ^0.7.0; import { DSMath } from "../../common/math.sol"; -import { Stores } from "../../common/stores.sol"; +import { Stores } from "../../common/stores-mainnet.sol"; import { AaveLendingPoolProviderInterface, diff --git a/contracts/senders2/aave-v2-migrator/helpers.sol b/contracts/senders2/aave-v2-migrator/helpers.sol index d382d83..fb7f075 100644 --- a/contracts/senders2/aave-v2-migrator/helpers.sol +++ b/contracts/senders2/aave-v2-migrator/helpers.sol @@ -1,63 +1,23 @@ pragma solidity >=0.7.0; +pragma experimental ABIEncoderV2; import { DSMath } from "../../common/math.sol"; -import { Stores } from "../../common/stores.sol"; +import { Stores } from "../../common/stores-mainnet.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Variables } from "./variables.sol"; + import { AaveLendingPoolProviderInterface, AaveDataProviderInterface, AaveInterface, + ATokenInterface, StateSenderInterface } from "./interfaces.sol"; -abstract contract Helpers is DSMath, Stores { - - using SafeERC20 for IERC20; - - struct AaveDataRaw { - address targetDsa; - uint[] supplyAmts; - uint[] variableBorrowAmts; - uint[] stableBorrowAmts; - address[] supplyTokens; - address[] borrowTokens; - } - - struct AaveData { - address targetDsa; - uint[] supplyAmts; - uint[] borrowAmts; - address[] supplyTokens; - address[] borrowTokens; - } - - /** - * @dev Aave referal code - */ - uint16 constant internal referralCode = 3228; - - address constant internal polygonReceiver = address(2); // Replace this - - /** - * @dev Aave Provider - */ - AaveLendingPoolProviderInterface constant internal aaveProvider = AaveLendingPoolProviderInterface(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5); - - /** - * @dev Aave Data Provider - */ - AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); - - /** - * @dev Polygon State Sync Contract - */ - StateSenderInterface constant internal stateSender = StateSenderInterface(0x28e4F3a7f651294B9564800b2D01f35189A5bFbE); - - function _borrow(address _token, uint _amt) internal { - } +abstract contract Helpers is DSMath, Stores, Variables { function _paybackBehalfOne(AaveInterface aave, address token, uint amt, uint rateMode, address user) private { aave.repay(token, amt, rateMode, user); @@ -91,8 +51,9 @@ abstract contract Helpers is DSMath, Stores { } } - function _PaybackCalculate(AaveInterface aave, AaveDataRaw memory _data, address sourceDsa) internal returns (uint[] stableBorrow, uint[] variableBorrow, uint[] totalBorrow) { + function _PaybackCalculate(AaveInterface aave, AaveDataRaw memory _data, address sourceDsa) internal returns (uint[] memory stableBorrow, uint[] memory variableBorrow, uint[] memory totalBorrow) { for (uint i = 0; i < _data.borrowTokens.length; i++) { + require(isSupportedToken[_data.borrowTokens[i]], "token-not-enabled"); address _token = _data.borrowTokens[i] == ethAddr ? wethAddr : _data.borrowTokens[i]; _data.borrowTokens[i] = _token; @@ -108,30 +69,40 @@ abstract contract Helpers is DSMath, Stores { totalBorrow[i] = add(stableBorrow[i], variableBorrow[i]); if (totalBorrow[i] > 0) { - IERC20(_token).safeApprove(address(aave), totalBorrow[i]); // TODO: Approval is to Aave address of atokens address? + IERC20(_token).approve(address(aave), totalBorrow[i]); // TODO: Approval is to Aave address of atokens address? } aave.borrow(_token, totalBorrow[i], 2, 3088, address(this)); // TODO: Borrowing debt to payback } } - function _getAtokens(AaveInterface aave, address[] memory supplyTokens, uint[] memory supplyAmts, uint fee) internal returns (uint[] finalAmts) { + function _getAtokens(address dsa, AaveInterface aave, address[] memory supplyTokens, uint[] memory supplyAmts) internal returns (uint[] memory finalAmts) { for (uint i = 0; i < supplyTokens.length; i++) { + require(isSupportedToken[supplyTokens[i]], "token-not-enabled"); (address _aToken, ,) = aaveData.getReserveTokensAddresses(supplyTokens[i]); ATokenInterface aTokenContract = ATokenInterface(_aToken); - - // TODO: deduct the fee from finalAmt + uint _finalAmt; if (supplyAmts[i] == uint(-1)) { - // TODO: get maximum balance and set the return variable + _finalAmt = aTokenContract.balanceOf(dsa); } else { - finalAmts[i] = supplyAmts[i]; + _finalAmt = supplyAmts[i]; } - aTokenContract.transferFrom(sourceDsa, address(this), finalAmts[i]); + aTokenContract.transferFrom(dsa, address(this), finalAmts[i]); + + _finalAmt = wmul(_finalAmt, fee); + finalAmts[i] = _finalAmt; + } } - function _checkRatio(AaveData data, uint _safeRatioGap) returns (bool isOk) { - // TODO: Check the debt/collateral ratio should be less than "_safeRatioGap" from Liquidation of that particular user assets + function isPositionSafe() internal returns (bool isOk) { + // TODO: Check the final position health + // @mubaris we need to add the function from Aave to check the health should be "safeRatioGap"(currently set to 20%) below liquidation + require(isOk, "position-at-risk"); + } + + function _checkRatio(AaveData memory data) public returns (bool isOk) { + // TODO: @mubaris Check the debt/collateral ratio should be less than "safeRatioGap" from Liquidation of that particular user assets } } \ No newline at end of file diff --git a/contracts/senders2/aave-v2-migrator/main.sol b/contracts/senders2/aave-v2-migrator/main.sol index bb90c58..db9ef65 100644 --- a/contracts/senders2/aave-v2-migrator/main.sol +++ b/contracts/senders2/aave-v2-migrator/main.sol @@ -3,31 +3,30 @@ pragma experimental ABIEncoderV2; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - import { TokenInterface } from "../../common/interfaces.sol"; import { Helpers } from "./helpers.sol"; -import { AaveInterface, ATokenInterface } from "./interfaces.sol"; +import { AaveInterface, ATokenInterface, IndexInterface } from "./interfaces.sol"; import { Events } from "./events.sol"; contract LiquidityResolver is Helpers, Events { using SafeERC20 for IERC20; - mapping(address => mapping(address => uint)) public deposits; - - // This will be used to have debt/collateral ratio always 20% less than liquidation - // TODO: Is this number correct for it? - uint public safeRatioGap = 20000000000000000; // 20%? - - uint public fee = 200000000000000; // 0.2% on collateral? - - // InstaIndex Address. - IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + event variablesUpdate(uint _safeRatioGap, uint _fee); function updateVariables(uint _safeRatioGap, uint _fee) public { require(msg.sender == instaIndex.master(), "not-master"); safeRatioGap = _safeRatioGap; fee = _fee; - // TODO: Add event + emit variablesUpdate(safeRatioGap, fee); + } + + function addTokenSupport(address[] memory _tokens) public { + require(msg.sender == instaIndex.master(), "not-master"); + for (uint i = 0; i < _tokens.length; i++) { + isSupportedToken[_tokens[i]] = true; + } + supportedTokens = _tokens; + // TODO: add event } function spell(address _target, bytes memory _data) external { @@ -46,25 +45,28 @@ contract LiquidityResolver is Helpers, Events { } } - // TODO: Deposited assets will get deposited into Aave as collateral function deposit(address[] calldata tokens, uint[] calldata amts) external payable { uint _length = tokens.length; require(_length == amts.length, "invalid-length"); + AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); + uint[] memory _amts = new uint[](_length); for (uint256 i = 0; i < _length; i++) { + require(isSupportedToken[tokens[i]], "token-not-enabled"); uint _amt; address _token = tokens[i]; if (_token == ethAddr) { require(msg.value == amts[i]); _amt = msg.value; - TokenInterface(wethAddr).deposit{value: msg.value}(); + aave.deposit(wethAddr, _amt, address(this), 3288); } else { IERC20 tokenContract = IERC20(_token); _amt = amts[i] == uint(-1) ? tokenContract.balanceOf(msg.sender) : amts[i]; tokenContract.safeTransferFrom(msg.sender, address(this), _amt); + aave.deposit(_token, _amt, address(this), 3288); } _amts[i] = _amt; @@ -75,14 +77,16 @@ contract LiquidityResolver is Helpers, Events { emit LogDeposit(msg.sender, tokens, _amts); } - // TODO: If not enough ideal token then withdraw the required amount from Aave. Also, check that it should not make position risky function withdraw(address[] calldata tokens, uint[] calldata amts) external { uint _length = tokens.length; require(_length == amts.length, "invalid-length"); + AaveInterface aave = AaveInterface(aaveProvider.getLendingPool()); + uint[] memory _amts = new uint[](_length); for (uint256 i = 0; i < _length; i++) { + require(isSupportedToken[tokens[i]], "token-not-enabled"); uint _amt = amts[i]; address _token = tokens[i]; uint maxAmt = deposits[msg.sender][_token]; @@ -91,11 +95,23 @@ contract LiquidityResolver is Helpers, Events { _amt = maxAmt; } + // TODO: @everyone check this throughly. Saving 1000 WEI for flashloan WETH. Also, should we make a different contract to handle 2 WEI dydx gas, I think this would be better. if (_token == ethAddr) { - TokenInterface(wethAddr).withdraw(_amt); + TokenInterface _tokenContract = TokenInterface(wethAddr); + uint _ethBal = address(this).balance; + uint _tknBal = _tokenContract.balanceOf(address(this)); + if ((_ethBal + _tknBal + 1000) < _amt) { + aave.withdraw(wethAddr, sub((_amt + 1000), (_tknBal + _ethBal)), address(this)); + } + _tokenContract.withdraw((sub(_amt, _ethBal))); msg.sender.call{value: _amt}(""); } else { - IERC20(_token).safeTransfer(msg.sender, _amt); + IERC20 _tokenContract = IERC20(_token); + uint _tknBal = _tokenContract.balanceOf(address(this)); + if (_tknBal < _amt) { + aave.withdraw(_token, sub(_amt, _tknBal), address(this)); + } + _tokenContract.safeTransfer(msg.sender, _amt); } _amts[i] = _amt; @@ -103,10 +119,13 @@ contract LiquidityResolver is Helpers, Events { deposits[msg.sender][_token] = sub(maxAmt, _amt); } + isPositionSafe(); + emit LogWithdraw(msg.sender, tokens, _amts); } - // TODO: Things to factor + // TODO: @mubaris Things to factor + // use supportedTokens array to loop through // If there is same token supply and borrow, then close the smaller one // If there is ideal token then payback or deposit according to the position // Object is the decrease the ratio and pay as less interest @@ -141,7 +160,7 @@ contract MigrateResolver is LiquidityResolver { _PaybackStable(_data.borrowTokens.length, aave, _data.borrowTokens, stableBorrows, sourceDsa); _PaybackVariable(_data.borrowTokens.length, aave, _data.borrowTokens, variableBorrows, sourceDsa); - (uint[] totalSupplies) = _getAtokens(aave, _data.supplyTokens, _data.supplyAmts, fee); + (uint[] totalSupplies) = _getAtokens(sourceDsa, aave, _data.supplyTokens, _data.supplyAmts, fee); // Aave on Polygon doesn't have stable borrowing so we'll borrow all the debt in variable AaveData memory data; @@ -153,11 +172,13 @@ contract MigrateResolver is LiquidityResolver { data.targetDsa = _data.targetDsa; data.borrowAmts = totalBorrows; - // TODO: Check the amount that user is trying to migrate is 20% below the Liquidation - bool isOk = _checkRatio(data, safeRatioGap); + // Checks the amount that user is trying to migrate is 20% below the Liquidation + bool isOk = _checkRatio(data); require(isOk, "position-risky-to-migrate"); - bytes memory positionData = data; // TODO: Can we do anything else to make the data more secure? (It's secure already) + isPositionSafe(); + + bytes memory positionData = data; // TODO: @everyone Can we do anything else to make the data more secure? (It's secure already) stateSender.syncState(polygonReceiver, positionData); emit LogAaveV2Migrate( @@ -178,16 +199,19 @@ contract MigrateResolver is LiquidityResolver { function migrateWithFlash(AaveDataRaw calldata _data, uint ethAmt) external { bytes data = abi.encode(_data, msg.sender, ethAmt); - // TODO: integrate dydx flashloan and borrow "ethAmt" and transfer ETH to this address + // TODO: @everyone integrate dydx flashloan and borrow "ethAmt" and transfer ETH to this address + // Should we create a new contract for flashloan or interact directly from this contract? Mainly to resolve 2 WEI bug of dydx flashloan } + // TODO: @everyone function callFunction( address sender, Account.Info memory account, bytes memory data ) public override { require(sender == address(this), "wrong-sender"); + // require(msg.sender == dydxFlash, "wrong-sender"); // TODO: msg.sender should be flashloan contract (address l2DSA, AaveDataRaw memory _data, address sourceDsa, uint ethAmt) = abi.decode( data, (address, AaveDataRaw, address, uint) diff --git a/contracts/senders2/aave-v2-migrator/variables.sol b/contracts/senders2/aave-v2-migrator/variables.sol new file mode 100644 index 0000000..e63c5f9 --- /dev/null +++ b/contracts/senders2/aave-v2-migrator/variables.sol @@ -0,0 +1,65 @@ +pragma solidity ^0.7.0; + +import { + AaveLendingPoolProviderInterface, + AaveDataProviderInterface, + StateSenderInterface, + IndexInterface +} from "./interfaces.sol"; + +contract Variables { + + struct AaveDataRaw { + address targetDsa; + uint[] supplyAmts; + uint[] variableBorrowAmts; + uint[] stableBorrowAmts; + address[] supplyTokens; + address[] borrowTokens; + } + + struct AaveData { + address targetDsa; + uint[] supplyAmts; + uint[] borrowAmts; + address[] supplyTokens; + address[] borrowTokens; + } + + /** + * @dev Aave referal code + */ + uint16 constant internal referralCode = 3228; + + address constant internal polygonReceiver = address(2); // Replace this + + // This will be used to have debt/collateral ratio always 20% less than liquidation + // TODO: Is this number correct for it? + // TODO: Add update function for this + uint public safeRatioGap = 20000000000000000; // 20%? + uint public fee = 998000000000000000; // 0.2% (99.8%) on collateral? TODO: Is this right? + // TODO: Set by construtor? + mapping(address => bool) public isSupportedToken; + address[] public supportedTokens; + + /** + * @dev Aave Provider + */ + AaveLendingPoolProviderInterface constant internal aaveProvider = AaveLendingPoolProviderInterface(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5); + + /** + * @dev Aave Data Provider + */ + AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); + + /** + * @dev Polygon State Sync Contract + */ + StateSenderInterface constant internal stateSender = StateSenderInterface(0x28e4F3a7f651294B9564800b2D01f35189A5bFbE); + + mapping(address => mapping(address => uint)) public deposits; + + // InstaIndex Address. + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + +} \ No newline at end of file