mirror of
https://github.com/Instadapp/dsa-polygon-migration.git
synced 2024-07-29 22:27:58 +00:00
commit
959952ae72
4
.env.example
Normal file
4
.env.example
Normal file
|
@ -0,0 +1,4 @@
|
|||
ALCHEMY_ID="<>"
|
||||
QUIKNODE_ID="<>"
|
||||
ETHERSCAN="<>"
|
||||
PRIVATE_KEY="<>"
|
15
contracts.json
Normal file
15
contracts.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"1": {
|
||||
"InstaAaveV2MigratorSender": "0xA0557234eB7b3c503388202D3768Cfa2f1AE9Dc2",
|
||||
"InstaMasterProxy": "0xa471D83e526B6b5D6c876088D34834B44D4064ff",
|
||||
"InstaPool": "0xd7e8E6f5deCc5642B77a5dD0e445965B128a585D",
|
||||
"ConnectAaveV2PolygonMigrator": "0x9686ce6ad5c3f7b212caf401b928c4bb3422e7ba",
|
||||
"InstaAaveV2MigratorSenderImplementation": "0x3cD0727d7bbBb6A5EADBDC72349370a7eB599301"
|
||||
},
|
||||
"137": {
|
||||
"InstaAaveV2MigratorReceiver": "0x4A090897f47993C2504144419751D6A91D79AbF4",
|
||||
"InstaMasterProxy": "0x697860CeE594c577F18f71cAf3d8B68D913c7366",
|
||||
"InstaPolygonTokenMapping": "0xa471D83e526B6b5D6c876088D34834B44D4064ff",
|
||||
"InstaAaveV2MigratorReceiverImplementation": "0xd7e8E6f5deCc5642B77a5dD0e445965B128a585D"
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ pragma experimental ABIEncoderV2;
|
|||
|
||||
interface TokenInterface {
|
||||
function approve(address, uint256) external;
|
||||
function transfer(address, uint) external;
|
||||
function transfer(address, uint) external returns (bool);
|
||||
function transferFrom(address, address, uint) external;
|
||||
function deposit() external payable;
|
||||
function withdraw(uint) external;
|
||||
|
@ -15,14 +15,3 @@ 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);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ abstract contract Stores {
|
|||
/**
|
||||
* @dev Return memory variable address
|
||||
*/
|
||||
MemoryInterface constant internal instaMemory = MemoryInterface(address(0)); // TODO: memory address on Polygon
|
||||
MemoryInterface constant internal instaMemory = MemoryInterface(0x6C7256cf7C003dD85683339F75DdE9971f98f2FD);
|
||||
|
||||
/**
|
||||
* @dev Get Uint value from InstaMemory Contract.
|
||||
|
|
|
@ -2,6 +2,9 @@ pragma solidity ^0.7.0;
|
|||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { Variables } from "./variables.sol";
|
||||
import "hardhat/console.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title InstaAccountV2.
|
||||
|
@ -16,18 +19,19 @@ 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
|
||||
address internal immutable migrationContract;
|
||||
// Connnectors Address.
|
||||
address public immutable connectorsM1;
|
||||
|
||||
constructor(address _connectors) {
|
||||
constructor(address _connectors, address _migration) {
|
||||
connectorsM1 = _connectors;
|
||||
migrationContract = _migration;
|
||||
}
|
||||
}
|
||||
|
||||
contract InstaImplementationM1 is Constants {
|
||||
|
||||
constructor(address _connectors) Constants(_connectors) {}
|
||||
constructor(address _connectors, address _migration) Constants(_connectors, _migration) {}
|
||||
|
||||
function decodeEvent(bytes memory response) internal pure returns (string memory _eventCode, bytes memory _eventParams) {
|
||||
if (response.length > 0) {
|
||||
|
|
|
@ -3,6 +3,7 @@ pragma experimental ABIEncoderV2;
|
|||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||
import "@openzeppelin/contracts/utils/Address.sol";
|
||||
import { DSMath } from "./common/math.sol";
|
||||
|
||||
interface Account {
|
||||
|
@ -261,11 +262,10 @@ interface MigrationInterface {
|
|||
contract Setup {
|
||||
address public constant soloAddr = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
|
||||
address public constant wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
MigrationInterface public constant migrationAddr = MigrationInterface(address(0)); // TODO: Migration address
|
||||
MigrationInterface public constant migrationAddr = MigrationInterface(0xA0557234eB7b3c503388202D3768Cfa2f1AE9Dc2);
|
||||
|
||||
TokenInterface wethContract = TokenInterface(wethAddr);
|
||||
ISoloMargin solo = ISoloMargin(soloAddr);
|
||||
|
||||
}
|
||||
|
||||
contract DydxFlashloaner is Setup, ICallee, DydxFlashloanBase, DSMath {
|
||||
|
@ -279,14 +279,14 @@ contract DydxFlashloaner is Setup, ICallee, DydxFlashloanBase, DSMath {
|
|||
require(sender == address(this), "not-same-sender");
|
||||
require(msg.sender == soloAddr, "not-solo-dydx-sender");
|
||||
|
||||
(AaveDataRaw memory _data, address dsa, uint ethAmt) = abi.decode(
|
||||
(bytes memory callData, uint ethAmt) = abi.decode(
|
||||
data,
|
||||
(AaveDataRaw, address, uint)
|
||||
(bytes, uint)
|
||||
);
|
||||
|
||||
wethContract.transfer(address(migrationAddr), ethAmt);
|
||||
|
||||
migrationAddr.migrateFlashCallback(_data, dsa, ethAmt);
|
||||
Address.functionCall(address(migrationAddr), callData);
|
||||
}
|
||||
|
||||
function initiateFlashLoan(bytes memory data, uint ethAmt) external {
|
||||
|
@ -302,6 +302,8 @@ contract DydxFlashloaner is Setup, ICallee, DydxFlashloanBase, DSMath {
|
|||
Account.Info[] memory accountInfos = new Account.Info[](1);
|
||||
accountInfos[0] = _getAccountInfo();
|
||||
|
||||
wethContract.approve(soloAddr, ethAmt + 2);
|
||||
|
||||
solo.operate(accountInfos, operations);
|
||||
}
|
||||
}
|
||||
|
@ -312,4 +314,4 @@ contract InstaPool is DydxFlashloaner {
|
|||
}
|
||||
|
||||
receive() external payable {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,27 @@ pragma solidity >=0.7.0;
|
|||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
event LogUpdateSafeRatioGap(
|
||||
uint256 oldSafeRatioGap,
|
||||
uint256 newSafeRatioGap
|
||||
);
|
||||
|
||||
event LogWithdraw(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
event LogAddSupportedTokens(
|
||||
address[] tokens
|
||||
);
|
||||
|
||||
event LogSettle();
|
||||
|
||||
event LogAaveV2Migrate(
|
||||
address indexed user,
|
||||
address[] supplyTokens,
|
||||
address[] borrowTokens,
|
||||
uint256[] supplyAmts,
|
||||
uint256[] borrowAmts
|
||||
);
|
||||
|
||||
event LogStateSync(
|
||||
uint256 indexed stateId,
|
||||
bytes data
|
||||
);
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pragma solidity >=0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||
|
@ -10,12 +11,28 @@ import {
|
|||
TokenMappingInterface,
|
||||
AaveData,
|
||||
AaveDataProviderInterface,
|
||||
AaveInterface
|
||||
AaveInterface,
|
||||
AccountInterface
|
||||
} from "./interfaces.sol";
|
||||
|
||||
abstract contract Helpers is Stores, DSMath, Variables {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
struct TransferHelperData {
|
||||
address token;
|
||||
address atoken;
|
||||
uint atokenBal;
|
||||
uint supplyAmt;
|
||||
uint tokenLiq;
|
||||
}
|
||||
|
||||
struct SpellHelperData {
|
||||
address token;
|
||||
address atoken;
|
||||
uint tokenLiq;
|
||||
uint borrowAmt;
|
||||
}
|
||||
|
||||
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]);
|
||||
|
@ -28,106 +45,90 @@ abstract contract Helpers is Stores, DSMath, Variables {
|
|||
return data;
|
||||
}
|
||||
|
||||
function isPositionSafe() internal returns (bool isOk) {
|
||||
// TODO: Check the final position health
|
||||
|
||||
function isPositionSafe() internal view returns (bool isOk) {
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
(,,,,,uint healthFactor) = aave.getUserAccountData(address(this));
|
||||
uint minLimit = wdiv(1e18, safeRatioGap);
|
||||
isOk = healthFactor > minLimit;
|
||||
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;
|
||||
TransferHelperData memory data;
|
||||
data.token = supplyTokens[i] == maticAddr ? wmaticAddr : supplyTokens[i];
|
||||
(data.atoken, ,) = aaveData.getReserveTokensAddresses(data.token);
|
||||
IERC20 _atokenContract = IERC20(data.atoken);
|
||||
IERC20 _tokenContract = IERC20(data.token);
|
||||
data.atokenBal = _atokenContract.balanceOf(address(this));
|
||||
data.supplyAmt = supplyAmts[i];
|
||||
|
||||
// get Aave liquidity of token
|
||||
uint tokenLiq = uint(0);
|
||||
(data.tokenLiq,,,,,,,,,) = aaveData.getReserveData(data.token);
|
||||
|
||||
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
|
||||
if (data.atokenBal < data.supplyAmt) {
|
||||
uint _reqAmt = data.supplyAmt - data.atokenBal;
|
||||
uint num = _reqAmt/data.tokenLiq + 1;
|
||||
uint splitAmt = _reqAmt/num;
|
||||
uint finalSplit = _reqAmt - (splitAmt * (num - 1));
|
||||
|
||||
_tokenContract.approve(address(aave), _reqAmt);
|
||||
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);
|
||||
if (j < num - 1) {
|
||||
aave.borrow(data.token, splitAmt, 2, 3288, address(this));
|
||||
aave.deposit(data.token, splitAmt, address(this), 3288);
|
||||
if (j == 0) aave.setUserUseReserveAsCollateral(data.token, true);
|
||||
} else {
|
||||
aave.borrow(_token, finalSplit, 2, 3288, address(this)); // TODO: is "2" for interest rate mode. Right?
|
||||
aave.deposit(_token, finalSplit, address(this), 3288);
|
||||
aave.borrow(data.token, finalSplit, 2, 3288, address(this));
|
||||
aave.deposit(data.token, finalSplit, address(this), 3288);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFlash) {
|
||||
aave.withdraw(_token, _flashAmt, address(this));
|
||||
}
|
||||
|
||||
_atokenContract.safeTransfer(dsa, _supplyAmt);
|
||||
_atokenContract.safeTransfer(dsa, data.supplyAmt);
|
||||
}
|
||||
}
|
||||
|
||||
function borrowAndTransferSpells(AaveInterface aave, address dsa, address[] memory borrowTokens, uint[] memory borrowAmts) internal {
|
||||
function borrowAndTransferSpells(address dsa, address[] memory supplyTokens, 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];
|
||||
SpellHelperData memory data;
|
||||
data.token = borrowTokens[i] == maticAddr ? wmaticAddr : borrowTokens[i];
|
||||
(data.atoken, ,) = aaveData.getReserveTokensAddresses(data.token);
|
||||
(data.tokenLiq,,,,,,,,,) = aaveData.getReserveData(data.token);
|
||||
data.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 num = data.borrowAmt/data.tokenLiq + 1;
|
||||
uint splitAmt = data.borrowAmt/num;
|
||||
uint finalSplit = data.borrowAmt - (splitAmt * (num - 1));
|
||||
|
||||
uint spellsAmt = (2 * num) + 1;
|
||||
uint spellsAmt = num <= 1 ? (2 * (num + 1)) : (2 * (num + 1)) + 1;
|
||||
string[] memory targets = new string[](spellsAmt);
|
||||
bytes[] memory castData = new bytes[](spellsAmt);
|
||||
|
||||
targets[0] = "AAVE-V2-A";
|
||||
castData[0] = abi.encodeWithSignature("enableCollateral(address[])", supplyTokens);
|
||||
|
||||
for (uint j = 0; j < num; j++) {
|
||||
targets[j] = "AAVE-A";
|
||||
uint k = j * 2;
|
||||
uint k = j * 2 + 1;
|
||||
|
||||
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?
|
||||
targets[k] = "AAVE-V2-A";
|
||||
castData[k] = abi.encodeWithSignature("borrow(address,uint256,uint256,uint256,uint256)", data.token, splitAmt, 2, 0, 0);
|
||||
targets[k+1] = "AAVE-V2-A";
|
||||
castData[k+1] = abi.encodeWithSignature("deposit(address,uint256,uint256,uint256)", data.token, splitAmt, 0, 0);
|
||||
} 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?
|
||||
targets[k] = "AAVE-V2-A";
|
||||
castData[k] = abi.encodeWithSignature("borrow(address,uint256,uint256,uint256,uint256)", data.token, finalSplit, 2, 0, 0);
|
||||
targets[k+1] = "AAVE-V2-A";
|
||||
castData[k+1] = abi.encodeWithSignature("deposit(address,uint256,uint256,uint256)", data.token, finalSplit, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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?)
|
||||
targets[spellsAmt - 1] = "BASIC-A";
|
||||
castData[spellsAmt - 1] = abi.encodeWithSignature("withdraw(address,uint256,address,uint256,uint256)", data.atoken, data.borrowAmt, address(this), 0, 0); // encode the data of atoken withdrawal
|
||||
AccountInterface(dsa).castMigrate(targets, castData, address(this));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ interface AccountInterface {
|
|||
function enable(address) external;
|
||||
function disable(address) external;
|
||||
function isAuth(address) external view returns (bool);
|
||||
function cast(
|
||||
function castMigrate(
|
||||
string[] calldata _targets,
|
||||
bytes[] calldata _datas,
|
||||
address _origin
|
||||
) external payable returns (bytes32);
|
||||
function migrateAave(address) external payable returns (bytes32);
|
||||
function version() external view returns (uint);
|
||||
}
|
||||
|
||||
interface TokenMappingInterface {
|
||||
|
@ -62,6 +62,18 @@ interface AaveDataProviderInterface {
|
|||
bool isActive,
|
||||
bool isFrozen
|
||||
);
|
||||
function getReserveData(address asset) external view returns (
|
||||
uint256 availableLiquidity,
|
||||
uint256 totalStableDebt,
|
||||
uint256 totalVariableDebt,
|
||||
uint256 liquidityRate,
|
||||
uint256 variableBorrowRate,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 averageStableBorrowRate,
|
||||
uint256 liquidityIndex,
|
||||
uint256 variableBorrowIndex,
|
||||
uint40 lastUpdateTimestamp
|
||||
);
|
||||
}
|
||||
|
||||
interface AaveInterface {
|
||||
|
@ -84,4 +96,8 @@ interface AaveInterface {
|
|||
uint256 ltv,
|
||||
uint256 healthFactor
|
||||
);
|
||||
}
|
||||
|
||||
interface InstaListInterface {
|
||||
function accountID(address) external view returns (uint);
|
||||
}
|
|
@ -11,6 +11,26 @@ import { Helpers } from "./helpers.sol";
|
|||
contract MigrateResolver is Helpers, Events {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
function updateSafeRatioGap(uint _safeRatioGap) public {
|
||||
require(msg.sender == instaIndex.master(), "not-master");
|
||||
emit LogUpdateSafeRatioGap(safeRatioGap, _safeRatioGap);
|
||||
safeRatioGap = _safeRatioGap;
|
||||
}
|
||||
|
||||
function addTokenSupport(address[] memory _tokens) public {
|
||||
require(msg.sender == instaIndex.master(), "not-master");
|
||||
for (uint i = 0; i < supportedTokens.length; i++) {
|
||||
delete isSupportedToken[supportedTokens[i]];
|
||||
}
|
||||
delete supportedTokens;
|
||||
for (uint i = 0; i < _tokens.length; i++) {
|
||||
require(!isSupportedToken[_tokens[i]], "already-added");
|
||||
isSupportedToken[_tokens[i]] = true;
|
||||
supportedTokens.push(_tokens[i]);
|
||||
}
|
||||
emit LogAddSupportedTokens(_tokens);
|
||||
}
|
||||
|
||||
function spell(address _target, bytes memory _data) external {
|
||||
require(msg.sender == instaIndex.master(), "not-master");
|
||||
require(_target != address(0), "target-invalid");
|
||||
|
@ -27,91 +47,11 @@ contract MigrateResolver is Helpers, Events {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 (_token == wmaticAddr) {
|
||||
if (address(this).balance > 0) {
|
||||
TokenInterface(wmaticAddr).deposit{value: address(this).balance}();
|
||||
}
|
||||
|
@ -119,7 +59,7 @@ contract MigrateResolver is Helpers, Events {
|
|||
IERC20 _tokenContract = IERC20(_token);
|
||||
uint _tokenBal = _tokenContract.balanceOf(address(this));
|
||||
if (_tokenBal > 0) {
|
||||
_tokenContract.approve(address(this), _tokenBal);
|
||||
_tokenContract.approve(address(aave), _tokenBal);
|
||||
aave.deposit(_token, _tokenBal, address(this), 3288);
|
||||
}
|
||||
(
|
||||
|
@ -129,17 +69,17 @@ contract MigrateResolver is Helpers, Events {
|
|||
) = 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?
|
||||
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 + flashAmts[_token]), address(this)); // TODO: fail because of not enough withdrawing capacity?
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: emit event
|
||||
emit LogSettle();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -147,30 +87,33 @@ contract MigrateResolver is Helpers, Events {
|
|||
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;
|
||||
address dsa = data.targetDsa;
|
||||
uint[] memory supplyAmts = data.supplyAmts;
|
||||
uint[] memory borrowAmts = data.borrowAmts;
|
||||
address[] memory supplyTokens = data.supplyTokens;
|
||||
address[] memory borrowTokens = data.borrowTokens;
|
||||
|
||||
require(instaList.accountID(dsa) != 0, "not-a-dsa");
|
||||
require(AccountInterface(dsa).version() == 2, "not-v2-dsa");
|
||||
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
|
||||
transferAtokens(aave, dsa, supplyTokens, supplyAmts);
|
||||
|
||||
// Have to borrow from user's account & transfer
|
||||
borrowAndTransferSpells(aave, dsa, borrowTokens, borrowAmts);
|
||||
borrowAndTransferSpells(dsa, supplyTokens, borrowTokens, borrowAmts);
|
||||
|
||||
isPositionSafe();
|
||||
|
||||
// TODO: emit event
|
||||
emit LogAaveV2Migrate(dsa, supplyTokens, borrowTokens, supplyAmts, supplyAmts);
|
||||
}
|
||||
|
||||
function onStateReceive(uint256 stateId, bytes calldata receivedData) external {
|
||||
// Add some more require statements. Any kind of hashing for better privacy?
|
||||
require(msg.sender == maticReceiver, "not-receiver-address");
|
||||
require(stateId > lastStateId, "wrong-data");
|
||||
lastStateId = stateId;
|
||||
|
||||
|
@ -178,9 +121,11 @@ contract AaveV2Migrator is MigrateResolver {
|
|||
// Can't do it via any address as user can migrate 2 times
|
||||
positions[stateId] = receivedData;
|
||||
|
||||
// TODO: add event
|
||||
emit LogStateSync(stateId, receivedData);
|
||||
}
|
||||
}
|
||||
|
||||
contract InstaAaveV2MigratorReceiverImplementation is AaveV2Migrator {
|
||||
function migrate(uint _id) external {
|
||||
bytes memory _data = positions[_id];
|
||||
|
||||
|
@ -191,7 +136,7 @@ contract AaveV2Migrator is MigrateResolver {
|
|||
_migratePosition(data);
|
||||
|
||||
delete positions[_id];
|
||||
|
||||
// TODO: add event
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
}
|
||||
|
|
|
@ -4,40 +4,67 @@ import {
|
|||
TokenMappingInterface,
|
||||
AaveLendingPoolProviderInterface,
|
||||
AaveDataProviderInterface,
|
||||
IndexInterface
|
||||
IndexInterface,
|
||||
InstaListInterface
|
||||
} from "./interfaces.sol";
|
||||
|
||||
contract Variables {
|
||||
// Constant Address //
|
||||
|
||||
// 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));
|
||||
|
||||
/**
|
||||
* @dev token Mapping contract Provider
|
||||
*/
|
||||
TokenMappingInterface constant public tokenMapping = TokenMappingInterface(address(0xa471D83e526B6b5D6c876088D34834B44D4064ff));
|
||||
/**
|
||||
* @dev Aave Provider
|
||||
*/
|
||||
AaveLendingPoolProviderInterface constant internal aaveProvider = AaveLendingPoolProviderInterface(0xd05e3E715d945B59290df0ae8eF85c1BdB684744);
|
||||
|
||||
|
||||
/**
|
||||
* @dev Aave Data Provider
|
||||
*/
|
||||
// TODO: add L2 Data provider address
|
||||
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(address(0));
|
||||
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x7551b5D2763519d4e37e8B81929D336De671d46d);
|
||||
|
||||
|
||||
|
||||
// dsa => position
|
||||
mapping(uint => bytes) public positions;
|
||||
mapping(address => mapping(address => uint)) public deposits;
|
||||
|
||||
// InstaIndex Address.
|
||||
/**
|
||||
* @dev InstaIndex Polygon contract
|
||||
*/
|
||||
IndexInterface public constant instaIndex = IndexInterface(0xA9B99766E6C676Cf1975c0D3166F96C0848fF5ad);
|
||||
|
||||
// TODO: Set by construtor?
|
||||
mapping(address => bool) public isSupportedToken;
|
||||
address[] public supportedTokens;
|
||||
/**
|
||||
* @dev InstaList Polygon contract
|
||||
*/
|
||||
InstaListInterface public constant instaList = InstaListInterface(0x839c2D3aDe63DF5b0b8F3E57D5e145057Ab41556);
|
||||
|
||||
|
||||
/**
|
||||
* @dev Matic StateReceiver contract
|
||||
*/
|
||||
address public constant maticReceiver = 0x0000000000000000000000000000000000001001;
|
||||
|
||||
|
||||
// Storage variables //
|
||||
|
||||
/**
|
||||
* @dev This will be used to have debt/collateral ratio always 20% less than liquidation
|
||||
*/
|
||||
uint public safeRatioGap = 800000000000000000; // 20%? 2e17
|
||||
|
||||
// mapping stateId => user position
|
||||
mapping(uint => bytes) public positions;
|
||||
|
||||
/**
|
||||
* @dev Mapping of supported token
|
||||
*/
|
||||
mapping(address => bool) public isSupportedToken;
|
||||
|
||||
/**
|
||||
* @dev Array of supported token
|
||||
*/
|
||||
address[] public supportedTokens; // don't add maticAddr. Only add wmaticAddr?
|
||||
|
||||
/**
|
||||
* @dev last stateId from the onStateReceive
|
||||
*/
|
||||
uint256 internal lastStateId;
|
||||
}
|
60
contracts/receivers/mapping/main.sol
Normal file
60
contracts/receivers/mapping/main.sol
Normal file
|
@ -0,0 +1,60 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface IndexInterface {
|
||||
function master() external view returns (address);
|
||||
}
|
||||
|
||||
abstract contract Helpers {
|
||||
|
||||
event LogTokenMapAdded(address indexed L1_token, address indexed L2_token);
|
||||
event LogTokenMapUpdated(address indexed L1_token, address indexed L2_token_new, address indexed L2_token_old);
|
||||
|
||||
// InstaIndex Address.
|
||||
IndexInterface public constant instaIndex = IndexInterface(0xA9B99766E6C676Cf1975c0D3166F96C0848fF5ad);
|
||||
|
||||
address public constant ethAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
|
||||
mapping (address => address) public tokenMapping;
|
||||
|
||||
modifier isMaster {
|
||||
require(msg.sender == instaIndex.master(), "not-a-master");
|
||||
_;
|
||||
}
|
||||
|
||||
function _addTokenMaps(address[] memory L1, address[] memory L2) internal {
|
||||
uint len = L1.length;
|
||||
require(len == L2.length, "addTokenMaps: Length not same");
|
||||
for (uint256 i = 0; i < len; i++) {
|
||||
require(tokenMapping[L1[i]] == address(0), "addTokenMaps: Token map already added");
|
||||
tokenMapping[L1[i]] = L2[i];
|
||||
emit LogTokenMapAdded(L1[i], L2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function addTokenMaps(address[] memory L1, address[] memory L2) external isMaster {
|
||||
_addTokenMaps(L1, L2);
|
||||
}
|
||||
|
||||
function updateTokenMaps(address[] memory L1, address[] memory L2) external isMaster {
|
||||
uint len = L1.length;
|
||||
require(len == L2.length, "updateTokenMaps: Length not same");
|
||||
for (uint256 i = 0; i < len; i++) {
|
||||
require(tokenMapping[L1[i]] != address(0), "updateTokenMaps: Token map already added");
|
||||
require(tokenMapping[L1[i]] != L2[i], "updateTokenMaps: L1 Token is mapped to same L2 Token");
|
||||
emit LogTokenMapUpdated(L1[i], tokenMapping[L1[i]], L2[i]);
|
||||
tokenMapping[L1[i]] = L2[i];
|
||||
}
|
||||
}
|
||||
|
||||
function getMapping(address L1Address) external view returns (address) {
|
||||
return tokenMapping[L1Address];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
contract InstaPolygonTokenMapping is Helpers {
|
||||
constructor(address[] memory L1, address[] memory L2) {
|
||||
_addTokenMaps(L1, L2);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import { AaveLendingPoolProviderInterface, AaveDataProviderInterface, AaveMigrat
|
|||
|
||||
abstract contract Helpers is DSMath, Stores {
|
||||
|
||||
AaveMigratorInterface constant internal migrator = AaveMigratorInterface(address(2)); // Replace this (Migrator contract)
|
||||
AaveMigratorInterface constant internal migrator = AaveMigratorInterface(address(0xA0557234eB7b3c503388202D3768Cfa2f1AE9Dc2));
|
||||
|
||||
/**
|
||||
* @dev Aave Data Provider
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { TokenInterface, AccountInterface } from "../../common/interfaces.sol";
|
||||
import { TokenInterface } from "../../common/interfaces.sol";
|
||||
import { AaveInterface, ATokenInterface, AaveDataRaw } from "./interfaces.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
@ -9,21 +9,27 @@ import { Events } from "./events.sol";
|
|||
contract AaveMigrateResolver is Helpers, Events {
|
||||
|
||||
function migrate(
|
||||
AaveDataRaw calldata _data,
|
||||
address targetDsa,
|
||||
address[] memory supplyTokens,
|
||||
address[] memory borrowTokens,
|
||||
uint[] memory variableBorrowAmts,
|
||||
uint[] memory stableBorrowAmts,
|
||||
uint[] memory supplyAmts,
|
||||
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");
|
||||
require(supplyTokens.length > 0, "0-length-not-allowed");
|
||||
require(supplyTokens.length == supplyAmts.length, "invalid-length");
|
||||
require(borrowTokens.length == variableBorrowAmts.length && borrowTokens.length == stableBorrowAmts.length, "invalid-length");
|
||||
require(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;
|
||||
data.targetDsa = targetDsa;
|
||||
data.supplyTokens = supplyTokens;
|
||||
data.borrowTokens = borrowTokens;
|
||||
data.variableBorrowAmts = variableBorrowAmts;
|
||||
data.stableBorrowAmts = stableBorrowAmts;
|
||||
data.supplyAmts = supplyAmts;
|
||||
|
||||
for (uint i = 0; i < data.supplyTokens.length; i++) {
|
||||
address _token = data.supplyTokens[i] == ethAddr ? wethAddr : data.supplyTokens[i];
|
||||
|
@ -50,6 +56,6 @@ contract AaveMigrateResolver is Helpers, Events {
|
|||
|
||||
}
|
||||
|
||||
contract AaveV2Migrator is AaveMigrateResolver {
|
||||
string constant public name = "AaveV2PolygonMigrator-v1";
|
||||
}
|
||||
contract ConnectV2AaveV2PolygonMigrator is AaveMigrateResolver {
|
||||
string constant public name = "Aave-V2-Polygon-Migrator-v1";
|
||||
}
|
||||
|
|
|
@ -2,16 +2,9 @@ pragma solidity >=0.7.0;
|
|||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(
|
||||
address owner,
|
||||
event LogSettle(
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
);
|
||||
|
||||
event LogWithdraw(
|
||||
address owner,
|
||||
address[] tokens,
|
||||
uint[] amts
|
||||
uint256[] amts
|
||||
);
|
||||
|
||||
event LogAaveV2Migrate(
|
||||
|
@ -19,11 +12,22 @@ contract Events {
|
|||
address indexed targetDsa,
|
||||
address[] supplyTokens,
|
||||
address[] borrowTokens,
|
||||
uint[] supplyAmts,
|
||||
uint[] variableBorrowAmts,
|
||||
uint[] stableBorrowAmts
|
||||
uint256[] supplyAmts,
|
||||
uint256[] variableBorrowAmts,
|
||||
uint256[] stableBorrowAmts
|
||||
);
|
||||
|
||||
event LogAddTokensSupport(address[] _tokens);
|
||||
event LogUpdateVariables(
|
||||
uint256 oldFee,
|
||||
uint256 newFee,
|
||||
uint256 oldSafeRatioGap,
|
||||
uint256 newSafeRatioGap
|
||||
);
|
||||
|
||||
event LogAddSupportedTokens(
|
||||
address[] tokens
|
||||
);
|
||||
|
||||
event LogVariablesUpdate(uint _safeRatioGap, uint _fee);
|
||||
|
||||
}
|
|
@ -19,9 +19,11 @@ import {
|
|||
} from "./interfaces.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Stores, Variables {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
function _paybackBehalfOne(AaveInterface aave, address token, uint amt, uint rateMode, address user) private {
|
||||
aave.repay(token, amt, rateMode, user);
|
||||
address _token = token == ethAddr ? wethAddr : token;
|
||||
aave.repay(_token, amt, rateMode, user);
|
||||
}
|
||||
|
||||
function _PaybackStable(
|
||||
|
@ -52,8 +54,21 @@ abstract contract Helpers is DSMath, Stores, Variables {
|
|||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
function _PaybackCalculate(
|
||||
AaveInterface aave,
|
||||
AaveDataRaw memory _data,
|
||||
address sourceDsa
|
||||
) internal returns (
|
||||
uint[] memory stableBorrow,
|
||||
uint[] memory variableBorrow,
|
||||
uint[] memory totalBorrow
|
||||
) {
|
||||
uint _len = _data.borrowTokens.length;
|
||||
stableBorrow = new uint256[](_len);
|
||||
variableBorrow = new uint256[](_len);
|
||||
totalBorrow = new uint256[](_len);
|
||||
|
||||
for (uint i = 0; i < _len; i++) {
|
||||
require(isSupportedToken[_data.borrowTokens[i]], "token-not-enabled");
|
||||
address _token = _data.borrowTokens[i] == ethAddr ? wethAddr : _data.borrowTokens[i];
|
||||
_data.borrowTokens[i] = _token;
|
||||
|
@ -65,21 +80,31 @@ abstract contract Helpers is DSMath, Stores, Variables {
|
|||
,,,,,
|
||||
) = 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?
|
||||
IERC20(_token).safeApprove(address(aave), totalBorrow[i]);
|
||||
}
|
||||
aave.borrow(_token, totalBorrow[i], 2, 3088, address(this)); // TODO: Borrowing debt to payback
|
||||
aave.borrow(_token, totalBorrow[i], 2, 3288, address(this));
|
||||
}
|
||||
}
|
||||
|
||||
function _getAtokens(address dsa, AaveInterface aave, address[] memory supplyTokens, uint[] memory supplyAmts) internal returns (uint[] memory finalAmts) {
|
||||
function _getAtokens(
|
||||
address dsa,
|
||||
address[] memory supplyTokens,
|
||||
uint[] memory supplyAmts
|
||||
) internal returns (
|
||||
uint[] memory finalAmts
|
||||
) {
|
||||
finalAmts = new uint256[](supplyTokens.length);
|
||||
for (uint i = 0; i < supplyTokens.length; i++) {
|
||||
require(isSupportedToken[supplyTokens[i]], "token-not-enabled");
|
||||
(address _aToken, ,) = aaveData.getReserveTokensAddresses(supplyTokens[i]);
|
||||
address _token = supplyTokens[i] == ethAddr ? wethAddr : supplyTokens[i];
|
||||
(address _aToken, ,) = aaveData.getReserveTokensAddresses(_token);
|
||||
ATokenInterface aTokenContract = ATokenInterface(_aToken);
|
||||
uint _finalAmt;
|
||||
if (supplyAmts[i] == uint(-1)) {
|
||||
|
@ -87,8 +112,7 @@ abstract contract Helpers is DSMath, Stores, Variables {
|
|||
} else {
|
||||
_finalAmt = supplyAmts[i];
|
||||
}
|
||||
|
||||
aTokenContract.transferFrom(dsa, address(this), finalAmts[i]);
|
||||
require(aTokenContract.transferFrom(dsa, address(this), _finalAmt), "_getAtokens: atokens transfer failed");
|
||||
|
||||
_finalAmt = wmul(_finalAmt, fee);
|
||||
finalAmts[i] = _finalAmt;
|
||||
|
@ -96,10 +120,9 @@ abstract contract Helpers is DSMath, Stores, Variables {
|
|||
}
|
||||
}
|
||||
|
||||
function isPositionSafe() internal returns (bool isOk) {
|
||||
function isPositionSafe() internal view 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");
|
||||
|
@ -111,20 +134,22 @@ abstract contract Helpers is DSMath, Stores, Variables {
|
|||
|
||||
// Liquidation threshold
|
||||
function getTokenLt(address[] memory tokens) internal view returns (uint[] memory decimals, uint[] memory tokenLts) {
|
||||
for (uint i = 0; i < tokens.length; i++) {
|
||||
uint _len = tokens.length;
|
||||
decimals = new uint[](_len);
|
||||
tokenLts = new uint[](_len);
|
||||
for (uint i = 0; i < _len; 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
|
||||
function convertTo18(uint amount, uint decimal) internal pure returns (uint) {
|
||||
return amount * (10 ** (18 - decimal));
|
||||
}
|
||||
|
||||
// TODO: need to verify this throughly
|
||||
/*
|
||||
* Checks the position to migrate should have a safe gap from liquidation
|
||||
*/
|
||||
function _checkRatio(AaveData memory data) public {
|
||||
function _checkRatio(AaveData memory data) public view {
|
||||
uint[] memory supplyTokenPrices = getTokensPrices(data.supplyTokens);
|
||||
(uint[] memory supplyDecimals, uint[] memory supplyLts) = getTokenLt(data.supplyTokens);
|
||||
|
||||
|
|
|
@ -72,6 +72,13 @@ interface ATokenInterface {
|
|||
function approve(address, uint256) external;
|
||||
}
|
||||
|
||||
interface AaveOracleInterface {
|
||||
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(address);
|
||||
function getFallbackOracle() external view returns(address);
|
||||
}
|
||||
|
||||
interface StateSenderInterface {
|
||||
function syncState(address receiver, bytes calldata data) external;
|
||||
function register(address sender, address receiver) external;
|
||||
|
@ -95,4 +102,8 @@ interface AavePriceOracle {
|
|||
interface ChainLinkInterface {
|
||||
function latestAnswer() external view returns (int256);
|
||||
function decimals() external view returns (uint256);
|
||||
}
|
||||
}
|
||||
|
||||
interface RootChainManagerInterface {
|
||||
function depositFor(address user, address token, bytes calldata depositData) external;
|
||||
}
|
||||
|
|
|
@ -11,22 +11,25 @@ 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);
|
||||
emit LogVariablesUpdate(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;
|
||||
for (uint i = 0; i < supportedTokens.length; i++) {
|
||||
delete isSupportedToken[supportedTokens[i]];
|
||||
}
|
||||
supportedTokens = _tokens;
|
||||
emit LogAddTokensSupport(_tokens);
|
||||
delete supportedTokens;
|
||||
for (uint i = 0; i < _tokens.length; i++) {
|
||||
require(!isSupportedToken[_tokens[i]], "already-added");
|
||||
isSupportedToken[_tokens[i]] = true;
|
||||
supportedTokens.push(_tokens[i]);
|
||||
}
|
||||
emit LogAddSupportedTokens(_tokens);
|
||||
}
|
||||
|
||||
function spell(address _target, bytes memory _data) external {
|
||||
|
@ -45,86 +48,6 @@ contract LiquidityResolver is Helpers, Events {
|
|||
}
|
||||
}
|
||||
|
||||
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: _amt}();
|
||||
TokenInterface(wethAddr).approve(address(aave), _amt);
|
||||
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);
|
||||
tokenContract.approve(address(aave), _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
|
||||
|
@ -134,8 +57,7 @@ contract LiquidityResolver is Helpers, Events {
|
|||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
for (uint i = 0; i < supportedTokens.length; i++) {
|
||||
address _token = supportedTokens[i];
|
||||
if (_token == ethAddr) {
|
||||
_token = wethAddr;
|
||||
if (_token == wethAddr) {
|
||||
if (address(this).balance > 0) {
|
||||
TokenInterface(wethAddr).deposit{value: address(this).balance}();
|
||||
}
|
||||
|
@ -143,7 +65,7 @@ contract LiquidityResolver is Helpers, Events {
|
|||
IERC20 _tokenContract = IERC20(_token);
|
||||
uint _tokenBal = _tokenContract.balanceOf(address(this));
|
||||
if (_tokenBal > 0) {
|
||||
_tokenContract.approve(address(this), _tokenBal);
|
||||
_tokenContract.safeApprove(address(aave), _tokenBal);
|
||||
aave.deposit(_token, _tokenBal, address(this), 3288);
|
||||
}
|
||||
(
|
||||
|
@ -154,22 +76,25 @@ contract LiquidityResolver is Helpers, Events {
|
|||
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);
|
||||
IERC20(_token).safeApprove(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);
|
||||
IERC20(_token).safeApprove(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"
|
||||
address _token = _tokens[i] == ethAddr ? wethAddr : _tokens[i];
|
||||
aave.withdraw(_token, _amts[i], address(this));
|
||||
IERC20(_token).safeApprove(erc20Predicate, _amts[i]);
|
||||
rootChainManager.depositFor(polygonReceiver, _token, abi.encode(_amts[i]));
|
||||
|
||||
isPositionSafe();
|
||||
}
|
||||
emit LogSettle(_tokens, _amts);
|
||||
}
|
||||
// TODO: emit event
|
||||
}
|
||||
|
||||
contract MigrateResolver is LiquidityResolver {
|
||||
|
@ -178,8 +103,7 @@ contract MigrateResolver is LiquidityResolver {
|
|||
function _migrate(
|
||||
AaveInterface aave,
|
||||
AaveDataRaw memory _data,
|
||||
address sourceDsa,
|
||||
uint ethAmt
|
||||
address sourceDsa
|
||||
) internal {
|
||||
require(_data.supplyTokens.length > 0, "0-length-not-allowed");
|
||||
require(_data.targetDsa != address(0), "invalid-address");
|
||||
|
@ -190,22 +114,36 @@ contract MigrateResolver is LiquidityResolver {
|
|||
"invalid-length"
|
||||
);
|
||||
|
||||
if (ethAmt > 0) {
|
||||
aave.deposit(wethAddr, ethAmt, address(this), 3288);
|
||||
for (uint i = 0; i < _data.supplyTokens.length; i++) {
|
||||
address _token = _data.supplyTokens[i];
|
||||
for (uint j = 0; j < _data.supplyTokens.length; j++) {
|
||||
if (j != i) {
|
||||
require(j != i, "token-repeated");
|
||||
}
|
||||
}
|
||||
require(_token != ethAddr, "should-be-eth-address");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _data.borrowTokens.length; i++) {
|
||||
address _token = _data.borrowTokens[i];
|
||||
for (uint j = 0; j < _data.borrowTokens.length; j++) {
|
||||
if (j != i) {
|
||||
require(j != i, "token-repeated");
|
||||
}
|
||||
}
|
||||
require(_token != ethAddr, "should-be-eth-address");
|
||||
}
|
||||
|
||||
(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);
|
||||
(uint[] memory totalSupplies) = _getAtokens(sourceDsa, _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;
|
||||
|
@ -214,10 +152,6 @@ contract MigrateResolver is LiquidityResolver {
|
|||
// 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));
|
||||
|
@ -232,26 +166,29 @@ contract MigrateResolver is LiquidityResolver {
|
|||
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
|
||||
require(msg.sender == address(flashloanContract), "not-flashloan-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);
|
||||
aave.deposit(wethAddr, ethAmt, address(this), 3288);
|
||||
_migrate(aave, _data, dsa);
|
||||
aave.withdraw(wethAddr, ethAmt, address(this));
|
||||
require(wethContract.transfer(address(flashloanContract), ethAmt), "migrateFlashCallback: weth transfer failed to Instapool");
|
||||
}
|
||||
}
|
||||
|
||||
contract InstaAaveV2MigratorSenderImplementation is MigrateResolver {
|
||||
function migrate(AaveDataRaw calldata _data) external {
|
||||
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
|
||||
_migrate(aave, _data, msg.sender);
|
||||
}
|
||||
|
||||
function migrateWithFlash(AaveDataRaw calldata _data, uint ethAmt) external {
|
||||
bytes memory data = abi.encode(_data, msg.sender, ethAmt);
|
||||
bytes memory callbackData = abi.encodeWithSelector(bytes4(this.migrateFlashCallback.selector), _data, msg.sender, ethAmt);
|
||||
bytes memory data = abi.encode(callbackData, ethAmt);
|
||||
|
||||
flashloanContract.initiateFlashLoan(data, ethAmt);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,13 +3,16 @@ pragma solidity ^0.7.0;
|
|||
import {
|
||||
AaveLendingPoolProviderInterface,
|
||||
AaveDataProviderInterface,
|
||||
AaveOracleInterface,
|
||||
StateSenderInterface,
|
||||
IndexInterface,
|
||||
FlashloanInterface
|
||||
FlashloanInterface,
|
||||
RootChainManagerInterface
|
||||
} from "./interfaces.sol";
|
||||
|
||||
contract Variables {
|
||||
|
||||
// Structs
|
||||
struct AaveDataRaw {
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
|
@ -27,26 +30,27 @@ contract Variables {
|
|||
address[] borrowTokens;
|
||||
}
|
||||
|
||||
struct TokenPrice {
|
||||
uint priceInEth;
|
||||
uint priceInUsd;
|
||||
}
|
||||
// Constant Addresses //
|
||||
|
||||
/**
|
||||
* @dev Aave referal code
|
||||
*/
|
||||
* @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 Polygon Receiver contract
|
||||
*/
|
||||
address constant internal polygonReceiver = 0x4A090897f47993C2504144419751D6A91D79AbF4;
|
||||
|
||||
/**
|
||||
* @dev Flashloan contract
|
||||
*/
|
||||
FlashloanInterface constant internal flashloanContract = FlashloanInterface(0xd7e8E6f5deCc5642B77a5dD0e445965B128a585D);
|
||||
|
||||
/**
|
||||
* @dev ERC20 Predicate address
|
||||
*/
|
||||
address constant internal erc20Predicate = 0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf;
|
||||
|
||||
/**
|
||||
* @dev Aave Provider
|
||||
|
@ -58,14 +62,47 @@ contract Variables {
|
|||
*/
|
||||
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d);
|
||||
|
||||
/**
|
||||
* @dev Aave Price Oracle
|
||||
*/
|
||||
AaveOracleInterface constant internal aaveOracle = AaveOracleInterface(0xA50ba011c48153De246E5192C8f9258A2ba79Ca9);
|
||||
|
||||
/**
|
||||
* @dev Polygon State Sync Contract
|
||||
*/
|
||||
StateSenderInterface constant internal stateSender = StateSenderInterface(0x28e4F3a7f651294B9564800b2D01f35189A5bFbE);
|
||||
|
||||
mapping(address => mapping(address => uint)) public deposits;
|
||||
|
||||
// InstaIndex Address.
|
||||
/**
|
||||
* @dev InstaIndex Address.
|
||||
*/
|
||||
IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723);
|
||||
|
||||
/**
|
||||
* @dev Polygon deposit bridge
|
||||
*/
|
||||
RootChainManagerInterface public constant rootChainManager = RootChainManagerInterface(0xA0c68C638235ee32657e8f720a23ceC1bFc77C77);
|
||||
|
||||
|
||||
// Storage variables //
|
||||
|
||||
/**
|
||||
* @dev This will be used to have debt/collateral ratio always 20% less than liquidation
|
||||
*/
|
||||
uint public safeRatioGap = 800000000000000000; // 80%
|
||||
|
||||
/**
|
||||
* @dev fee on collateral
|
||||
*/
|
||||
uint public fee = 998000000000000000; // 0.2% (99.8%) on collateral
|
||||
|
||||
/**
|
||||
* @dev Mapping of supported token
|
||||
*/
|
||||
mapping(address => bool) public isSupportedToken;
|
||||
|
||||
/**
|
||||
* @dev Array of supported token
|
||||
*/
|
||||
address[] public supportedTokens; // don't add ethAddr. Only add wethAddr
|
||||
|
||||
}
|
|
@ -13,19 +13,27 @@ const { utils } = require("ethers");
|
|||
|
||||
const ALCHEMY_ID = process.env.ALCHEMY_ID;
|
||||
const PRIVATE_KEY = process.env.PRIVATE_KEY;
|
||||
const QUIKNODE_ID = process.env.QUIKNODE_ID;
|
||||
// ================================= CONFIG =========================================
|
||||
module.exports = {
|
||||
defaultNetwork: "hardhat",
|
||||
// defaultNetwork: "hardhat",
|
||||
tenderly: {
|
||||
project: "team-development",
|
||||
username: "InstaDApp",
|
||||
forkNetwork: "1"
|
||||
},
|
||||
networks: {
|
||||
hardhat: {
|
||||
// hardhat: { // mainnet forking
|
||||
// forking: {
|
||||
// url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
// blockNumber: 12240294,
|
||||
// },
|
||||
// blockGasLimit: 12000000,
|
||||
// },
|
||||
hardhat: { // matic forking
|
||||
forking: {
|
||||
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
blockNumber: 12068005,
|
||||
url: `https://cold-red-river.matic.quiknode.pro/${QUIKNODE_ID}/`,
|
||||
blockNumber: 13350783,
|
||||
},
|
||||
blockGasLimit: 12000000,
|
||||
},
|
||||
|
@ -37,7 +45,7 @@ module.exports = {
|
|||
url: `https://eth.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
accounts: [`0x${PRIVATE_KEY}`],
|
||||
timeout: 150000,
|
||||
gasPrice: parseInt(utils.parseUnits("93", "gwei"))
|
||||
gasPrice: parseInt(utils.parseUnits("131", "gwei"))
|
||||
},
|
||||
matic: {
|
||||
url: "https://rpc-mainnet.maticvigil.com/",
|
||||
|
@ -67,7 +75,9 @@ module.exports = {
|
|||
},
|
||||
etherscan: {
|
||||
apiKey: process.env.ETHERSCAN
|
||||
},
|
||||
mocha: {
|
||||
timeout: 50000
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
1181
package-lock.json
generated
1181
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -24,6 +24,8 @@
|
|||
"solc": "0.7.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^3.4.0-solc-0.7"
|
||||
"@nomiclabs/hardhat-etherscan": "^2.1.1",
|
||||
"@openzeppelin/contracts": "^3.4.0-solc-0.7",
|
||||
"dotenv": "^8.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,25 @@ async function main() {
|
|||
const instaAaveV2MigratorSender = await InstaAaveV2MigratorSender.deploy(instaEmptyImpl.address, instaMasterProxy.address, "0x");
|
||||
await instaAaveV2MigratorSender.deployed();
|
||||
|
||||
console.log("InstaAaveV2MigratorSender deployed: ", instaAaveV2MigratorSender.address);
|
||||
|
||||
const InstaPool = await ethers.getContractFactory("InstaPool");
|
||||
const instaPool = await InstaPool.deploy();
|
||||
await instaPool.deployed();
|
||||
|
||||
console.log("InstaPool deployed: ", instaPool.address);
|
||||
|
||||
|
||||
const InstaAaveV2MigratorSenderImplementation = await ethers.getContractFactory("InstaAaveV2MigratorSenderImplementation");
|
||||
const instaAaveV2MigratorSenderImplementation = await InstaAaveV2MigratorSenderImplementation.deploy();
|
||||
await instaAaveV2MigratorSenderImplementation.deployed();
|
||||
|
||||
console.log("InstaAaveV2MigratorSenderImplementation deployed: ", instaAaveV2MigratorSenderImplementation.address);
|
||||
|
||||
const InstaAaveV2MigratorSender = await ethers.getContractFactory("InstaAaveV2MigratorSender");
|
||||
const instaAaveV2MigratorSender = await InstaAaveV2MigratorSender.deploy(instaEmptyImpl.address, instaMasterProxy.address, "0x");
|
||||
await instaAaveV2MigratorSender.deployed();
|
||||
|
||||
console.log("InstaAaveV2MigratorSender deployed: ", instaAaveV2MigratorSender.address);
|
||||
|
||||
await hre.run("verify:verify", {
|
||||
|
@ -47,13 +66,25 @@ async function main() {
|
|||
contract: "contracts/proxy/senders.sol:InstaAaveV2MigratorSender"
|
||||
}
|
||||
)
|
||||
|
||||
await hre.run("verify:verify", {
|
||||
address: instaPool.address,
|
||||
constructorArguments: []
|
||||
}
|
||||
)
|
||||
|
||||
await hre.run("verify:verify", {
|
||||
address: instaAaveV2MigratorSenderImplementation.address,
|
||||
constructorArguments: []
|
||||
}
|
||||
)
|
||||
|
||||
} else if (hre.network.name === "matic") {
|
||||
console.log(
|
||||
"\n\n Deploying Contracts to matic..."
|
||||
);
|
||||
instaIndex = "0xA9B99766E6C676Cf1975c0D3166F96C0848fF5ad"
|
||||
|
||||
|
||||
const InstaEmptyImpl = await ethers.getContractFactory("InstaEmptyImpl");
|
||||
const instaEmptyImpl = await InstaEmptyImpl.deploy();
|
||||
await instaEmptyImpl.deployed();
|
||||
|
@ -72,6 +103,31 @@ async function main() {
|
|||
await instaAaveV2MigratorReceiver.deployed();
|
||||
|
||||
console.log("InstaAaveV2MigratorReceiver deployed: ", instaAaveV2MigratorReceiver.address);
|
||||
|
||||
const tokenMaps = {
|
||||
// polygon address : main net address
|
||||
// '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', //TODO
|
||||
'0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619': '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
|
||||
'0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063': '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
|
||||
'0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
|
||||
'0xc2132D05D31c914a87C6611C10748AEb04B58e8F': '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
|
||||
'0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270': '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', // MATIC
|
||||
'0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6': '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', // WBTC
|
||||
// '0xD6DF932A45C0f255f85145f286eA0b292B21C90B': '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9' // AAVE
|
||||
}
|
||||
|
||||
const InstaPolygonTokenMapping = await ethers.getContractFactory("InstaPolygonTokenMapping");
|
||||
const instaPolygonTokenMapping = await InstaPolygonTokenMapping.deploy(Object.values(tokenMaps), Object.keys(tokenMaps));
|
||||
await instaPolygonTokenMapping.deployed();
|
||||
|
||||
console.log("InstaPolygonTokenMapping deployed: ", instaPolygonTokenMappings.address);
|
||||
|
||||
const InstaAaveV2MigratorReceiverImplementation = await ethers.getContractFactory("InstaAaveV2MigratorReceiverImplementation");
|
||||
const instaAaveV2MigratorReceiverImplementation = await InstaAaveV2MigratorReceiverImplementation.deploy();
|
||||
await instaAaveV2MigratorReceiverImplementation.deployed();
|
||||
|
||||
console.log("InstaAaveV2MigratorReceiverImplementation deployed: ", instaAaveV2MigratorReceiverImplementation.address);
|
||||
|
||||
console.log("Contracts deployed")
|
||||
}
|
||||
}
|
||||
|
|
267
test/migrator_l1.test.js
Normal file
267
test/migrator_l1.test.js
Normal file
|
@ -0,0 +1,267 @@
|
|||
const hre = require("hardhat");
|
||||
const { expect } = require("chai");
|
||||
const { ethers, network, waffle } = hre;
|
||||
const { provider, deployContract } = waffle
|
||||
|
||||
const Migrator = require("../artifacts/contracts/senders/aave-v2-migrator/main.sol/MigrateResolver.json")
|
||||
const InstaPool = require("../artifacts/contracts/liquidity.sol/InstaPool.json")
|
||||
|
||||
describe("Migrator", function() {
|
||||
let accounts, masterAddress, master, migrator, ethereum, instapool
|
||||
|
||||
const erc20Abi = [
|
||||
"function balanceOf(address) view returns (uint)",
|
||||
"function transfer(address to, uint amount)",
|
||||
"function approve(address spender, uint amount)"
|
||||
]
|
||||
|
||||
const syncStateAbi = [
|
||||
"function register(address sender, address receiver)"
|
||||
]
|
||||
|
||||
const usdc = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
||||
const usdt = '0xdac17f958d2ee523a2206206994597c13d831ec7'
|
||||
const dai = '0x6b175474e89094c44da98b954eedeac495271d0f'
|
||||
const wbtc = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599'
|
||||
const aave = '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9'
|
||||
const eth = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'
|
||||
const weth = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
|
||||
|
||||
const aweth = '0x030ba81f1c18d280636f32af80b9aad02cf0854e'
|
||||
const aaave = '0xFFC97d72E13E01096502Cb8Eb52dEe56f74DAD7B'
|
||||
const awbtc = '0x9ff58f4ffb29fa2266ab25e75e2a8b3503311656'
|
||||
|
||||
const maxValue = '115792089237316195423570985008687907853269984665640564039457584007913129639935'
|
||||
|
||||
const supportedTokens = [usdc, usdt, dai, wbtc, aave, weth]
|
||||
|
||||
before(async function() {
|
||||
masterAddress = "0xb1DC62EC38E6E3857a887210C38418E4A17Da5B2"
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ masterAddress ]
|
||||
})
|
||||
|
||||
accounts = await ethers.getSigners();
|
||||
master = ethers.provider.getSigner(masterAddress)
|
||||
|
||||
migrator = await deployContract(master, Migrator, [])
|
||||
instapool = await deployContract(master, InstaPool, [])
|
||||
|
||||
console.log("Migrator deployed: ", migrator.address)
|
||||
console.log("Instapool deployed: ", instapool.address)
|
||||
|
||||
const syncStateOwnerAddr = '0xFa7D2a996aC6350f4b56C043112Da0366a59b74c'
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ syncStateOwnerAddr ]
|
||||
})
|
||||
const syncStateOwner = ethers.provider.getSigner(syncStateOwnerAddr)
|
||||
const syncStateContract = new ethers.Contract('0x28e4F3a7f651294B9564800b2D01f35189A5bFbE', syncStateAbi, syncStateOwner)
|
||||
await accounts[0].sendTransaction({ to: syncStateOwnerAddr, value: ethers.utils.parseEther('1') })
|
||||
await syncStateContract.register(migrator.address, '0xA35f3FEFEcb5160327d1B6A210b60D1e1d7968e3')
|
||||
// await syncStateContract.register(instapool.address, '0xA35f3FEFEcb5160327d1B6A210b60D1e1d7968e3')
|
||||
|
||||
const usdcHolderAddr = '0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503' // 1,000,000
|
||||
await accounts[0].sendTransaction({ to: usdcHolderAddr, value: ethers.utils.parseEther('1') })
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ usdcHolderAddr ]
|
||||
})
|
||||
const usdcHolder = ethers.provider.getSigner(usdcHolderAddr)
|
||||
const usdcContract = new ethers.Contract(usdc, erc20Abi, usdcHolder)
|
||||
await usdcContract.transfer(migrator.address, ethers.utils.parseUnits('1000000', 6))
|
||||
|
||||
const usdtHolderAddr = '0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503' // 1,000,000
|
||||
await accounts[0].sendTransaction({ to: usdtHolderAddr, value: ethers.utils.parseEther('1') })
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ usdtHolderAddr ]
|
||||
})
|
||||
const usdtHolder = ethers.provider.getSigner(usdtHolderAddr)
|
||||
const usdtContract = new ethers.Contract(usdt, erc20Abi, usdtHolder)
|
||||
await usdtContract.transfer(migrator.address, ethers.utils.parseUnits('1000000', 6))
|
||||
|
||||
const daiHolderAddr = '0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503' // 1,000,000
|
||||
await accounts[0].sendTransaction({ to: daiHolderAddr, value: ethers.utils.parseEther('1') })
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ daiHolderAddr ]
|
||||
})
|
||||
const daiHolder = ethers.provider.getSigner(daiHolderAddr)
|
||||
const daiContract = new ethers.Contract(dai, erc20Abi, daiHolder)
|
||||
await daiContract.transfer(migrator.address, ethers.utils.parseUnits('1000000', 18))
|
||||
|
||||
const wbtcHolderAddr = '0xf977814e90da44bfa03b6295a0616a897441acec' // 16
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ wbtcHolderAddr ]
|
||||
})
|
||||
const wbtcHolder = ethers.provider.getSigner(wbtcHolderAddr)
|
||||
const wbtcContract = new ethers.Contract(wbtc, erc20Abi, wbtcHolder)
|
||||
await wbtcContract.transfer(migrator.address, ethers.utils.parseUnits('16', 8))
|
||||
|
||||
const wethHolderAddr = '0x0f4ee9631f4be0a63756515141281a3e2b293bbe' // 500
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ wethHolderAddr ]
|
||||
})
|
||||
const wethHolder = ethers.provider.getSigner(wethHolderAddr)
|
||||
const wethContract = new ethers.Contract(weth, erc20Abi, wethHolder)
|
||||
await wethContract.transfer(migrator.address, ethers.utils.parseUnits('500', 18))
|
||||
await wethContract.transfer(instapool.address, ethers.utils.parseUnits('10', 18))
|
||||
|
||||
ethereum = network.provider
|
||||
})
|
||||
|
||||
it("should set tokens", async function() {
|
||||
const tx = await migrator.connect(master).addTokenSupport(supportedTokens)
|
||||
const receipt = await tx.wait()
|
||||
|
||||
const isUsdc = await migrator.isSupportedToken(usdc)
|
||||
expect(isUsdc).to.be.true;
|
||||
})
|
||||
|
||||
it("test migrate", async function() {
|
||||
|
||||
const sourceAddr = '0x05A14F14E7a435542468D6F4d408D6F67303D769'
|
||||
await master.sendTransaction({
|
||||
to: sourceAddr,
|
||||
value: ethers.utils.parseEther("1")
|
||||
});
|
||||
const rawData = {
|
||||
targetDsa: "0x150Acc42e6751776c9E784EfF830cB4f35aE98f3",
|
||||
supplyTokens: [weth],
|
||||
borrowTokens: [usdt],
|
||||
supplyAmts: [ethers.utils.parseEther('60')],
|
||||
variableBorrowAmts: [ethers.utils.parseUnits('10000', 6)],
|
||||
stableBorrowAmts: [0]
|
||||
}
|
||||
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ sourceAddr ]
|
||||
})
|
||||
const signer = ethers.provider.getSigner(sourceAddr)
|
||||
|
||||
const awethContract = new ethers.Contract(aweth, erc20Abi, signer)
|
||||
await awethContract.approve(migrator.address, maxValue)
|
||||
|
||||
const tx = await migrator.connect(signer).migrateWithFlash(rawData, ethers.utils.parseEther('80'))
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
|
||||
it("test settle", async function() {
|
||||
const tokens = [weth]
|
||||
const amts = [ethers.utils.parseEther('60')]
|
||||
|
||||
const tx = await migrator.settle(tokens, amts)
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
|
||||
it("test settle 2", async function() {
|
||||
const tokens = [usdc]
|
||||
const amts = [ethers.utils.parseUnits('20000', 6)]
|
||||
|
||||
const tx = await migrator.settle(tokens, amts)
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
|
||||
it("test migrate 2", async function() {
|
||||
const sourceAddr = '0x6126f2a1bd956630f810d5ea351c5a4d65cb5033'
|
||||
|
||||
const rawData = {
|
||||
targetDsa: '0x150Acc42e6751776c9E784EfF830cB4f35aE98f3',
|
||||
supplyTokens: [weth],
|
||||
borrowTokens: [usdc, usdt, dai],
|
||||
supplyAmts: [ethers.utils.parseEther('100')],
|
||||
variableBorrowAmts: [0, 0, ethers.utils.parseUnits('20000', 18)],
|
||||
stableBorrowAmts: [ethers.utils.parseUnits('20000', 6), ethers.utils.parseUnits('20000', 6), ethers.utils.parseUnits('20000', 18)]
|
||||
}
|
||||
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ sourceAddr ]
|
||||
})
|
||||
const signer = ethers.provider.getSigner(sourceAddr)
|
||||
|
||||
const awethContract = new ethers.Contract(aweth, erc20Abi, signer)
|
||||
await awethContract.approve(migrator.address, maxValue)
|
||||
const aaaveContract = new ethers.Contract(aaave, erc20Abi, signer)
|
||||
await aaaveContract.approve(migrator.address, maxValue)
|
||||
|
||||
const tx = await migrator.connect(signer).migrateWithFlash(rawData, ethers.utils.parseEther('150'))
|
||||
const receipt = await tx.wait()
|
||||
})
|
||||
|
||||
it("test migrate 3", async function() {
|
||||
const sourceAddr = '0x37e5df37885a6d0b43bee9ec2997b1e0037fb490'
|
||||
|
||||
const rawData = {
|
||||
targetDsa: '0x32d99500f7621C6Dc5391395D419236383Dbff97',
|
||||
supplyTokens: [weth],
|
||||
borrowTokens: [usdc, usdt],
|
||||
supplyAmts: [ethers.utils.parseEther('1000')],
|
||||
variableBorrowAmts: [ethers.utils.parseUnits('20000', 6), ethers.utils.parseUnits('40000', 6)],
|
||||
stableBorrowAmts: [ethers.utils.parseUnits('40000', 6), 0]
|
||||
}
|
||||
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ sourceAddr ]
|
||||
})
|
||||
const signer = ethers.provider.getSigner(sourceAddr)
|
||||
|
||||
const awethContract = new ethers.Contract(aweth, erc20Abi, signer)
|
||||
await awethContract.approve(migrator.address, maxValue)
|
||||
|
||||
const tx = await migrator.connect(signer).migrateWithFlash(rawData, ethers.utils.parseEther('1200'))
|
||||
const receipt = await tx.wait()
|
||||
})
|
||||
|
||||
it("test migrate 4", async function() {
|
||||
const sourceAddr = '0xeb43b5597e3bde0b0c03ee6731ba7c0247e1581e'
|
||||
|
||||
const rawData = {
|
||||
targetDsa: '0x29601161ad5DA8c54435F4065af3A0EE30Cb24dD',
|
||||
supplyTokens: [weth, wbtc],
|
||||
borrowTokens: [usdc],
|
||||
supplyAmts: [ethers.utils.parseEther('4000'), ethers.utils.parseUnits('30', 8)],
|
||||
variableBorrowAmts: [ethers.utils.parseUnits('1000000', 6)],
|
||||
stableBorrowAmts: [ethers.utils.parseUnits('5000000', 6)]
|
||||
}
|
||||
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ sourceAddr ]
|
||||
})
|
||||
const signer = ethers.provider.getSigner(sourceAddr)
|
||||
|
||||
const awethContract = new ethers.Contract(aweth, erc20Abi, signer)
|
||||
await awethContract.approve(migrator.address, maxValue)
|
||||
const awbtcContract = new ethers.Contract(awbtc, erc20Abi, signer)
|
||||
await awbtcContract.approve(migrator.address, maxValue)
|
||||
|
||||
const tx = await migrator.connect(signer).migrateWithFlash(rawData, ethers.utils.parseEther('4000'))
|
||||
const receipt = await tx.wait()
|
||||
})
|
||||
|
||||
it("test settle 3", async function() {
|
||||
const tokens = [weth, wbtc]
|
||||
const amts = [
|
||||
ethers.utils.parseEther('2000'),
|
||||
ethers.utils.parseUnits('25', 8)
|
||||
]
|
||||
|
||||
const tx = await migrator.settle(tokens, amts)
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
})
|
|
@ -1,14 +0,0 @@
|
|||
const { expect } = require("chai");
|
||||
|
||||
describe("Greeter", function() {
|
||||
it("Should return the new greeting once it's changed", async function() {
|
||||
const Greeter = await ethers.getContractFactory("Greeter");
|
||||
const greeter = await Greeter.deploy("Hello, world!");
|
||||
|
||||
await greeter.deployed();
|
||||
expect(await greeter.greet()).to.equal("Hello, world!");
|
||||
|
||||
await greeter.setGreeting("Hola, mundo!");
|
||||
expect(await greeter.greet()).to.equal("Hola, mundo!");
|
||||
});
|
||||
});
|
267
test/sender_l1.test.js
Normal file
267
test/sender_l1.test.js
Normal file
|
@ -0,0 +1,267 @@
|
|||
const hre = require("hardhat");
|
||||
const { expect } = require("chai");
|
||||
const { ethers, network, waffle } = hre;
|
||||
const { provider, deployContract } = waffle
|
||||
|
||||
const Migrator = require("../artifacts/contracts/receivers/aave-v2-receiver/main.sol/AaveV2Migrator.json")
|
||||
const TokenMappingContract = require("../artifacts/contracts/receivers/mapping/main.sol/InstaPolygonTokenMapping.json")
|
||||
const Implementations_m2Contract = require("../artifacts/contracts/implementation/aave-v2-migrator/main.sol/InstaImplementationM1.json")
|
||||
|
||||
const tokenMaps = {
|
||||
// polygon address : main net address
|
||||
// '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', //TODO
|
||||
'0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619': '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
|
||||
'0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063': '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
|
||||
'0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
|
||||
'0xc2132D05D31c914a87C6611C10748AEb04B58e8F': '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
|
||||
'0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270': '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', // MATIC
|
||||
'0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6': '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', // WBTC
|
||||
// '0xD6DF932A45C0f255f85145f286eA0b292B21C90B': '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9' // AAVE
|
||||
}
|
||||
|
||||
//
|
||||
describe("Migrator", function() {
|
||||
let accounts, masterAddress, master, migrator, ethereum, instapool, tokenMapping, implementations_m2Contract
|
||||
|
||||
const erc20Abi = [
|
||||
"function balanceOf(address) view returns (uint)",
|
||||
"function transfer(address to, uint amount)",
|
||||
"function approve(address spender, uint amount)"
|
||||
]
|
||||
|
||||
const instaImplementationABI = [
|
||||
"function addImplementation(address _implementation, bytes4[] calldata _sigs)"
|
||||
]
|
||||
|
||||
const implementations_m2Sigs = ["0x5a19a5eb"]
|
||||
|
||||
const migrateData = "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000150acc42e6751776c9e784eff830cb4f35ae98f300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000033f007ebdfe640000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000002540be4000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7"
|
||||
|
||||
const usdc = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'
|
||||
const usdt = '0xc2132D05D31c914a87C6611C10748AEb04B58e8F'
|
||||
const dai = '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063'
|
||||
const wbtc = '0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6'
|
||||
const aave = '0xD6DF932A45C0f255f85145f286eA0b292B21C90B'
|
||||
const weth = '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619'
|
||||
const wmatic = '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270'
|
||||
|
||||
const instaConnectorsV2 = '0x0a0a82D2F86b9E46AE60E22FCE4e8b916F858Ddc'
|
||||
const instaImplementations = '0x39d3d5e7c11D61E072511485878dd84711c19d4A'
|
||||
|
||||
|
||||
const maxValue = '115792089237316195423570985008687907853269984665640564039457584007913129639935'
|
||||
|
||||
// const supportedTokens = [usdc, usdt, dai, wbtc, aave, eth, weth]
|
||||
|
||||
before(async function() {
|
||||
masterAddress = "0x31de2088f38ed7F8a4231dE03973814edA1f8773"
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ masterAddress ]
|
||||
})
|
||||
|
||||
accounts = await ethers.getSigners();
|
||||
master = ethers.provider.getSigner(masterAddress)
|
||||
|
||||
migrator = await deployContract(master, Migrator, [])
|
||||
|
||||
// instapool = await deployContract(master, InstaPool, [])
|
||||
tokenMapping = await deployContract(master, TokenMappingContract, [Object.values(tokenMaps), Object.keys(tokenMaps)])
|
||||
console.log("Migrator deployed: ", migrator.address)
|
||||
implementations_m2Contract = await deployContract(master, Implementations_m2Contract, [instaConnectorsV2, migrator.address])
|
||||
|
||||
console.log("Migrator deployed: ", migrator.address)
|
||||
console.log("tokenMapping deployed: ", tokenMapping.address)
|
||||
console.log("implementations_m2Contract deployed: ", implementations_m2Contract.address)
|
||||
|
||||
await master.sendTransaction({
|
||||
to: migrator.address,
|
||||
value: ethers.utils.parseEther("45500000")
|
||||
});
|
||||
ethereum = network.provider
|
||||
})
|
||||
|
||||
it("should set implementationsV2", async function() {
|
||||
|
||||
const instaImplementationsContract = new ethers.Contract(instaImplementations, instaImplementationABI, master)
|
||||
await instaImplementationsContract.connect(master).addImplementation(implementations_m2Contract.address, implementations_m2Sigs)
|
||||
})
|
||||
|
||||
it("should set tokens", async function() {
|
||||
const tx = await migrator.connect(master).addTokenSupport([...Object.keys(tokenMaps).slice(1, 3), "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"])
|
||||
const receipt = await tx.wait()
|
||||
|
||||
const isMatic = await migrator.isSupportedToken("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE")
|
||||
expect(isMatic).to.be.true;
|
||||
})
|
||||
|
||||
it("should set data", async function() {
|
||||
const tx = await migrator.onStateReceive("345", migrateData)
|
||||
const receipt = await tx.wait()
|
||||
|
||||
const _migrateData = await migrator.positions("345")
|
||||
// console.log("_migrateData", _migrateData)
|
||||
// console.log("tokenMapping deployed: ", await tokenMapping.getMapping("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"))
|
||||
expect(_migrateData).to.be.eq(migrateData);
|
||||
|
||||
})
|
||||
|
||||
it("test settle", async function() {
|
||||
const tx = await migrator.settle()
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
|
||||
it("test migrate", async function() {
|
||||
|
||||
const tx = await migrator.migrate("345")
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
|
||||
it("fund assets", async function() {
|
||||
const usdcHolderAddr = '0x986a2fCa9eDa0e06fBf7839B89BfC006eE2a23Dd' // 1,000,000
|
||||
await accounts[0].sendTransaction({ to: usdcHolderAddr, value: ethers.utils.parseEther('1') })
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ usdcHolderAddr ]
|
||||
})
|
||||
const usdcHolder = ethers.provider.getSigner(usdcHolderAddr)
|
||||
const usdcContract = new ethers.Contract(usdc, erc20Abi, usdcHolder)
|
||||
await usdcContract.transfer(migrator.address, ethers.utils.parseUnits('1000000', 6))
|
||||
|
||||
const usdtHolderAddr = '0xe67e43b831A541c5Fa40DE52aB0aFbE311514E64' // 500,000
|
||||
await accounts[0].sendTransaction({ to: usdtHolderAddr, value: ethers.utils.parseEther('1') })
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ usdtHolderAddr ]
|
||||
})
|
||||
const usdtHolder = ethers.provider.getSigner(usdtHolderAddr)
|
||||
const usdtContract = new ethers.Contract(usdt, erc20Abi, usdtHolder)
|
||||
await usdtContract.transfer(migrator.address, ethers.utils.parseUnits('500000', 6))
|
||||
|
||||
const daiHolderAddr = '0x7A61A0Ed364E599Ae4748D1EbE74bf236Dd27B09' // 300,000
|
||||
await accounts[0].sendTransaction({ to: daiHolderAddr, value: ethers.utils.parseEther('1') })
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ daiHolderAddr ]
|
||||
})
|
||||
const daiHolder = ethers.provider.getSigner(daiHolderAddr)
|
||||
const daiContract = new ethers.Contract(dai, erc20Abi, daiHolder)
|
||||
await daiContract.transfer(migrator.address, ethers.utils.parseUnits('300000', 18))
|
||||
|
||||
// const wbtcHolderAddr = '0x4572581Fc62D4477B9E11bb65eA8a1c306CbBa3D' // 1
|
||||
// await hre.network.provider.request({
|
||||
// method: "hardhat_impersonateAccount",
|
||||
// params: [ wbtcHolderAddr ]
|
||||
// })
|
||||
// const wbtcHolder = ethers.provider.getSigner(wbtcHolderAddr)
|
||||
// const wbtcContract = new ethers.Contract(wbtc, erc20Abi, wbtcHolder)
|
||||
// await wbtcContract.transfer(migrator.address, ethers.utils.parseUnits('0.5', 8))
|
||||
|
||||
let wethHolderAddr = '0xac1513a6C4C3E74Cb0c1f77c8cBbbf22A2400e33' // 150
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ wethHolderAddr ]
|
||||
})
|
||||
let wethHolder = ethers.provider.getSigner(wethHolderAddr)
|
||||
let wethContract = new ethers.Contract(weth, erc20Abi, wethHolder)
|
||||
await wethContract.transfer(migrator.address, ethers.utils.parseUnits('150', 18))
|
||||
|
||||
wethHolderAddr = '0xBe31a54c78f6E73819ffF78072Be1660485c8105' // 130
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ wethHolderAddr ]
|
||||
})
|
||||
wethHolder = ethers.provider.getSigner(wethHolderAddr)
|
||||
wethContract = new ethers.Contract(weth, erc20Abi, wethHolder)
|
||||
await wethContract.transfer(migrator.address, ethers.utils.parseUnits('130', 18))
|
||||
|
||||
wethHolderAddr = '0x10752de2972390BA3D5A47A26179E526019C01c0' // 100
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ wethHolderAddr ]
|
||||
})
|
||||
wethHolder = ethers.provider.getSigner(wethHolderAddr)
|
||||
wethContract = new ethers.Contract(weth, erc20Abi, wethHolder)
|
||||
await wethContract.transfer(migrator.address, ethers.utils.parseUnits('100', 18))
|
||||
|
||||
wethHolderAddr = '0x0ee5CDBec0665D31ee00EE35b46e85EdcB9CEb31' // 100
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ wethHolderAddr ]
|
||||
})
|
||||
wethHolder = ethers.provider.getSigner(wethHolderAddr)
|
||||
wethContract = new ethers.Contract(weth, erc20Abi, wethHolder)
|
||||
await wethContract.transfer(migrator.address, ethers.utils.parseUnits('100', 18))
|
||||
|
||||
wethHolderAddr = '0xE3f892174190b3F0Fa502Eb84c8208c7c0998c50' // 90
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ wethHolderAddr ]
|
||||
})
|
||||
wethHolder = ethers.provider.getSigner(wethHolderAddr)
|
||||
wethContract = new ethers.Contract(weth, erc20Abi, wethHolder)
|
||||
await wethContract.transfer(migrator.address, ethers.utils.parseUnits('100', 18))
|
||||
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [ wmatic ]
|
||||
})
|
||||
const wmaticSigner = ethers.provider.getSigner(wmatic)
|
||||
await wmaticSigner.sendTransaction({
|
||||
to: migrator.address,
|
||||
value: ethers.utils.parseEther("50000000")
|
||||
});
|
||||
})
|
||||
|
||||
it("test settle 2", async function() {
|
||||
const tx = await migrator.settle()
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
|
||||
it("test migrate 2", async function() {
|
||||
const positionData = '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000150acc42e6751776c9e784eff830cb4f35ae98f300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000056900d33ca7fc0000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000004a817c80000000000000000000000000000000000000000000000000000000004a817c800000000000000000000000000000000000000000000000878678326eac90000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000003000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000006b175474e89094c44da98b954eedeac495271d0f'
|
||||
let tx = await migrator.onStateReceive("346", positionData)
|
||||
await tx.wait()
|
||||
|
||||
tx = await migrator.migrate("346")
|
||||
await tx.wait()
|
||||
})
|
||||
|
||||
it("test settle 3", async function() {
|
||||
const tx = await migrator.settle()
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
|
||||
it("test migrate 3", async function() {
|
||||
const positionData = '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000032d99500f7621c6dc5391395d419236383dbff9700000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000361a08405e8fd8000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000df847580000000000000000000000000000000000000000000000000000000009502f90000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7'
|
||||
let tx = await migrator.onStateReceive("347", positionData)
|
||||
await tx.wait()
|
||||
|
||||
tx = await migrator.migrate("347")
|
||||
await tx.wait()
|
||||
})
|
||||
|
||||
it("test settle 4", async function() {
|
||||
const tx = await migrator.settle()
|
||||
const receipt = await tx.wait()
|
||||
|
||||
// console.log(receipt)
|
||||
})
|
||||
|
||||
it("test migrate 4", async function() {
|
||||
const positionData = '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000029601161ad5da8c54435f4065af3a0ee30cb24dd00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000d86821017a3f60000000000000000000000000000000000000000000000000000000000000b274d080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000574fbde60000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
||||
let tx = await migrator.onStateReceive("348", positionData)
|
||||
await tx.wait()
|
||||
|
||||
tx = await migrator.migrate("348")
|
||||
await tx.wait()
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue
Block a user