mirror of
https://github.com/Instadapp/dsa-polygon-migration.git
synced 2024-07-29 22:27:58 +00:00
Merge pull request #2 from Instadapp/aave-polygon-updates
Major updates in Migration
This commit is contained in:
commit
5c65053570
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.sol linguist-language=Solidity
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"solidity.compileUsingRemoteVersion": "v0.7.0+commit.9e61f92b"
|
||||
}
|
13
contracts/bin/implementations/aave-v2-migrator/events.sol
Normal file
13
contracts/bin/implementations/aave-v2-migrator/events.sol
Normal file
|
@ -0,0 +1,13 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Events {
|
||||
event LogMigrateAaveV2(
|
||||
address indexed owner,
|
||||
address[] supplyTokens,
|
||||
address[] borrowTokens,
|
||||
uint[] supplyAmts,
|
||||
uint[] variableBorrowAmts,
|
||||
uint[] stableBorrowAmts
|
||||
);
|
||||
}
|
31
contracts/bin/implementations/aave-v2-migrator/helpers.sol
Normal file
31
contracts/bin/implementations/aave-v2-migrator/helpers.sol
Normal file
|
@ -0,0 +1,31 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Stores } from "../../common/stores-polygon.sol";
|
||||
|
||||
import {
|
||||
AaveLendingPoolProviderInterface,
|
||||
AaveDataProviderInterface,
|
||||
AaveInterface
|
||||
} from "./interfaces.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Stores {
|
||||
/**
|
||||
* @dev Aave referal code
|
||||
*/
|
||||
uint16 constant internal referralCode = 3228;
|
||||
|
||||
/**
|
||||
* @dev Aave Provider (TODO - Replace the address)
|
||||
*/
|
||||
AaveLendingPoolProviderInterface constant internal aaveProvider = AaveLendingPoolProviderInterface(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5);
|
||||
|
||||
/**
|
||||
* @dev Aave Data Provider (TODO - Replace the address)
|
||||
*/
|
||||
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d);
|
||||
|
||||
function getIsColl(address token) internal view returns (bool isCol) {
|
||||
(, , , , , , , , isCol) = aaveData.getUserReserveData(token, address(this));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface AaveInterface {
|
||||
function deposit(address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode) external;
|
||||
function withdraw(address _asset, uint256 _amount, address _to) external;
|
||||
function borrow(
|
||||
address _asset,
|
||||
uint256 _amount,
|
||||
uint256 _interestRateMode,
|
||||
uint16 _referralCode,
|
||||
address _onBehalfOf
|
||||
) external;
|
||||
function repay(address _asset, uint256 _amount, uint256 _rateMode, address _onBehalfOf) external;
|
||||
function setUserUseReserveAsCollateral(address _asset, bool _useAsCollateral) external;
|
||||
function getUserAccountData(address user) external view returns (
|
||||
uint256 totalCollateralETH,
|
||||
uint256 totalDebtETH,
|
||||
uint256 availableBorrowsETH,
|
||||
uint256 currentLiquidationThreshold,
|
||||
uint256 ltv,
|
||||
uint256 healthFactor
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveLendingPoolProviderInterface {
|
||||
function getLendingPool() external view returns (address);
|
||||
}
|
||||
|
||||
// Aave Protocol Data Provider
|
||||
interface AaveDataProviderInterface {
|
||||
function getReserveTokensAddresses(address _asset) external view returns (
|
||||
address aTokenAddress,
|
||||
address stableDebtTokenAddress,
|
||||
address variableDebtTokenAddress
|
||||
);
|
||||
function getUserReserveData(address _asset, address _user) external view returns (
|
||||
uint256 currentATokenBalance,
|
||||
uint256 currentStableDebt,
|
||||
uint256 currentVariableDebt,
|
||||
uint256 principalStableDebt,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 liquidityRate,
|
||||
uint40 stableRateLastUpdated,
|
||||
bool usageAsCollateralEnabled
|
||||
);
|
||||
function getReserveConfigurationData(address asset) external view returns (
|
||||
uint256 decimals,
|
||||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus,
|
||||
uint256 reserveFactor,
|
||||
bool usageAsCollateralEnabled,
|
||||
bool borrowingEnabled,
|
||||
bool stableBorrowRateEnabled,
|
||||
bool isActive,
|
||||
bool isFrozen
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveAddressProviderRegistryInterface {
|
||||
function getAddressesProvidersList() external view returns (address[] memory);
|
||||
}
|
||||
|
||||
interface ATokenInterface {
|
||||
function scaledBalanceOf(address _user) external view returns (uint256);
|
||||
function isTransferAllowed(address _user, uint256 _amount) external view returns (bool);
|
||||
function balanceOf(address _user) external view returns(uint256);
|
||||
function transferFrom(address, address, uint) external returns (bool);
|
||||
function approve(address, uint256) external;
|
||||
}
|
||||
|
||||
struct AaveData {
|
||||
bool isFinal;
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
uint[] variableBorrowAmts;
|
||||
uint[] stableBorrowAmts;
|
||||
address[] supplyTokens;
|
||||
address[] borrowTokens;
|
||||
}
|
||||
|
||||
interface ReceiverInterface {
|
||||
function getPosition(address) external view returns (AaveData memory);
|
||||
}
|
55
contracts/bin/implementations/aave-v2-migrator/main.sol
Normal file
55
contracts/bin/implementations/aave-v2-migrator/main.sol
Normal file
|
@ -0,0 +1,55 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
import { TokenInterface, AccountInterface } from "../../common/interfaces.sol";
|
||||
import { AaveInterface, ReceiverInterface, AaveData } from "./interfaces.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
contract AaveMigratorResolver is Helpers, Events {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
ReceiverInterface public immutable receiver;
|
||||
|
||||
constructor(address _receiver) {
|
||||
receiver = ReceiverInterface(_receiver);
|
||||
}
|
||||
|
||||
function migrateAave(address owner) external payable returns (bytes32) {
|
||||
require(msg.sender == address(receiver) && AccountInterface(address(this)).isAuth(owner), "not-authorized");
|
||||
AaveData memory data = receiver.getPosition(owner);
|
||||
require(!data.isFinal, "already-migrated");
|
||||
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
|
||||
for (uint i = 0; i < data.supplyTokens.length; i++) {
|
||||
TokenInterface token = TokenInterface(data.supplyTokens[i]);
|
||||
uint amt = data.supplyAmts[i];
|
||||
token.approve(address(aave), amt);
|
||||
|
||||
aave.deposit(address(token), amt, address(this), referralCode);
|
||||
if (!getIsColl(address(token))) {
|
||||
aave.setUserUseReserveAsCollateral(address(token), true);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < data.borrowTokens.length; i++) {
|
||||
address token = data.borrowTokens[i];
|
||||
uint variableAmt = data.variableBorrowAmts[i];
|
||||
uint stableAmt = data.stableBorrowAmts[i];
|
||||
|
||||
if (variableAmt > 0) {
|
||||
aave.borrow(token, variableAmt, 2, referralCode, address(this));
|
||||
}
|
||||
if (stableAmt > 0) {
|
||||
aave.borrow(token, stableAmt, 1, referralCode, address(this));
|
||||
}
|
||||
|
||||
uint totalAmt = add(variableAmt, stableAmt);
|
||||
IERC20(token).safeTransfer(address(receiver), totalAmt);
|
||||
}
|
||||
}
|
||||
}
|
16
contracts/bin/receivers/aave-v2-receiver/events.sol
Normal file
16
contracts/bin/receivers/aave-v2-receiver/events.sol
Normal file
|
@ -0,0 +1,16 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
|
||||
event LogWithdraw(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
}
|
21
contracts/bin/receivers/aave-v2-receiver/helpers.sol
Normal file
21
contracts/bin/receivers/aave-v2-receiver/helpers.sol
Normal file
|
@ -0,0 +1,21 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { TokenMappingInterface, AaveData } from "./interfaces.sol";
|
||||
|
||||
abstract contract Helpers is DSMath {
|
||||
// Replace this
|
||||
TokenMappingInterface tokenMapping = TokenMappingInterface(address(2));
|
||||
|
||||
function remapTokens(AaveData memory data) internal returns (AaveData memory) {
|
||||
for (uint i = 0; i < data.supplyTokens.length; i++) {
|
||||
data.supplyTokens[i] = tokenMapping.getMapping(data.supplyTokens[i]);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < data.borrowTokens.length; i++) {
|
||||
data.borrowTokens[i] = tokenMapping.getMapping(data.borrowTokens[i]);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
28
contracts/bin/receivers/aave-v2-receiver/interfaces.sol
Normal file
28
contracts/bin/receivers/aave-v2-receiver/interfaces.sol
Normal file
|
@ -0,0 +1,28 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface AccountInterface {
|
||||
function enable(address) external;
|
||||
function disable(address) external;
|
||||
function isAuth(address) external view returns (bool);
|
||||
function cast(
|
||||
string[] calldata _targets,
|
||||
bytes[] calldata _datas,
|
||||
address _origin
|
||||
) external payable returns (bytes32);
|
||||
function migrateAave(address) external payable returns (bytes32);
|
||||
}
|
||||
|
||||
interface TokenMappingInterface {
|
||||
function getMapping(address) external view returns (address);
|
||||
}
|
||||
|
||||
struct AaveData {
|
||||
bool isFinal;
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
uint[] variableBorrowAmts;
|
||||
uint[] stableBorrowAmts;
|
||||
address[] supplyTokens;
|
||||
address[] borrowTokens;
|
||||
}
|
115
contracts/bin/receivers/aave-v2-receiver/main.sol
Normal file
115
contracts/bin/receivers/aave-v2-receiver/main.sol
Normal file
|
@ -0,0 +1,115 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
import { AccountInterface, AaveData } from "./interfaces.sol";
|
||||
import { Events } from "./events.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
|
||||
contract MigrateResolver is Helpers, Events {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
mapping (address => AaveData) public positions;
|
||||
mapping(address => mapping(address => uint)) deposits;
|
||||
|
||||
function deposit(address[] calldata tokens, uint[] calldata amts) external {
|
||||
uint _length = tokens.length;
|
||||
require(_length == amts.length, "invalid-length");
|
||||
|
||||
uint[] memory _amts = new uint[](_length);
|
||||
|
||||
for (uint256 i = 0; i < _length; i++) {
|
||||
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);
|
||||
|
||||
deposits[msg.sender][_token] = _amt;
|
||||
_amts[i] = _amt;
|
||||
}
|
||||
|
||||
emit LogDeposit(msg.sender, tokens, _amts);
|
||||
}
|
||||
|
||||
function withdraw(address[] calldata tokens, uint[] calldata amts) external {
|
||||
uint _length = tokens.length;
|
||||
require(_length == amts.length, "invalid-length");
|
||||
|
||||
uint[] memory _amts = new uint[](_length);
|
||||
|
||||
for (uint256 i = 0; i < _length; i++) {
|
||||
uint _amt = amts[i];
|
||||
address _token = tokens[i];
|
||||
uint maxAmt = deposits[msg.sender][_token];
|
||||
|
||||
if (_amt > maxAmt) {
|
||||
_amt = maxAmt;
|
||||
}
|
||||
|
||||
IERC20(_token).safeTransfer(msg.sender, _amt);
|
||||
|
||||
deposits[msg.sender][_token] = sub(maxAmt, _amt);
|
||||
|
||||
_amts[i] = _amt;
|
||||
}
|
||||
|
||||
emit LogWithdraw(msg.sender, tokens, _amts);
|
||||
}
|
||||
}
|
||||
|
||||
contract AaveV2Migrator is MigrateResolver {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
uint private lastStateId;
|
||||
|
||||
function _migratePosition(address owner) internal {
|
||||
AaveData storage data = positions[owner];
|
||||
|
||||
require(!data.isFinal, "already-migrated");
|
||||
|
||||
for (uint i = 0; i < data.supplyTokens.length; i++) {
|
||||
IERC20(data.supplyTokens[i]).safeTransfer(data.targetDsa, data.supplyAmts[i]);
|
||||
}
|
||||
|
||||
AccountInterface(data.targetDsa).migrateAave(owner);
|
||||
data.isFinal = true;
|
||||
}
|
||||
|
||||
function getPosition(address owner) public view returns (AaveData memory data) {
|
||||
data = positions[owner];
|
||||
}
|
||||
|
||||
function canMigrate(address owner) 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;
|
||||
|
||||
(address owner, AaveData memory data) = abi.decode(receivedData, (address, AaveData));
|
||||
positions[owner] = remapTokens(data);
|
||||
|
||||
if (canMigrate(owner)) {
|
||||
_migratePosition(owner);
|
||||
}
|
||||
}
|
||||
|
||||
function migrate(address owner) external {
|
||||
require(canMigrate(owner), "not-enough-liquidity");
|
||||
|
||||
_migratePosition(owner);
|
||||
}
|
||||
}
|
10
contracts/bin/senders/aave-v2-connector/events.sol
Normal file
10
contracts/bin/senders/aave-v2-connector/events.sol
Normal file
|
@ -0,0 +1,10 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogAaveV2Migrate(
|
||||
address indexed user,
|
||||
address indexed targetDsa,
|
||||
address[] supplyTokens,
|
||||
address[] borrowTokens
|
||||
);
|
||||
}
|
15
contracts/bin/senders/aave-v2-connector/helpers.sol
Normal file
15
contracts/bin/senders/aave-v2-connector/helpers.sol
Normal file
|
@ -0,0 +1,15 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Stores } from "../../common/stores-mainnet.sol";
|
||||
import { AaveLendingPoolProviderInterface, AaveDataProviderInterface, AaveMigratorInterface } from "./interfaces.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Stores {
|
||||
|
||||
AaveMigratorInterface constant internal migrator = AaveMigratorInterface(address(2)); // Replace this (Migrator contract)
|
||||
|
||||
/**
|
||||
* @dev Aave Data Provider
|
||||
*/
|
||||
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d);
|
||||
}
|
87
contracts/bin/senders/aave-v2-connector/interfaces.sol
Normal file
87
contracts/bin/senders/aave-v2-connector/interfaces.sol
Normal file
|
@ -0,0 +1,87 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface AaveInterface {
|
||||
function deposit(address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode) external;
|
||||
function withdraw(address _asset, uint256 _amount, address _to) external;
|
||||
function borrow(
|
||||
address _asset,
|
||||
uint256 _amount,
|
||||
uint256 _interestRateMode,
|
||||
uint16 _referralCode,
|
||||
address _onBehalfOf
|
||||
) external;
|
||||
function repay(address _asset, uint256 _amount, uint256 _rateMode, address _onBehalfOf) external;
|
||||
function setUserUseReserveAsCollateral(address _asset, bool _useAsCollateral) external;
|
||||
function getUserAccountData(address user) external view returns (
|
||||
uint256 totalCollateralETH,
|
||||
uint256 totalDebtETH,
|
||||
uint256 availableBorrowsETH,
|
||||
uint256 currentLiquidationThreshold,
|
||||
uint256 ltv,
|
||||
uint256 healthFactor
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveLendingPoolProviderInterface {
|
||||
function getLendingPool() external view returns (address);
|
||||
}
|
||||
|
||||
// Aave Protocol Data Provider
|
||||
interface AaveDataProviderInterface {
|
||||
function getReserveTokensAddresses(address _asset) external view returns (
|
||||
address aTokenAddress,
|
||||
address stableDebtTokenAddress,
|
||||
address variableDebtTokenAddress
|
||||
);
|
||||
function getUserReserveData(address _asset, address _user) external view returns (
|
||||
uint256 currentATokenBalance,
|
||||
uint256 currentStableDebt,
|
||||
uint256 currentVariableDebt,
|
||||
uint256 principalStableDebt,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 liquidityRate,
|
||||
uint40 stableRateLastUpdated,
|
||||
bool usageAsCollateralEnabled
|
||||
);
|
||||
function getReserveConfigurationData(address asset) external view returns (
|
||||
uint256 decimals,
|
||||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus,
|
||||
uint256 reserveFactor,
|
||||
bool usageAsCollateralEnabled,
|
||||
bool borrowingEnabled,
|
||||
bool stableBorrowRateEnabled,
|
||||
bool isActive,
|
||||
bool isFrozen
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveAddressProviderRegistryInterface {
|
||||
function getAddressesProvidersList() external view returns (address[] memory);
|
||||
}
|
||||
|
||||
interface ATokenInterface {
|
||||
function scaledBalanceOf(address _user) external view returns (uint256);
|
||||
function isTransferAllowed(address _user, uint256 _amount) external view returns (bool);
|
||||
function balanceOf(address _user) external view returns(uint256);
|
||||
function transferFrom(address, address, uint) external returns (bool);
|
||||
function approve(address, uint256) external;
|
||||
}
|
||||
|
||||
interface AaveMigratorInterface {
|
||||
function migrate(address, address, address[] calldata, address[] calldata) external;
|
||||
function migrate(address, AaveData memory) external;
|
||||
}
|
||||
|
||||
struct AaveData {
|
||||
bool isFinal;
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
uint[] variableBorrowAmts;
|
||||
uint[] stableBorrowAmts;
|
||||
address[] supplyTokens;
|
||||
address[] borrowTokens;
|
||||
}
|
72
contracts/bin/senders/aave-v2-connector/main.sol
Normal file
72
contracts/bin/senders/aave-v2-connector/main.sol
Normal file
|
@ -0,0 +1,72 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { TokenInterface, AccountInterface } from "../../common/interfaces.sol";
|
||||
import { AaveInterface, ATokenInterface, AaveData } from "./interfaces.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
contract AaveMigrateResolver is Helpers, Events {
|
||||
|
||||
// function migrate(
|
||||
// address targetDsa,
|
||||
// address[] calldata supplyTokens,
|
||||
// address[] calldata borrowTokens
|
||||
// ) external payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
// require(supplyTokens.length > 0, "0-length-not-allowed");
|
||||
// require(targetDsa != address(0), "invalid-address");
|
||||
|
||||
// for (uint i = 0; i < supplyTokens.length; i++) {
|
||||
// address _token = supplyTokens[i] == ethAddr ? wethAddr : supplyTokens[i];
|
||||
// (address _aToken, ,) = aaveData.getReserveTokensAddresses(_token);
|
||||
// ATokenInterface _aTokenContract = ATokenInterface(_aToken);
|
||||
// _aTokenContract.approve(address(migrator), _aTokenContract.balanceOf(address(this)));
|
||||
// }
|
||||
|
||||
// migrator.migrate(msg.sender, targetDsa, supplyTokens, borrowTokens);
|
||||
|
||||
// _eventName = "LogAaveV2Migrate(address,address,address[],address[])";
|
||||
// _eventParam = abi.encode(msg.sender, targetDsa, supplyTokens, borrowTokens);
|
||||
// }
|
||||
|
||||
function migrate(
|
||||
AaveData calldata _data
|
||||
) external payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
require(_data.supplyTokens.length > 0, "0-length-not-allowed");
|
||||
require(_data.supplyTokens.length == _data.supplyAmts.length, "invalid-length");
|
||||
require(_data.targetDsa != address(0), "invalid-address");
|
||||
require(!_data.isFinal, "wrong-data");
|
||||
|
||||
AaveData memory data;
|
||||
|
||||
data.borrowTokens = _data.borrowTokens;
|
||||
data.isFinal = _data.isFinal;
|
||||
data.stableBorrowAmts = _data.stableBorrowAmts;
|
||||
data.supplyAmts = _data.supplyAmts;
|
||||
data.supplyTokens = _data.supplyTokens;
|
||||
data.targetDsa = _data.targetDsa;
|
||||
data.variableBorrowAmts = _data.variableBorrowAmts;
|
||||
|
||||
for (uint i = 0; i < data.supplyTokens.length; i++) {
|
||||
address _token = data.supplyTokens[i] == ethAddr ? wethAddr : data.supplyTokens[i];
|
||||
data.supplyTokens[i] = _token;
|
||||
(address _aToken, ,) = aaveData.getReserveTokensAddresses(_token);
|
||||
ATokenInterface _aTokenContract = ATokenInterface(_aToken);
|
||||
|
||||
if (data.supplyAmts[i] == uint(-1)) {
|
||||
data.supplyAmts[i] = _aTokenContract.balanceOf(address(this));
|
||||
}
|
||||
|
||||
_aTokenContract.approve(address(migrator), data.supplyAmts[i]);
|
||||
}
|
||||
|
||||
migrator.migrate(msg.sender, data);
|
||||
|
||||
_eventName = "LogAaveV2Migrate(address,address,address[],address[])";
|
||||
_eventParam = abi.encode(msg.sender, data.targetDsa, data.supplyTokens, data.borrowTokens);
|
||||
}
|
||||
}
|
||||
|
||||
contract AaveV2Migrator is AaveMigrateResolver {
|
||||
string constant public name = "AaveV2PolygonMigrator-v1";
|
||||
}
|
26
contracts/bin/senders/aave-v2-migrator/events.sol
Normal file
26
contracts/bin/senders/aave-v2-migrator/events.sol
Normal file
|
@ -0,0 +1,26 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
|
||||
event LogWithdraw(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
|
||||
event LogAaveV2Migrate(
|
||||
address indexed user,
|
||||
address indexed targetDsa,
|
||||
address[] supplyTokens,
|
||||
address[] borrowTokens,
|
||||
uint[] supplyAmts,
|
||||
uint[] variableBorrowAmts,
|
||||
uint[] stableBorrowAmts
|
||||
);
|
||||
}
|
80
contracts/bin/senders/aave-v2-migrator/helpers.sol
Normal file
80
contracts/bin/senders/aave-v2-migrator/helpers.sol
Normal file
|
@ -0,0 +1,80 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Stores } from "../../common/stores-mainnet.sol";
|
||||
|
||||
import {
|
||||
AaveLendingPoolProviderInterface,
|
||||
AaveDataProviderInterface,
|
||||
AaveInterface,
|
||||
StateSenderInterface
|
||||
} from "./interfaces.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Stores {
|
||||
/**
|
||||
* @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 _paybackBehalfOne(AaveInterface aave, address token, uint amt, uint rateMode, address user) private {
|
||||
aave.repay(token, amt, rateMode, user);
|
||||
}
|
||||
|
||||
function _PaybackStable(
|
||||
uint _length,
|
||||
AaveInterface aave,
|
||||
address[] memory tokens,
|
||||
uint256[] memory amts,
|
||||
address user
|
||||
) internal {
|
||||
for (uint i = 0; i < _length; i++) {
|
||||
if (amts[i] > 0) {
|
||||
_paybackBehalfOne(aave, tokens[i], amts[i], 1, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _PaybackVariable(
|
||||
uint _length,
|
||||
AaveInterface aave,
|
||||
address[] memory tokens,
|
||||
uint256[] memory amts,
|
||||
address user
|
||||
) internal {
|
||||
for (uint i = 0; i < _length; i++) {
|
||||
if (amts[i] > 0) {
|
||||
_paybackBehalfOne(aave, tokens[i], amts[i], 2, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _Withdraw(
|
||||
uint _length,
|
||||
AaveInterface aave,
|
||||
address[] memory tokens,
|
||||
uint256[] memory amts
|
||||
) internal {
|
||||
for (uint i = 0; i < _length; i++) {
|
||||
if (amts[i] > 0) {
|
||||
aave.withdraw(tokens[i], amts[i], address(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
contracts/bin/senders/aave-v2-migrator/interfaces.sol
Normal file
77
contracts/bin/senders/aave-v2-migrator/interfaces.sol
Normal file
|
@ -0,0 +1,77 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface AaveInterface {
|
||||
function deposit(address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode) external;
|
||||
function withdraw(address _asset, uint256 _amount, address _to) external;
|
||||
function borrow(
|
||||
address _asset,
|
||||
uint256 _amount,
|
||||
uint256 _interestRateMode,
|
||||
uint16 _referralCode,
|
||||
address _onBehalfOf
|
||||
) external;
|
||||
function repay(address _asset, uint256 _amount, uint256 _rateMode, address _onBehalfOf) external;
|
||||
function setUserUseReserveAsCollateral(address _asset, bool _useAsCollateral) external;
|
||||
function getUserAccountData(address user) external view returns (
|
||||
uint256 totalCollateralETH,
|
||||
uint256 totalDebtETH,
|
||||
uint256 availableBorrowsETH,
|
||||
uint256 currentLiquidationThreshold,
|
||||
uint256 ltv,
|
||||
uint256 healthFactor
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveLendingPoolProviderInterface {
|
||||
function getLendingPool() external view returns (address);
|
||||
}
|
||||
|
||||
// Aave Protocol Data Provider
|
||||
interface AaveDataProviderInterface {
|
||||
function getReserveTokensAddresses(address _asset) external view returns (
|
||||
address aTokenAddress,
|
||||
address stableDebtTokenAddress,
|
||||
address variableDebtTokenAddress
|
||||
);
|
||||
function getUserReserveData(address _asset, address _user) external view returns (
|
||||
uint256 currentATokenBalance,
|
||||
uint256 currentStableDebt,
|
||||
uint256 currentVariableDebt,
|
||||
uint256 principalStableDebt,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 liquidityRate,
|
||||
uint40 stableRateLastUpdated,
|
||||
bool usageAsCollateralEnabled
|
||||
);
|
||||
function getReserveConfigurationData(address asset) external view returns (
|
||||
uint256 decimals,
|
||||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus,
|
||||
uint256 reserveFactor,
|
||||
bool usageAsCollateralEnabled,
|
||||
bool borrowingEnabled,
|
||||
bool stableBorrowRateEnabled,
|
||||
bool isActive,
|
||||
bool isFrozen
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveAddressProviderRegistryInterface {
|
||||
function getAddressesProvidersList() external view returns (address[] memory);
|
||||
}
|
||||
|
||||
interface ATokenInterface {
|
||||
function scaledBalanceOf(address _user) external view returns (uint256);
|
||||
function isTransferAllowed(address _user, uint256 _amount) external view returns (bool);
|
||||
function balanceOf(address _user) external view returns(uint256);
|
||||
function transferFrom(address, address, uint) external returns (bool);
|
||||
function approve(address, uint256) external;
|
||||
}
|
||||
|
||||
interface StateSenderInterface {
|
||||
function syncState(address receiver, bytes calldata data) external;
|
||||
function register(address sender, address receiver) external;
|
||||
}
|
241
contracts/bin/senders/aave-v2-migrator/main.sol
Normal file
241
contracts/bin/senders/aave-v2-migrator/main.sol
Normal file
|
@ -0,0 +1,241 @@
|
|||
pragma solidity ^0.7.0;
|
||||
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 { Events } from "./events.sol";
|
||||
|
||||
contract LiquidityResolver is Helpers, Events {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
mapping(address => mapping(address => uint)) deposits;
|
||||
|
||||
function deposit(address[] calldata tokens, uint[] calldata amts) external payable {
|
||||
uint _length = tokens.length;
|
||||
require(_length == amts.length, "invalid-length");
|
||||
|
||||
uint[] memory _amts = new uint[](_length);
|
||||
|
||||
for (uint256 i = 0; i < _length; i++) {
|
||||
uint _amt;
|
||||
address _token = tokens[i];
|
||||
if (_token == ethAddr) {
|
||||
require(msg.value == amts[i]);
|
||||
_amt = msg.value;
|
||||
|
||||
TokenInterface(wethAddr).deposit{value: msg.value}();
|
||||
} else {
|
||||
IERC20 tokenContract = IERC20(_token);
|
||||
_amt = amts[i] == uint(-1) ? tokenContract.balanceOf(msg.sender) : amts[i];
|
||||
tokenContract.safeTransferFrom(msg.sender, address(this), _amt);
|
||||
}
|
||||
|
||||
_amts[i] = _amt;
|
||||
|
||||
deposits[msg.sender][_token] = _amt;
|
||||
}
|
||||
|
||||
emit LogDeposit(msg.sender, tokens, _amts);
|
||||
}
|
||||
|
||||
function withdraw(address[] calldata tokens, uint[] calldata amts) external {
|
||||
uint _length = tokens.length;
|
||||
require(_length == amts.length, "invalid-length");
|
||||
|
||||
uint[] memory _amts = new uint[](_length);
|
||||
|
||||
for (uint256 i = 0; i < _length; i++) {
|
||||
uint _amt = amts[i];
|
||||
address _token = tokens[i];
|
||||
uint maxAmt = deposits[msg.sender][_token];
|
||||
|
||||
if (_amt > maxAmt) {
|
||||
_amt = maxAmt;
|
||||
}
|
||||
|
||||
if (_token == ethAddr) {
|
||||
TokenInterface(wethAddr).withdraw(_amt);
|
||||
msg.sender.call{value: _amt}("");
|
||||
} else {
|
||||
IERC20(_token).safeTransfer(msg.sender, _amt);
|
||||
}
|
||||
|
||||
_amts[i] = _amt;
|
||||
|
||||
deposits[msg.sender][_token] = sub(maxAmt, _amt);
|
||||
}
|
||||
|
||||
emit LogWithdraw(msg.sender, tokens, _amts);
|
||||
}
|
||||
}
|
||||
|
||||
contract MigrateResolver is LiquidityResolver {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
struct AaveData {
|
||||
bool isFinal;
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
uint[] variableBorrowAmts;
|
||||
uint[] stableBorrowAmts;
|
||||
address[] supplyTokens;
|
||||
address[] borrowTokens;
|
||||
}
|
||||
|
||||
mapping (address => AaveData) public positions;
|
||||
|
||||
function migrate(address owner, AaveData calldata _data) external {
|
||||
require(_data.supplyTokens.length > 0, "0-length-not-allowed");
|
||||
require(_data.targetDsa != address(0), "invalid-address");
|
||||
require(_data.supplyTokens.length == _data.supplyAmts.length, "invalid-length");
|
||||
require(
|
||||
_data.borrowTokens.length == _data.variableBorrowAmts.length &&
|
||||
_data.borrowTokens.length == _data.stableBorrowAmts.length,
|
||||
"invalid-length"
|
||||
);
|
||||
|
||||
AaveData memory data;
|
||||
|
||||
data.borrowTokens = _data.borrowTokens;
|
||||
data.isFinal = _data.isFinal;
|
||||
data.stableBorrowAmts = _data.stableBorrowAmts;
|
||||
data.supplyAmts = _data.supplyAmts;
|
||||
data.supplyTokens = _data.supplyTokens;
|
||||
data.targetDsa = _data.targetDsa;
|
||||
data.variableBorrowAmts = _data.variableBorrowAmts;
|
||||
|
||||
address sourceDsa = msg.sender;
|
||||
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
|
||||
(,,,,,uint healthFactor) = aave.getUserAccountData(sourceDsa);
|
||||
require(healthFactor > 1e18, "position-not-safe");
|
||||
|
||||
for (uint i = 0; i < data.supplyTokens.length; i++) {
|
||||
(address _aToken, ,) = aaveData.getReserveTokensAddresses(data.supplyTokens[i]);
|
||||
ATokenInterface aTokenContract = ATokenInterface(_aToken);
|
||||
|
||||
aTokenContract.transferFrom(msg.sender, address(this), data.supplyAmts[i]);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < data.borrowTokens.length; i++) {
|
||||
address _token = data.borrowTokens[i] == ethAddr ? wethAddr : data.borrowTokens[i];
|
||||
data.borrowTokens[i] = _token;
|
||||
|
||||
(
|
||||
,
|
||||
uint stableDebt,
|
||||
uint variableDebt,
|
||||
,,,,,
|
||||
) = aaveData.getUserReserveData(_token, sourceDsa);
|
||||
|
||||
data.stableBorrowAmts[i] = data.stableBorrowAmts[i] == uint(-1) ? stableDebt : data.stableBorrowAmts[i];
|
||||
data.variableBorrowAmts[i] = data.variableBorrowAmts[i] == uint(-1) ? variableDebt : data.variableBorrowAmts[i];
|
||||
|
||||
|
||||
uint totalBorrowAmt = add(data.stableBorrowAmts[i], data.variableBorrowAmts[i]);
|
||||
if (totalBorrowAmt > 0) {
|
||||
IERC20(_token).safeApprove(address(aave), totalBorrowAmt);
|
||||
}
|
||||
}
|
||||
|
||||
_PaybackStable(data.borrowTokens.length, aave, data.borrowTokens, data.stableBorrowAmts, sourceDsa);
|
||||
_PaybackVariable(data.borrowTokens.length, aave, data.borrowTokens, data.variableBorrowAmts, sourceDsa);
|
||||
_Withdraw(data.supplyTokens.length, aave, data.supplyTokens, data.supplyAmts);
|
||||
|
||||
positions[owner] = data;
|
||||
bytes memory positionData = abi.encode(owner, data);
|
||||
stateSender.syncState(polygonReceiver, positionData);
|
||||
|
||||
emit LogAaveV2Migrate(
|
||||
msg.sender,
|
||||
data.targetDsa,
|
||||
data.supplyTokens,
|
||||
data.borrowTokens,
|
||||
data.supplyAmts,
|
||||
data.variableBorrowAmts,
|
||||
data.stableBorrowAmts
|
||||
);
|
||||
}
|
||||
|
||||
// function migrate(
|
||||
// address owner,
|
||||
// address targetDsa,
|
||||
// address[] calldata supplyTokens,
|
||||
// address[] calldata borrowTokens
|
||||
// ) external {
|
||||
// require(supplyTokens.length > 0, "0-length-not-allowed");
|
||||
// require(targetDsa != address(0), "invalid-address");
|
||||
|
||||
// address sourceDsa = msg.sender;
|
||||
|
||||
// AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
|
||||
// AaveData memory data;
|
||||
|
||||
// (,,,,,uint healthFactor) = aave.getUserAccountData(sourceDsa);
|
||||
// require(healthFactor > 1e18, "position-not-safe");
|
||||
|
||||
// data.supplyAmts = new uint[](supplyTokens.length);
|
||||
// data.supplyTokens = new address[](supplyTokens.length);
|
||||
// data.targetDsa = targetDsa;
|
||||
|
||||
// for (uint i = 0; i < supplyTokens.length; i++) {
|
||||
// address _token = supplyTokens[i] == ethAddr ? wethAddr : supplyTokens[i];
|
||||
// (address _aToken, ,) = aaveData.getReserveTokensAddresses(_token);
|
||||
|
||||
// ATokenInterface aTokenContract = ATokenInterface(_aToken);
|
||||
|
||||
// data.supplyTokens[i] = _token;
|
||||
// data.supplyAmts[i] = aTokenContract.balanceOf(sourceDsa);
|
||||
|
||||
// aTokenContract.transferFrom(msg.sender, address(this), data.supplyAmts[i]);
|
||||
// }
|
||||
|
||||
// if (borrowTokens.length > 0) {
|
||||
// data.variableBorrowAmts = new uint[](borrowTokens.length);
|
||||
// data.stableBorrowAmts = new uint[](borrowTokens.length);
|
||||
|
||||
// for (uint i = 0; i < borrowTokens.length; i++) {
|
||||
// address _token = borrowTokens[i] == ethAddr ? wethAddr : borrowTokens[i];
|
||||
// data.borrowTokens[i] = _token;
|
||||
|
||||
// (
|
||||
// ,
|
||||
// data.stableBorrowAmts[i],
|
||||
// data.variableBorrowAmts[i],
|
||||
// ,,,,,
|
||||
// ) = aaveData.getUserReserveData(_token, sourceDsa);
|
||||
|
||||
// uint totalBorrowAmt = add(data.stableBorrowAmts[i], data.variableBorrowAmts[i]);
|
||||
|
||||
// if (totalBorrowAmt > 0) {
|
||||
// IERC20(_token).safeApprove(address(aave), totalBorrowAmt);
|
||||
// }
|
||||
// }
|
||||
|
||||
// _PaybackStable(borrowTokens.length, aave, data.borrowTokens, data.stableBorrowAmts, sourceDsa);
|
||||
// _PaybackVariable(borrowTokens.length, aave, data.borrowTokens, data.variableBorrowAmts, sourceDsa);
|
||||
// }
|
||||
|
||||
// _Withdraw(supplyTokens.length, aave, data.supplyTokens, data.supplyAmts);
|
||||
|
||||
// positions[owner] = data;
|
||||
// bytes memory positionData = abi.encode(owner, data);
|
||||
// stateSender.syncState(polygonReceiver, positionData);
|
||||
|
||||
// emit LogAaveV2Migrate(
|
||||
// msg.sender,
|
||||
// targetDsa,
|
||||
// supplyTokens,
|
||||
// borrowTokens,
|
||||
// data.supplyAmts,
|
||||
// data.variableBorrowAmts,
|
||||
// data.stableBorrowAmts
|
||||
// );
|
||||
// }
|
||||
}
|
28
contracts/common/interfaces.sol
Normal file
28
contracts/common/interfaces.sol
Normal file
|
@ -0,0 +1,28 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
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 (uint);
|
||||
function decimals() external view returns (uint);
|
||||
}
|
||||
|
||||
interface MemoryInterface {
|
||||
function getUint(uint id) external returns (uint num);
|
||||
function setUint(uint id, uint val) external;
|
||||
}
|
||||
|
||||
interface AccountInterface {
|
||||
function enable(address) external;
|
||||
function disable(address) external;
|
||||
function isAuth(address) external view returns (bool);
|
||||
function cast(
|
||||
string[] calldata _targets,
|
||||
bytes[] calldata _datas,
|
||||
address _origin
|
||||
) external payable returns (bytes32);
|
||||
}
|
49
contracts/common/math.sol
Normal file
49
contracts/common/math.sol
Normal file
|
@ -0,0 +1,49 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
|
||||
|
||||
contract DSMath {
|
||||
uint constant WAD = 10 ** 18;
|
||||
uint constant RAY = 10 ** 27;
|
||||
|
||||
function add(uint x, uint y) internal pure returns (uint z) {
|
||||
z = SafeMath.add(x, y);
|
||||
}
|
||||
|
||||
function sub(uint x, uint y) internal virtual pure returns (uint z) {
|
||||
z = SafeMath.sub(x, y);
|
||||
}
|
||||
|
||||
function mul(uint x, uint y) internal pure returns (uint z) {
|
||||
z = SafeMath.mul(x, y);
|
||||
}
|
||||
|
||||
function div(uint x, uint y) internal pure returns (uint z) {
|
||||
z = SafeMath.div(x, y);
|
||||
}
|
||||
|
||||
function wmul(uint x, uint y) internal pure returns (uint z) {
|
||||
z = SafeMath.add(SafeMath.mul(x, y), WAD / 2) / WAD;
|
||||
}
|
||||
|
||||
function wdiv(uint x, uint y) internal pure returns (uint z) {
|
||||
z = SafeMath.add(SafeMath.mul(x, WAD), y / 2) / y;
|
||||
}
|
||||
|
||||
function rdiv(uint x, uint y) internal pure returns (uint z) {
|
||||
z = SafeMath.add(SafeMath.mul(x, RAY), y / 2) / y;
|
||||
}
|
||||
|
||||
function rmul(uint x, uint y) internal pure returns (uint z) {
|
||||
z = SafeMath.add(SafeMath.mul(x, y), RAY / 2) / RAY;
|
||||
}
|
||||
|
||||
function toInt(uint x) internal pure returns (int y) {
|
||||
y = int(x);
|
||||
require(y >= 0, "int-overflow");
|
||||
}
|
||||
|
||||
function toRad(uint wad) internal pure returns (uint rad) {
|
||||
rad = mul(wad, 10 ** 27);
|
||||
}
|
||||
}
|
37
contracts/common/stores-mainnet.sol
Normal file
37
contracts/common/stores-mainnet.sol
Normal file
|
@ -0,0 +1,37 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { MemoryInterface } from "./interfaces.sol";
|
||||
|
||||
|
||||
abstract contract Stores {
|
||||
|
||||
/**
|
||||
* @dev Return ethereum address
|
||||
*/
|
||||
address constant internal ethAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
|
||||
/**
|
||||
* @dev Return Wrapped ETH address
|
||||
*/
|
||||
address constant internal wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
|
||||
/**
|
||||
* @dev Return memory variable address
|
||||
*/
|
||||
MemoryInterface constant internal instaMemory = MemoryInterface(0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
37
contracts/common/stores-polygon.sol
Normal file
37
contracts/common/stores-polygon.sol
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
119
contracts/implementation/aave-v2-migrator/main.sol
Normal file
119
contracts/implementation/aave-v2-migrator/main.sol
Normal file
|
@ -0,0 +1,119 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { Variables } from "./variables.sol";
|
||||
|
||||
/**
|
||||
* @title InstaAccountV2.
|
||||
* @dev DeFi Smart Account Wallet.
|
||||
*/
|
||||
|
||||
interface ConnectorsInterface {
|
||||
function isConnectors(string[] calldata connectorNames) external view returns (bool, address[] memory);
|
||||
}
|
||||
|
||||
contract Constants is Variables {
|
||||
// InstaIndex Address.
|
||||
address internal constant instaIndex = 0xA9B99766E6C676Cf1975c0D3166F96C0848fF5ad;
|
||||
// Migration contract Address.
|
||||
address internal constant migrationContract = address(0); // TODO: update address on deployment
|
||||
// Connnectors Address.
|
||||
address public immutable connectorsM1;
|
||||
|
||||
constructor(address _connectors) {
|
||||
connectorsM1 = _connectors;
|
||||
}
|
||||
}
|
||||
|
||||
contract InstaImplementationM1 is Constants {
|
||||
|
||||
constructor(address _connectors) Constants(_connectors) {}
|
||||
|
||||
function decodeEvent(bytes memory response) internal pure returns (string memory _eventCode, bytes memory _eventParams) {
|
||||
if (response.length > 0) {
|
||||
(_eventCode, _eventParams) = abi.decode(response, (string, bytes));
|
||||
}
|
||||
}
|
||||
|
||||
event LogCastMigrate(
|
||||
address indexed origin,
|
||||
address indexed sender,
|
||||
uint256 value,
|
||||
string[] targetsNames,
|
||||
address[] targets,
|
||||
string[] eventNames,
|
||||
bytes[] eventParams
|
||||
);
|
||||
|
||||
receive() external payable {}
|
||||
|
||||
/**
|
||||
* @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 This is the main function, Where all the different functions are called
|
||||
* from Smart Account.
|
||||
* @param _targetNames Array of Connector address.
|
||||
* @param _datas Array of Calldata.
|
||||
*/
|
||||
function castMigrate(
|
||||
string[] calldata _targetNames,
|
||||
bytes[] calldata _datas,
|
||||
address _origin
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (bytes32) // Dummy return to fix instaIndex buildWithCast function
|
||||
{
|
||||
uint256 _length = _targetNames.length;
|
||||
require(_auth[msg.sender] || msg.sender == instaIndex || msg.sender == migrationContract, "1: permission-denied");
|
||||
require(_length != 0, "1: length-invalid");
|
||||
require(_length == _datas.length , "1: array-length-invalid");
|
||||
|
||||
string[] memory eventNames = new string[](_length);
|
||||
bytes[] memory eventParams = new bytes[](_length);
|
||||
|
||||
// TODO: restrict migration contract to run something specific? or give is all access as it doesn't have power to run anything else
|
||||
(bool isOk, address[] memory _targets) = ConnectorsInterface(connectorsM1).isConnectors(_targetNames);
|
||||
|
||||
require(isOk, "1: not-connector");
|
||||
|
||||
for (uint i = 0; i < _length; i++) {
|
||||
bytes memory response = spell(_targets[i], _datas[i]);
|
||||
(eventNames[i], eventParams[i]) = decodeEvent(response);
|
||||
}
|
||||
|
||||
emit LogCastMigrate(
|
||||
_origin,
|
||||
msg.sender,
|
||||
msg.value,
|
||||
_targetNames,
|
||||
_targets,
|
||||
eventNames,
|
||||
eventParams
|
||||
);
|
||||
}
|
||||
|
||||
}
|
6
contracts/implementation/aave-v2-migrator/variables.sol
Normal file
6
contracts/implementation/aave-v2-migrator/variables.sol
Normal file
|
@ -0,0 +1,6 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Variables {
|
||||
// Auth Module(Address of Auth => bool).
|
||||
mapping (address => bool) internal _auth;
|
||||
}
|
315
contracts/liquidity.sol
Normal file
315
contracts/liquidity.sol
Normal file
|
@ -0,0 +1,315 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||
import { DSMath } from "./common/math.sol";
|
||||
|
||||
interface Account {
|
||||
struct Info {
|
||||
address owner; // The address that owns the account
|
||||
uint256 number; // A nonce that allows a single address to control many accounts
|
||||
}
|
||||
}
|
||||
|
||||
interface ListInterface {
|
||||
function accountID(address) external view returns (uint64);
|
||||
}
|
||||
|
||||
interface Actions {
|
||||
enum ActionType {
|
||||
Deposit, // supply tokens
|
||||
Withdraw, // borrow tokens
|
||||
Transfer, // transfer balance between accounts
|
||||
Buy, // buy an amount of some token (publicly)
|
||||
Sell, // sell an amount of some token (publicly)
|
||||
Trade, // trade tokens against another account
|
||||
Liquidate, // liquidate an undercollateralized or expiring account
|
||||
Vaporize, // use excess tokens to zero-out a completely negative account
|
||||
Call // send arbitrary data to an address
|
||||
}
|
||||
|
||||
struct ActionArgs {
|
||||
ActionType actionType;
|
||||
uint256 accountId;
|
||||
Types.AssetAmount amount;
|
||||
uint256 primaryMarketId;
|
||||
uint256 secondaryMarketId;
|
||||
address otherAddress;
|
||||
uint256 otherAccountId;
|
||||
bytes data;
|
||||
}
|
||||
|
||||
struct DepositArgs {
|
||||
Types.AssetAmount amount;
|
||||
Account.Info account;
|
||||
uint256 market;
|
||||
address from;
|
||||
}
|
||||
|
||||
struct WithdrawArgs {
|
||||
Types.AssetAmount amount;
|
||||
Account.Info account;
|
||||
uint256 market;
|
||||
address to;
|
||||
}
|
||||
|
||||
struct CallArgs {
|
||||
Account.Info account;
|
||||
address callee;
|
||||
bytes data;
|
||||
}
|
||||
}
|
||||
|
||||
interface Types {
|
||||
enum AssetDenomination {
|
||||
Wei, // the amount is denominated in wei
|
||||
Par // the amount is denominated in par
|
||||
}
|
||||
|
||||
enum AssetReference {
|
||||
Delta, // the amount is given as a delta from the current value
|
||||
Target // the amount is given as an exact number to end up at
|
||||
}
|
||||
|
||||
struct AssetAmount {
|
||||
bool sign; // true if positive
|
||||
AssetDenomination denomination;
|
||||
AssetReference ref;
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
struct Wei {
|
||||
bool sign; // true if positive
|
||||
uint256 value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface ISoloMargin {
|
||||
struct OperatorArg {
|
||||
address operator;
|
||||
bool trusted;
|
||||
}
|
||||
|
||||
function getMarketTokenAddress(uint256 marketId)
|
||||
external
|
||||
view
|
||||
returns (address);
|
||||
|
||||
function getNumMarkets() external view returns (uint256);
|
||||
|
||||
|
||||
function operate(
|
||||
Account.Info[] calldata accounts,
|
||||
Actions.ActionArgs[] calldata actions
|
||||
) external;
|
||||
|
||||
function getAccountWei(Account.Info calldata account, uint256 marketId)
|
||||
external
|
||||
view
|
||||
returns (Types.Wei memory);
|
||||
}
|
||||
|
||||
contract DydxFlashloanBase {
|
||||
function _getMarketIdFromTokenAddress(address _solo, address token)
|
||||
internal
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
ISoloMargin solo = ISoloMargin(_solo);
|
||||
|
||||
uint256 numMarkets = solo.getNumMarkets();
|
||||
|
||||
address curToken;
|
||||
for (uint256 i = 0; i < numMarkets; i++) {
|
||||
curToken = solo.getMarketTokenAddress(i);
|
||||
|
||||
if (curToken == token) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
revert("No marketId found for provided token");
|
||||
}
|
||||
|
||||
function _getAccountInfo() internal view returns (Account.Info memory) {
|
||||
return Account.Info({owner: address(this), number: 1});
|
||||
}
|
||||
|
||||
function _getWithdrawAction(uint marketId, uint256 amount)
|
||||
internal
|
||||
view
|
||||
returns (Actions.ActionArgs memory)
|
||||
{
|
||||
return
|
||||
Actions.ActionArgs({
|
||||
actionType: Actions.ActionType.Withdraw,
|
||||
accountId: 0,
|
||||
amount: Types.AssetAmount({
|
||||
sign: false,
|
||||
denomination: Types.AssetDenomination.Wei,
|
||||
ref: Types.AssetReference.Delta,
|
||||
value: amount
|
||||
}),
|
||||
primaryMarketId: marketId,
|
||||
secondaryMarketId: 0,
|
||||
otherAddress: address(this),
|
||||
otherAccountId: 0,
|
||||
data: ""
|
||||
});
|
||||
}
|
||||
|
||||
function _getCallAction(bytes memory data)
|
||||
internal
|
||||
view
|
||||
returns (Actions.ActionArgs memory)
|
||||
{
|
||||
return
|
||||
Actions.ActionArgs({
|
||||
actionType: Actions.ActionType.Call,
|
||||
accountId: 0,
|
||||
amount: Types.AssetAmount({
|
||||
sign: false,
|
||||
denomination: Types.AssetDenomination.Wei,
|
||||
ref: Types.AssetReference.Delta,
|
||||
value: 0
|
||||
}),
|
||||
primaryMarketId: 0,
|
||||
secondaryMarketId: 0,
|
||||
otherAddress: address(this),
|
||||
otherAccountId: 0,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
function _getDepositAction(uint marketId, uint256 amount)
|
||||
internal
|
||||
view
|
||||
returns (Actions.ActionArgs memory)
|
||||
{
|
||||
return
|
||||
Actions.ActionArgs({
|
||||
actionType: Actions.ActionType.Deposit,
|
||||
accountId: 0,
|
||||
amount: Types.AssetAmount({
|
||||
sign: true,
|
||||
denomination: Types.AssetDenomination.Wei,
|
||||
ref: Types.AssetReference.Delta,
|
||||
value: amount
|
||||
}),
|
||||
primaryMarketId: marketId,
|
||||
secondaryMarketId: 0,
|
||||
otherAddress: address(this),
|
||||
otherAccountId: 0,
|
||||
data: ""
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @title ICallee
|
||||
* @author dYdX
|
||||
*
|
||||
* Interface that Callees for Solo must implement in order to ingest data.
|
||||
*/
|
||||
interface ICallee {
|
||||
|
||||
// ============ Public Functions ============
|
||||
|
||||
/**
|
||||
* Allows users to send this contract arbitrary data.
|
||||
*
|
||||
* @param sender The msg.sender to Solo
|
||||
* @param accountInfo The account from which the data is being sent
|
||||
* @param data Arbitrary data given by the sender
|
||||
*/
|
||||
function callFunction(
|
||||
address sender,
|
||||
Account.Info calldata accountInfo,
|
||||
bytes calldata data
|
||||
)
|
||||
external;
|
||||
}
|
||||
interface IndexInterface {
|
||||
function master() external view returns (address);
|
||||
}
|
||||
|
||||
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 (uint);
|
||||
function decimals() external view returns (uint);
|
||||
}
|
||||
|
||||
struct AaveDataRaw {
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
uint[] variableBorrowAmts;
|
||||
uint[] stableBorrowAmts;
|
||||
address[] supplyTokens;
|
||||
address[] borrowTokens;
|
||||
}
|
||||
|
||||
interface MigrationInterface {
|
||||
function migrateFlashCallback(AaveDataRaw calldata _data, address dsa, uint ethAmt) external;
|
||||
}
|
||||
|
||||
contract Setup {
|
||||
address public constant soloAddr = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
|
||||
address public constant wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
MigrationInterface public constant migrationAddr = MigrationInterface(address(0)); // TODO: Migration address
|
||||
|
||||
TokenInterface wethContract = TokenInterface(wethAddr);
|
||||
ISoloMargin solo = ISoloMargin(soloAddr);
|
||||
|
||||
}
|
||||
|
||||
contract DydxFlashloaner is Setup, ICallee, DydxFlashloanBase, DSMath {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
function callFunction(
|
||||
address sender,
|
||||
Account.Info memory account,
|
||||
bytes memory data
|
||||
) public override {
|
||||
require(sender == address(this), "not-same-sender");
|
||||
require(msg.sender == soloAddr, "not-solo-dydx-sender");
|
||||
|
||||
(AaveDataRaw memory _data, address dsa, uint ethAmt) = abi.decode(
|
||||
data,
|
||||
(AaveDataRaw, address, uint)
|
||||
);
|
||||
|
||||
wethContract.transfer(address(migrationAddr), ethAmt);
|
||||
|
||||
migrationAddr.migrateFlashCallback(_data, dsa, ethAmt);
|
||||
}
|
||||
|
||||
function initiateFlashLoan(bytes memory data, uint ethAmt) external {
|
||||
require(msg.sender == address(migrationAddr), "not-migration-contract");
|
||||
uint marketId = _getMarketIdFromTokenAddress(soloAddr, wethAddr); // TODO: set Static market ID?
|
||||
|
||||
Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);
|
||||
|
||||
operations[0] = _getWithdrawAction(marketId, ethAmt);
|
||||
operations[1] = _getCallAction(data);
|
||||
operations[2] = _getDepositAction(marketId, ethAmt + 2);
|
||||
|
||||
Account.Info[] memory accountInfos = new Account.Info[](1);
|
||||
accountInfos[0] = _getAccountInfo();
|
||||
|
||||
solo.operate(accountInfos, operations);
|
||||
}
|
||||
}
|
||||
|
||||
contract InstaPool is DydxFlashloaner {
|
||||
constructor() public {
|
||||
wethContract.approve(wethAddr, uint(-1));
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
}
|
16
contracts/receivers/aave-v2-receiver/events.sol
Normal file
16
contracts/receivers/aave-v2-receiver/events.sol
Normal file
|
@ -0,0 +1,16 @@
|
|||
pragma solidity >=0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
|
||||
event LogWithdraw(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
}
|
133
contracts/receivers/aave-v2-receiver/helpers.sol
Normal file
133
contracts/receivers/aave-v2-receiver/helpers.sol
Normal file
|
@ -0,0 +1,133 @@
|
|||
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,
|
||||
AaveDataProviderInterface,
|
||||
AaveInterface
|
||||
} from "./interfaces.sol";
|
||||
|
||||
abstract contract Helpers is Stores, DSMath, Variables {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < data.borrowTokens.length; i++) {
|
||||
data.borrowTokens[i] = tokenMapping.getMapping(data.borrowTokens[i]);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function isPositionSafe() internal returns (bool isOk) {
|
||||
// TODO: Check the final position health
|
||||
require(isOk, "position-at-risk");
|
||||
}
|
||||
|
||||
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)
|
||||
uint _atokenBal = _atokenContract.balanceOf(address(this));
|
||||
uint _supplyAmt = supplyAmts[i];
|
||||
bool isFlash;
|
||||
uint _flashAmt;
|
||||
|
||||
// get Aave liquidity of token
|
||||
uint tokenLiq = uint(0);
|
||||
|
||||
if (_atokenBal < _supplyAmt) {
|
||||
uint _reqAmt = _supplyAmt - _atokenBal;
|
||||
if (tokenLiq < _reqAmt) {
|
||||
_flashAmt = flashAmts[_token];
|
||||
if (_flashAmt > 0) {
|
||||
aave.deposit(_token, _flashAmt, address(this), 3288); // TODO: what is our ID on Polygon?
|
||||
tokenLiq += _flashAmt;
|
||||
isFlash = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint num = _reqAmt/tokenLiq + 1; // TODO: Is this right
|
||||
uint splitAmt = _reqAmt/num; // TODO: Check decimal
|
||||
uint finalSplit = _reqAmt - (splitAmt * (num - 1)); // TODO: to resolve upper decimal error
|
||||
|
||||
for (uint j = 0; j < num; j++) {
|
||||
if (i < num - 1) {
|
||||
aave.borrow(_token, splitAmt, 2, 3288, address(this)); // TODO: is "2" for interest rate mode. Right?
|
||||
aave.deposit(_token, splitAmt, address(this), 3288);
|
||||
} else {
|
||||
aave.borrow(_token, finalSplit, 2, 3288, address(this)); // TODO: is "2" for interest rate mode. Right?
|
||||
aave.deposit(_token, finalSplit, address(this), 3288);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFlash) {
|
||||
aave.withdraw(_token, _flashAmt, address(this));
|
||||
}
|
||||
|
||||
_atokenContract.safeTransfer(dsa, _supplyAmt);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
_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.
|
||||
uint num = _borrowAmt/tokenLiq + 1; // TODO: Is this right
|
||||
uint splitAmt = _borrowAmt/num; // TODO: Check decimal
|
||||
uint finalSplit = _borrowAmt - (splitAmt * (num - 1)); // TODO: to resolve upper decimal error
|
||||
|
||||
uint spellsAmt = (2 * num) + 1;
|
||||
string[] memory targets = new string[](spellsAmt);
|
||||
bytes[] memory castData = new bytes[](spellsAmt);
|
||||
for (uint j = 0; j < num; j++) {
|
||||
targets[j] = "AAVE-A";
|
||||
uint k = j * 2;
|
||||
if (i < num - 1) {
|
||||
// borrow spell
|
||||
castData[k] = abi.encode("6abcd3de", _token, splitAmt, 2, 0, 0); // TODO: verify this & is rate mode right?
|
||||
// deposit spell
|
||||
castData[k+1] = abi.encode("ce88b439", _token, splitAmt, 2, 0, 0); // TODO: verify this & is rate mode right?
|
||||
} else {
|
||||
// borrow spell
|
||||
castData[k] = abi.encode("6abcd3de", _token, finalSplit, 2, 0, 0); // TODO: verify this & is rate mode right?
|
||||
// deposit spell
|
||||
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?)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
87
contracts/receivers/aave-v2-receiver/interfaces.sol
Normal file
87
contracts/receivers/aave-v2-receiver/interfaces.sol
Normal file
|
@ -0,0 +1,87 @@
|
|||
pragma solidity >=0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface AccountInterface {
|
||||
function enable(address) external;
|
||||
function disable(address) external;
|
||||
function isAuth(address) external view returns (bool);
|
||||
function cast(
|
||||
string[] calldata _targets,
|
||||
bytes[] calldata _datas,
|
||||
address _origin
|
||||
) external payable returns (bytes32);
|
||||
function migrateAave(address) external payable returns (bytes32);
|
||||
}
|
||||
|
||||
interface TokenMappingInterface {
|
||||
function getMapping(address) external view returns (address);
|
||||
}
|
||||
|
||||
struct AaveData {
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
uint[] borrowAmts;
|
||||
address[] supplyTokens;
|
||||
address[] borrowTokens;
|
||||
}
|
||||
|
||||
interface IndexInterface {
|
||||
function master() external view returns (address);
|
||||
}
|
||||
|
||||
interface AaveLendingPoolProviderInterface {
|
||||
function getLendingPool() external view returns (address);
|
||||
}
|
||||
|
||||
interface AaveDataProviderInterface {
|
||||
function getReserveTokensAddresses(address _asset) external view returns (
|
||||
address aTokenAddress,
|
||||
address stableDebtTokenAddress,
|
||||
address variableDebtTokenAddress
|
||||
);
|
||||
function getUserReserveData(address _asset, address _user) external view returns (
|
||||
uint256 currentATokenBalance,
|
||||
uint256 currentStableDebt,
|
||||
uint256 currentVariableDebt,
|
||||
uint256 principalStableDebt,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 liquidityRate,
|
||||
uint40 stableRateLastUpdated,
|
||||
bool usageAsCollateralEnabled
|
||||
);
|
||||
function getReserveConfigurationData(address asset) external view returns (
|
||||
uint256 decimals,
|
||||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus,
|
||||
uint256 reserveFactor,
|
||||
bool usageAsCollateralEnabled,
|
||||
bool borrowingEnabled,
|
||||
bool stableBorrowRateEnabled,
|
||||
bool isActive,
|
||||
bool isFrozen
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveInterface {
|
||||
function deposit(address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode) external;
|
||||
function withdraw(address _asset, uint256 _amount, address _to) external;
|
||||
function borrow(
|
||||
address _asset,
|
||||
uint256 _amount,
|
||||
uint256 _interestRateMode,
|
||||
uint16 _referralCode,
|
||||
address _onBehalfOf
|
||||
) external;
|
||||
function repay(address _asset, uint256 _amount, uint256 _rateMode, address _onBehalfOf) external;
|
||||
function setUserUseReserveAsCollateral(address _asset, bool _useAsCollateral) external;
|
||||
function getUserAccountData(address user) external view returns (
|
||||
uint256 totalCollateralETH,
|
||||
uint256 totalDebtETH,
|
||||
uint256 availableBorrowsETH,
|
||||
uint256 currentLiquidationThreshold,
|
||||
uint256 ltv,
|
||||
uint256 healthFactor
|
||||
);
|
||||
}
|
197
contracts/receivers/aave-v2-receiver/main.sol
Normal file
197
contracts/receivers/aave-v2-receiver/main.sol
Normal file
|
@ -0,0 +1,197 @@
|
|||
pragma solidity ^0.7.0;
|
||||
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 { 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;
|
||||
|
||||
function spell(address _target, bytes memory _data) external {
|
||||
require(msg.sender == instaIndex.master(), "not-master");
|
||||
require(_target != address(0), "target-invalid");
|
||||
assembly {
|
||||
let succeeded := delegatecall(gas(), _target, add(_data, 0x20), mload(_data), 0, 0)
|
||||
|
||||
switch iszero(succeeded)
|
||||
case 1 {
|
||||
// throw if delegatecall failed
|
||||
let size := returndatasize()
|
||||
returndatacopy(0x00, 0x00, size)
|
||||
revert(0x00, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
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;
|
||||
}
|
||||
|
||||
emit LogDeposit(msg.sender, tokens, _amts);
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
if (_amt > maxAmt) {
|
||||
_amt = maxAmt;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
isPositionSafe();
|
||||
|
||||
emit LogWithdraw(msg.sender, tokens, _amts);
|
||||
}
|
||||
|
||||
function settle() external {
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
for (uint i = 0; i < supportedTokens.length; i++) {
|
||||
address _token = supportedTokens[i];
|
||||
if (_token == maticAddr) {
|
||||
_token = wmaticAddr;
|
||||
if (address(this).balance > 0) {
|
||||
TokenInterface(wmaticAddr).deposit{value: address(this).balance}();
|
||||
}
|
||||
}
|
||||
IERC20 _tokenContract = IERC20(_token);
|
||||
uint _tokenBal = _tokenContract.balanceOf(address(this));
|
||||
if (_tokenBal > 0) {
|
||||
_tokenContract.approve(address(this), _tokenBal);
|
||||
aave.deposit(_token, _tokenBal, address(this), 3288);
|
||||
}
|
||||
(
|
||||
uint supplyBal,,
|
||||
uint borrowBal,
|
||||
,,,,,
|
||||
) = aaveData.getUserReserveData(_token, address(this));
|
||||
if (supplyBal != 0 && borrowBal != 0) {
|
||||
if (supplyBal > borrowBal) {
|
||||
aave.withdraw(_token, (borrowBal + flashAmts[_token]), address(this)); // TODO: fail because of not enough withdrawing capacity?
|
||||
IERC20(_token).approve(address(aave), borrowBal);
|
||||
aave.repay(_token, borrowBal, 2, address(this));
|
||||
} else {
|
||||
aave.withdraw(_token, (supplyBal + flashAmts[_token]), address(this)); // TODO: fail because of not enough withdrawing capacity?
|
||||
IERC20(_token).approve(address(aave), supplyBal);
|
||||
aave.repay(_token, supplyBal, 2, address(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: emit event
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
contract AaveV2Migrator is MigrateResolver {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
uint private lastStateId;
|
||||
|
||||
function _migratePosition(AaveData memory _data) internal {
|
||||
AaveData memory data = remapTokens(_data); // converting L1 token addresses to L2 addresses
|
||||
|
||||
address dsa = _data.targetDsa;
|
||||
uint[] memory supplyAmts = _data.supplyAmts;
|
||||
uint[] memory borrowAmts = _data.borrowAmts;
|
||||
address[] memory supplyTokens = _data.supplyTokens;
|
||||
address[] memory borrowTokens = _data.borrowTokens;
|
||||
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
|
||||
transferAtokens(aave, dsa, supplyTokens, supplyAmts);
|
||||
|
||||
// Have to borrow from user's account & transfer
|
||||
borrowAndTransferSpells(aave, dsa, borrowTokens, borrowAmts);
|
||||
|
||||
isPositionSafe();
|
||||
|
||||
// TODO: emit event
|
||||
}
|
||||
|
||||
function onStateReceive(uint256 stateId, bytes calldata receivedData) external {
|
||||
require(stateId > lastStateId, "wrong-data");
|
||||
lastStateId = stateId;
|
||||
|
||||
// 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;
|
||||
|
||||
// TODO: add event
|
||||
}
|
||||
|
||||
function migrate(uint _id) external {
|
||||
bytes memory _data = positions[_id];
|
||||
|
||||
require(_data.length != 0, "already-migrated");
|
||||
|
||||
AaveData memory data = abi.decode(_data, (AaveData));
|
||||
|
||||
_migratePosition(data);
|
||||
|
||||
delete positions[_id];
|
||||
|
||||
// TODO: add event
|
||||
}
|
||||
}
|
43
contracts/receivers/aave-v2-receiver/variables.sol
Normal file
43
contracts/receivers/aave-v2-receiver/variables.sol
Normal file
|
@ -0,0 +1,43 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import {
|
||||
TokenMappingInterface,
|
||||
AaveLendingPoolProviderInterface,
|
||||
AaveDataProviderInterface,
|
||||
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 = 800000000000000000; // 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);
|
||||
|
||||
/**
|
||||
* @dev Aave Data Provider
|
||||
*/
|
||||
// TODO: add L2 Data provider address
|
||||
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(address(0));
|
||||
|
||||
|
||||
// dsa => position
|
||||
mapping(uint => bytes) public positions;
|
||||
mapping(address => mapping(address => uint)) public deposits;
|
||||
|
||||
// InstaIndex Address.
|
||||
IndexInterface public constant instaIndex = IndexInterface(0xA9B99766E6C676Cf1975c0D3166F96C0848fF5ad);
|
||||
|
||||
// TODO: Set by construtor?
|
||||
mapping(address => bool) public isSupportedToken;
|
||||
address[] public supportedTokens;
|
||||
|
||||
}
|
10
contracts/senders/aave-v2-connector/events.sol
Normal file
10
contracts/senders/aave-v2-connector/events.sol
Normal file
|
@ -0,0 +1,10 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogAaveV2Migrate(
|
||||
address indexed user,
|
||||
address indexed targetDsa,
|
||||
address[] supplyTokens,
|
||||
address[] borrowTokens
|
||||
);
|
||||
}
|
15
contracts/senders/aave-v2-connector/helpers.sol
Normal file
15
contracts/senders/aave-v2-connector/helpers.sol
Normal file
|
@ -0,0 +1,15 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Stores } from "../../common/stores-mainnet.sol";
|
||||
import { AaveLendingPoolProviderInterface, AaveDataProviderInterface, AaveMigratorInterface } from "./interfaces.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Stores {
|
||||
|
||||
AaveMigratorInterface constant internal migrator = AaveMigratorInterface(address(2)); // Replace this (Migrator contract)
|
||||
|
||||
/**
|
||||
* @dev Aave Data Provider
|
||||
*/
|
||||
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d);
|
||||
}
|
86
contracts/senders/aave-v2-connector/interfaces.sol
Normal file
86
contracts/senders/aave-v2-connector/interfaces.sol
Normal file
|
@ -0,0 +1,86 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface AaveInterface {
|
||||
function deposit(address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode) external;
|
||||
function withdraw(address _asset, uint256 _amount, address _to) external;
|
||||
function borrow(
|
||||
address _asset,
|
||||
uint256 _amount,
|
||||
uint256 _interestRateMode,
|
||||
uint16 _referralCode,
|
||||
address _onBehalfOf
|
||||
) external;
|
||||
function repay(address _asset, uint256 _amount, uint256 _rateMode, address _onBehalfOf) external;
|
||||
function setUserUseReserveAsCollateral(address _asset, bool _useAsCollateral) external;
|
||||
function getUserAccountData(address user) external view returns (
|
||||
uint256 totalCollateralETH,
|
||||
uint256 totalDebtETH,
|
||||
uint256 availableBorrowsETH,
|
||||
uint256 currentLiquidationThreshold,
|
||||
uint256 ltv,
|
||||
uint256 healthFactor
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveLendingPoolProviderInterface {
|
||||
function getLendingPool() external view returns (address);
|
||||
}
|
||||
|
||||
// Aave Protocol Data Provider
|
||||
interface AaveDataProviderInterface {
|
||||
function getReserveTokensAddresses(address _asset) external view returns (
|
||||
address aTokenAddress,
|
||||
address stableDebtTokenAddress,
|
||||
address variableDebtTokenAddress
|
||||
);
|
||||
function getUserReserveData(address _asset, address _user) external view returns (
|
||||
uint256 currentATokenBalance,
|
||||
uint256 currentStableDebt,
|
||||
uint256 currentVariableDebt,
|
||||
uint256 principalStableDebt,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 liquidityRate,
|
||||
uint40 stableRateLastUpdated,
|
||||
bool usageAsCollateralEnabled
|
||||
);
|
||||
function getReserveConfigurationData(address asset) external view returns (
|
||||
uint256 decimals,
|
||||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus,
|
||||
uint256 reserveFactor,
|
||||
bool usageAsCollateralEnabled,
|
||||
bool borrowingEnabled,
|
||||
bool stableBorrowRateEnabled,
|
||||
bool isActive,
|
||||
bool isFrozen
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveAddressProviderRegistryInterface {
|
||||
function getAddressesProvidersList() external view returns (address[] memory);
|
||||
}
|
||||
|
||||
interface ATokenInterface {
|
||||
function scaledBalanceOf(address _user) external view returns (uint256);
|
||||
function isTransferAllowed(address _user, uint256 _amount) external view returns (bool);
|
||||
function balanceOf(address _user) external view returns(uint256);
|
||||
function transferFrom(address, address, uint) external returns (bool);
|
||||
function approve(address, uint256) external;
|
||||
}
|
||||
|
||||
interface AaveMigratorInterface {
|
||||
function migrate(AaveDataRaw memory _data) external;
|
||||
function migrateWithFlash(AaveDataRaw memory _data, uint ethAmt) external;
|
||||
}
|
||||
|
||||
struct AaveDataRaw {
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
uint[] variableBorrowAmts;
|
||||
uint[] stableBorrowAmts;
|
||||
address[] supplyTokens;
|
||||
address[] borrowTokens;
|
||||
}
|
55
contracts/senders/aave-v2-connector/main.sol
Normal file
55
contracts/senders/aave-v2-connector/main.sol
Normal file
|
@ -0,0 +1,55 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { TokenInterface, AccountInterface } from "../../common/interfaces.sol";
|
||||
import { AaveInterface, ATokenInterface, AaveDataRaw } from "./interfaces.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
contract AaveMigrateResolver is Helpers, Events {
|
||||
|
||||
function migrate(
|
||||
AaveDataRaw calldata _data,
|
||||
uint ethAmt // if ethAmt is > 0 then use migrateWithflash
|
||||
) external payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
require(_data.supplyTokens.length > 0, "0-length-not-allowed");
|
||||
require(_data.supplyTokens.length == _data.supplyAmts.length, "invalid-length");
|
||||
require(_data.targetDsa != address(0), "invalid-address");
|
||||
|
||||
AaveDataRaw memory data;
|
||||
|
||||
data.borrowTokens = _data.borrowTokens;
|
||||
data.stableBorrowAmts = _data.stableBorrowAmts;
|
||||
data.supplyAmts = _data.supplyAmts;
|
||||
data.supplyTokens = _data.supplyTokens;
|
||||
data.targetDsa = _data.targetDsa;
|
||||
data.variableBorrowAmts = _data.variableBorrowAmts;
|
||||
|
||||
for (uint i = 0; i < data.supplyTokens.length; i++) {
|
||||
address _token = data.supplyTokens[i] == ethAddr ? wethAddr : data.supplyTokens[i];
|
||||
data.supplyTokens[i] = _token;
|
||||
(address _aToken, ,) = aaveData.getReserveTokensAddresses(_token);
|
||||
ATokenInterface _aTokenContract = ATokenInterface(_aToken);
|
||||
|
||||
if (data.supplyAmts[i] == uint(-1)) {
|
||||
data.supplyAmts[i] = _aTokenContract.balanceOf(address(this));
|
||||
}
|
||||
|
||||
_aTokenContract.approve(address(migrator), data.supplyAmts[i]);
|
||||
}
|
||||
|
||||
if (ethAmt > 0) {
|
||||
migrator.migrateWithFlash(data, ethAmt);
|
||||
} else {
|
||||
migrator.migrate(data);
|
||||
}
|
||||
|
||||
_eventName = "LogAaveV2Migrate(address,address,address[],address[])";
|
||||
_eventParam = abi.encode(msg.sender, data.targetDsa, data.supplyTokens, data.borrowTokens);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
contract AaveV2Migrator is AaveMigrateResolver {
|
||||
string constant public name = "AaveV2PolygonMigrator-v1";
|
||||
}
|
26
contracts/senders/aave-v2-migrator/events.sol
Normal file
26
contracts/senders/aave-v2-migrator/events.sol
Normal file
|
@ -0,0 +1,26 @@
|
|||
pragma solidity >=0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
|
||||
event LogWithdraw(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
|
||||
event LogAaveV2Migrate(
|
||||
address indexed user,
|
||||
address indexed targetDsa,
|
||||
address[] supplyTokens,
|
||||
address[] borrowTokens,
|
||||
uint[] supplyAmts,
|
||||
uint[] variableBorrowAmts,
|
||||
uint[] stableBorrowAmts
|
||||
);
|
||||
}
|
149
contracts/senders/aave-v2-migrator/helpers.sol
Normal file
149
contracts/senders/aave-v2-migrator/helpers.sol
Normal file
|
@ -0,0 +1,149 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { DSMath } from "../../common/math.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,
|
||||
AavePriceOracle,
|
||||
ChainLinkInterface
|
||||
} from "./interfaces.sol";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function _PaybackStable(
|
||||
uint _length,
|
||||
AaveInterface aave,
|
||||
address[] memory tokens,
|
||||
uint256[] memory amts,
|
||||
address user
|
||||
) internal {
|
||||
for (uint i = 0; i < _length; i++) {
|
||||
if (amts[i] > 0) {
|
||||
_paybackBehalfOne(aave, tokens[i], amts[i], 1, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _PaybackVariable(
|
||||
uint _length,
|
||||
AaveInterface aave,
|
||||
address[] memory tokens,
|
||||
uint256[] memory amts,
|
||||
address user
|
||||
) internal {
|
||||
for (uint i = 0; i < _length; i++) {
|
||||
if (amts[i] > 0) {
|
||||
_paybackBehalfOne(aave, tokens[i], amts[i], 2, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
(
|
||||
,
|
||||
uint stableDebt,
|
||||
uint variableDebt,
|
||||
,,,,,
|
||||
) = aaveData.getUserReserveData(_token, sourceDsa);
|
||||
|
||||
stableBorrow[i] = _data.stableBorrowAmts[i] == uint(-1) ? stableDebt : _data.stableBorrowAmts[i];
|
||||
variableBorrow[i] = _data.variableBorrowAmts[i] == uint(-1) ? variableDebt : _data.variableBorrowAmts[i];
|
||||
|
||||
totalBorrow[i] = add(stableBorrow[i], variableBorrow[i]);
|
||||
if (totalBorrow[i] > 0) {
|
||||
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(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);
|
||||
uint _finalAmt;
|
||||
if (supplyAmts[i] == uint(-1)) {
|
||||
_finalAmt = aTokenContract.balanceOf(dsa);
|
||||
} else {
|
||||
_finalAmt = supplyAmts[i];
|
||||
}
|
||||
|
||||
aTokenContract.transferFrom(dsa, address(this), finalAmts[i]);
|
||||
|
||||
_finalAmt = wmul(_finalAmt, fee);
|
||||
finalAmts[i] = _finalAmt;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function isPositionSafe() internal returns (bool isOk) {
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
(,,,,,uint healthFactor) = aave.getUserAccountData(address(this));
|
||||
// TODO: Check throughly minLimit = 100%/80% = 125% (20% gap initially)
|
||||
uint minLimit = wdiv(1e18, safeRatioGap);
|
||||
isOk = healthFactor > minLimit;
|
||||
require(isOk, "position-at-risk");
|
||||
}
|
||||
|
||||
function getTokensPrices(address[] memory tokens) internal view returns(uint[] memory tokenPricesInEth) {
|
||||
tokenPricesInEth = AavePriceOracle(aaveProvider.getPriceOracle()).getAssetsPrices(tokens);
|
||||
}
|
||||
|
||||
// Liquidation threshold
|
||||
function getTokenLt(address[] memory tokens) internal view returns (uint[] memory decimals, uint[] memory tokenLts) {
|
||||
for (uint i = 0; i < tokens.length; i++) {
|
||||
(decimals[i],,tokenLts[i],,,,,,,) = aaveData.getReserveConfigurationData(tokens[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function convertTo18(uint amount, uint decimal) internal returns (uint) {
|
||||
return amount * (10 ** (18 - decimal)); // TODO: verify this
|
||||
}
|
||||
|
||||
// TODO: need to verify this throughly
|
||||
/*
|
||||
* Checks the position to migrate should have a safe gap from liquidation
|
||||
*/
|
||||
function _checkRatio(AaveData memory data) public {
|
||||
uint[] memory supplyTokenPrices = getTokensPrices(data.supplyTokens);
|
||||
(uint[] memory supplyDecimals, uint[] memory supplyLts) = getTokenLt(data.supplyTokens);
|
||||
|
||||
uint[] memory borrowTokenPrices = getTokensPrices(data.borrowTokens);
|
||||
(uint[] memory borrowDecimals,) = getTokenLt(data.borrowTokens);
|
||||
uint netSupply;
|
||||
uint netBorrow;
|
||||
uint liquidation;
|
||||
for (uint i = 0; i < data.supplyTokens.length; i++) {
|
||||
uint _amt = wmul(convertTo18(data.supplyAmts[i], supplyDecimals[i]), supplyTokenPrices[i]);
|
||||
netSupply += _amt;
|
||||
liquidation += (_amt * supplyLts[i]) / 10000; // convert the number 8000 to 0.8
|
||||
}
|
||||
for (uint i = 0; i < data.borrowTokens.length; i++) {
|
||||
uint _amt = wmul(convertTo18(data.borrowAmts[i], borrowDecimals[i]), borrowTokenPrices[i]);
|
||||
netBorrow += _amt;
|
||||
}
|
||||
uint _dif = wmul(netSupply, sub(1e18, safeRatioGap));
|
||||
require(netBorrow < sub(liquidation, _dif), "position-is-risky-to-migrate");
|
||||
}
|
||||
|
||||
}
|
98
contracts/senders/aave-v2-migrator/interfaces.sol
Normal file
98
contracts/senders/aave-v2-migrator/interfaces.sol
Normal file
|
@ -0,0 +1,98 @@
|
|||
pragma solidity >=0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface AaveInterface {
|
||||
function deposit(address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode) external;
|
||||
function withdraw(address _asset, uint256 _amount, address _to) external;
|
||||
function borrow(
|
||||
address _asset,
|
||||
uint256 _amount,
|
||||
uint256 _interestRateMode,
|
||||
uint16 _referralCode,
|
||||
address _onBehalfOf
|
||||
) external;
|
||||
function repay(address _asset, uint256 _amount, uint256 _rateMode, address _onBehalfOf) external;
|
||||
function setUserUseReserveAsCollateral(address _asset, bool _useAsCollateral) external;
|
||||
function getUserAccountData(address user) external view returns (
|
||||
uint256 totalCollateralETH,
|
||||
uint256 totalDebtETH,
|
||||
uint256 availableBorrowsETH,
|
||||
uint256 currentLiquidationThreshold,
|
||||
uint256 ltv,
|
||||
uint256 healthFactor
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveLendingPoolProviderInterface {
|
||||
function getLendingPool() external view returns (address);
|
||||
function getPriceOracle() external view returns (address);
|
||||
}
|
||||
|
||||
// Aave Protocol Data Provider
|
||||
interface AaveDataProviderInterface {
|
||||
function getReserveTokensAddresses(address _asset) external view returns (
|
||||
address aTokenAddress,
|
||||
address stableDebtTokenAddress,
|
||||
address variableDebtTokenAddress
|
||||
);
|
||||
function getUserReserveData(address _asset, address _user) external view returns (
|
||||
uint256 currentATokenBalance,
|
||||
uint256 currentStableDebt,
|
||||
uint256 currentVariableDebt,
|
||||
uint256 principalStableDebt,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 liquidityRate,
|
||||
uint40 stableRateLastUpdated,
|
||||
bool usageAsCollateralEnabled
|
||||
);
|
||||
function getReserveConfigurationData(address asset) external view returns (
|
||||
uint256 decimals,
|
||||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus,
|
||||
uint256 reserveFactor,
|
||||
bool usageAsCollateralEnabled,
|
||||
bool borrowingEnabled,
|
||||
bool stableBorrowRateEnabled,
|
||||
bool isActive,
|
||||
bool isFrozen
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveAddressProviderRegistryInterface {
|
||||
function getAddressesProvidersList() external view returns (address[] memory);
|
||||
}
|
||||
|
||||
interface ATokenInterface {
|
||||
function scaledBalanceOf(address _user) external view returns (uint256);
|
||||
function isTransferAllowed(address _user, uint256 _amount) external view returns (bool);
|
||||
function balanceOf(address _user) external view returns(uint256);
|
||||
function transferFrom(address, address, uint) external returns (bool);
|
||||
function approve(address, uint256) external;
|
||||
}
|
||||
|
||||
interface StateSenderInterface {
|
||||
function syncState(address receiver, bytes calldata data) external;
|
||||
function register(address sender, address receiver) external;
|
||||
}
|
||||
|
||||
interface IndexInterface {
|
||||
function master() external view returns (address);
|
||||
}
|
||||
|
||||
interface FlashloanInterface {
|
||||
function initiateFlashLoan(bytes memory data, uint ethAmt) external;
|
||||
}
|
||||
|
||||
interface AavePriceOracle {
|
||||
function getAssetPrice(address _asset) external view returns(uint256);
|
||||
function getAssetsPrices(address[] calldata _assets) external view returns(uint256[] memory);
|
||||
function getSourceOfAsset(address _asset) external view returns(uint256);
|
||||
function getFallbackOracle() external view returns(uint256);
|
||||
}
|
||||
|
||||
interface ChainLinkInterface {
|
||||
function latestAnswer() external view returns (int256);
|
||||
function decimals() external view returns (uint256);
|
||||
}
|
254
contracts/senders/aave-v2-migrator/main.sol
Normal file
254
contracts/senders/aave-v2-migrator/main.sol
Normal file
|
@ -0,0 +1,254 @@
|
|||
pragma solidity ^0.7.0;
|
||||
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, IndexInterface } from "./interfaces.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
contract LiquidityResolver is Helpers, Events {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
event variablesUpdate(uint _safeRatioGap, uint _fee);
|
||||
|
||||
function updateVariables(uint _safeRatioGap, uint _fee) public {
|
||||
require(msg.sender == instaIndex.master(), "not-master");
|
||||
safeRatioGap = _safeRatioGap;
|
||||
fee = _fee;
|
||||
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 {
|
||||
require(msg.sender == instaIndex.master(), "not-master");
|
||||
require(_target != address(0), "target-invalid");
|
||||
assembly {
|
||||
let succeeded := delegatecall(gas(), _target, add(_data, 0x20), mload(_data), 0, 0)
|
||||
|
||||
switch iszero(succeeded)
|
||||
case 1 {
|
||||
// throw if delegatecall failed
|
||||
let size := returndatasize()
|
||||
returndatacopy(0x00, 0x00, size)
|
||||
revert(0x00, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
deposits[msg.sender][_token] += _amt;
|
||||
}
|
||||
|
||||
emit LogDeposit(msg.sender, tokens, _amts);
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
if (_amt > maxAmt) {
|
||||
_amt = maxAmt;
|
||||
}
|
||||
|
||||
deposits[msg.sender][_token] = sub(maxAmt, _amt);
|
||||
|
||||
if (_token == ethAddr) {
|
||||
TokenInterface _tokenContract = TokenInterface(wethAddr);
|
||||
uint _ethBal = address(this).balance;
|
||||
uint _tknBal = _tokenContract.balanceOf(address(this));
|
||||
if ((_ethBal + _tknBal) < _amt) {
|
||||
aave.withdraw(wethAddr, sub(_amt, (_tknBal + _ethBal)), address(this));
|
||||
}
|
||||
_tokenContract.withdraw((sub(_amt, _ethBal)));
|
||||
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;
|
||||
}
|
||||
|
||||
isPositionSafe();
|
||||
|
||||
emit LogWithdraw(msg.sender, tokens, _amts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param _tokens - array of tokens to transfer to L2 receiver's contract
|
||||
* @param _amts - array of token amounts to transfer to L2 receiver's contract
|
||||
*/
|
||||
function settle(address[] calldata _tokens, uint[] calldata _amts) external {
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
for (uint i = 0; i < supportedTokens.length; i++) {
|
||||
address _token = supportedTokens[i];
|
||||
if (_token == ethAddr) {
|
||||
_token = wethAddr;
|
||||
if (address(this).balance > 0) {
|
||||
TokenInterface(wethAddr).deposit{value: address(this).balance}();
|
||||
}
|
||||
}
|
||||
IERC20 _tokenContract = IERC20(_token);
|
||||
uint _tokenBal = _tokenContract.balanceOf(address(this));
|
||||
if (_tokenBal > 0) {
|
||||
_tokenContract.approve(address(this), _tokenBal);
|
||||
aave.deposit(_token, _tokenBal, address(this), 3288);
|
||||
}
|
||||
(
|
||||
uint supplyBal,,
|
||||
uint borrowBal,
|
||||
,,,,,
|
||||
) = aaveData.getUserReserveData(_token, address(this));
|
||||
if (supplyBal != 0 && borrowBal != 0) {
|
||||
if (supplyBal > borrowBal) {
|
||||
aave.withdraw(_token, borrowBal, address(this)); // TODO: fail because of not enough withdrawing capacity?
|
||||
IERC20(_token).approve(address(aave), borrowBal);
|
||||
aave.repay(_token, borrowBal, 2, address(this));
|
||||
} else {
|
||||
aave.withdraw(_token, supplyBal, address(this)); // TODO: fail because of not enough withdrawing capacity?
|
||||
IERC20(_token).approve(address(aave), supplyBal);
|
||||
aave.repay(_token, supplyBal, 2, address(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < _tokens.length; i++) {
|
||||
aave.withdraw(_tokens[i], _amts[i], address(this));
|
||||
// TODO: transfer to polygon's receiver address "polygonReceiver"
|
||||
isPositionSafe();
|
||||
}
|
||||
}
|
||||
// TODO: emit event
|
||||
}
|
||||
|
||||
contract MigrateResolver is LiquidityResolver {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
function _migrate(
|
||||
AaveInterface aave,
|
||||
AaveDataRaw memory _data,
|
||||
address sourceDsa,
|
||||
uint ethAmt
|
||||
) internal {
|
||||
require(_data.supplyTokens.length > 0, "0-length-not-allowed");
|
||||
require(_data.targetDsa != address(0), "invalid-address");
|
||||
require(_data.supplyTokens.length == _data.supplyAmts.length, "invalid-length");
|
||||
require(
|
||||
_data.borrowTokens.length == _data.variableBorrowAmts.length &&
|
||||
_data.borrowTokens.length == _data.stableBorrowAmts.length,
|
||||
"invalid-length"
|
||||
);
|
||||
|
||||
if (ethAmt > 0) {
|
||||
aave.deposit(wethAddr, ethAmt, address(this), 3288);
|
||||
}
|
||||
|
||||
(uint[] memory stableBorrows, uint[] memory variableBorrows, uint[] memory totalBorrows) = _PaybackCalculate(aave, _data, sourceDsa);
|
||||
|
||||
_PaybackStable(_data.borrowTokens.length, aave, _data.borrowTokens, stableBorrows, sourceDsa);
|
||||
_PaybackVariable(_data.borrowTokens.length, aave, _data.borrowTokens, variableBorrows, sourceDsa);
|
||||
|
||||
(uint[] memory totalSupplies) = _getAtokens(sourceDsa, aave, _data.supplyTokens, _data.supplyAmts);
|
||||
|
||||
// Aave on Polygon doesn't have stable borrowing so we'll borrow all the debt in variable
|
||||
AaveData memory data;
|
||||
|
||||
data.borrowTokens = _data.borrowTokens;
|
||||
data.borrowAmts = _data.stableBorrowAmts;
|
||||
data.supplyAmts = totalSupplies;
|
||||
data.supplyTokens = _data.supplyTokens;
|
||||
data.targetDsa = _data.targetDsa;
|
||||
data.borrowAmts = totalBorrows;
|
||||
|
||||
// Checks the amount that user is trying to migrate is 20% below the Liquidation
|
||||
_checkRatio(data);
|
||||
|
||||
if (ethAmt > 0) {
|
||||
aave.withdraw(wethAddr, ethAmt, address(this));
|
||||
}
|
||||
|
||||
isPositionSafe();
|
||||
|
||||
stateSender.syncState(polygonReceiver, abi.encode(data));
|
||||
|
||||
emit LogAaveV2Migrate(
|
||||
sourceDsa,
|
||||
data.targetDsa,
|
||||
data.supplyTokens,
|
||||
data.borrowTokens,
|
||||
totalSupplies,
|
||||
variableBorrows,
|
||||
stableBorrows
|
||||
);
|
||||
}
|
||||
|
||||
function migrate(AaveDataRaw calldata _data) external {
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
_migrate(aave, _data, msg.sender, 0);
|
||||
}
|
||||
|
||||
function migrateFlashCallback(AaveDataRaw calldata _data, address dsa, uint ethAmt) external {
|
||||
require(msg.sender == address(flashloanContract), "not-flashloan-contract"); // TODO: flash loan contract
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
|
||||
TokenInterface wethContract = TokenInterface(wethAddr);
|
||||
wethContract.approve(address(aave), ethAmt);
|
||||
_migrate(aave, _data, dsa, ethAmt);
|
||||
wethContract.transfer(address(flashloanContract), ethAmt);
|
||||
}
|
||||
|
||||
function migrateWithFlash(AaveDataRaw calldata _data, uint ethAmt) external {
|
||||
bytes memory data = abi.encode(_data, msg.sender, ethAmt);
|
||||
|
||||
flashloanContract.initiateFlashLoan(data, ethAmt);
|
||||
}
|
||||
|
||||
}
|
71
contracts/senders/aave-v2-migrator/variables.sol
Normal file
71
contracts/senders/aave-v2-migrator/variables.sol
Normal file
|
@ -0,0 +1,71 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import {
|
||||
AaveLendingPoolProviderInterface,
|
||||
AaveDataProviderInterface,
|
||||
StateSenderInterface,
|
||||
IndexInterface,
|
||||
FlashloanInterface
|
||||
} 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;
|
||||
}
|
||||
|
||||
struct TokenPrice {
|
||||
uint priceInEth;
|
||||
uint priceInUsd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Aave referal code
|
||||
*/
|
||||
uint16 constant internal referralCode = 3228;
|
||||
|
||||
address constant internal polygonReceiver = address(0); // TODO: Replace this
|
||||
FlashloanInterface constant internal flashloanContract = FlashloanInterface(address(0)); // TODO: Replace this
|
||||
|
||||
// This will be used to have debt/collateral ratio always 20% less than liquidation
|
||||
// TODO: Is this number correct for it?
|
||||
uint public safeRatioGap = 800000000000000000; // 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);
|
||||
|
||||
}
|
17764
package-lock.json
generated
17764
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,10 @@
|
|||
"chai": "^4.3.4",
|
||||
"ethereum-waffle": "^3.3.0",
|
||||
"ethers": "^5.1.0",
|
||||
"hardhat": "^2.1.2"
|
||||
"hardhat": "^2.1.2",
|
||||
"solc": "0.7.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^3.4.0-solc-0.7"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user