Merge branch 'main' of github.com:Instadapp/dsa-connectors

This commit is contained in:
Edward Mulraney 2021-06-25 09:41:09 +01:00
commit 003ef06887
50 changed files with 8074 additions and 3891 deletions

View File

@ -0,0 +1,6 @@
pragma solidity ^0.7.0;
contract Events {
event LogVoteCast(uint256 proposalId, uint256 support, string reason);
event LogDelegate(address delegatee);
}

View File

@ -0,0 +1,18 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { InstaTokenInterface, InstaGovernorInterface } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev InstaGovernorBravo
*/
InstaGovernorInterface internal constant instaGovernor = InstaGovernorInterface(0x0204Cd037B2ec03605CFdFe482D8e257C765fA1B);
/**
* @dev INST Token
*/
InstaTokenInterface internal constant instToken = InstaTokenInterface(0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb);
}

View File

@ -0,0 +1,10 @@
pragma solidity ^0.7.0;
interface InstaGovernorInterface {
function castVoteWithReason(uint proposalId, uint8 support, string calldata reason) external;
}
interface InstaTokenInterface {
function delegate(address delegatee) external;
function delegates(address) external view returns(address);
}

View File

@ -0,0 +1,60 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/**
* @title Instadapp Governance.
* @dev Governance.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { Stores } from "../../common/stores.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract Resolver is Events, Helpers {
/**
* @dev Delegate votes.
* @notice Delegating votes to delegatee.
* @param delegatee The address to delegate the votes.
*/
function delegate(address delegatee) external payable returns (string memory _eventName, bytes memory _eventParam) {
require(instToken.delegates(address(this)) != delegatee, "Already delegated to same delegatee.");
instToken.delegate(delegatee);
_eventName = "LogDelegate(address)";
_eventParam = abi.encode(delegatee);
}
/**
* @dev Cast vote.
* @notice Casting vote for a proposal
* @param proposalId The id of the proposal to vote on
* @param support The support value for the vote. 0=against, 1=for, 2=abstain
*/
function voteCast(uint256 proposalId, uint256 support) external payable returns (string memory _eventName, bytes memory _eventParam) {
instaGovernor.castVoteWithReason(proposalId, uint8(support), "");
_eventName = "LogVoteCast(uint256,uint256,string)";
_eventParam = abi.encode(proposalId, support, "");
}
/**
* @dev Cast vote with reason.
* @notice Casting vote for a proposal
* @param proposalId The id of the proposal to vote on
* @param support The support value for the vote. 0=against, 1=for, 2=abstain
* @param reason The reason given for the vote
*/
function voteCastWithReason(uint256 proposalId, uint256 support, string calldata reason) external payable returns (string memory _eventName, bytes memory _eventParam) {
instaGovernor.castVoteWithReason(proposalId, uint8(support), reason);
_eventName = "LogVoteCast(uint256,uint256,string)";
_eventParam = abi.encode(proposalId, support, reason);
}
}
contract ConnectV2InstadappGovernanceBravo is Resolver {
string public constant name = "Instadapp-governance-bravo-v1";
}

View File

@ -18,7 +18,13 @@ abstract contract AuthorityResolver is Events, Helpers {
function add(
address authority
) external payable returns (string memory _eventName, bytes memory _eventParam) {
AccountInterface(address(this)).enable(authority);
require(authority != address(0), "Not-valid-authority");
AccountInterface _dsa = AccountInterface(address(this));
if (_dsa.isAuth(authority)) {
authority = address(0);
} else {
_dsa.enable(authority);
}
_eventName = "LogAddAuth(address,address)";
_eventParam = abi.encode(msg.sender, authority);
@ -33,7 +39,13 @@ abstract contract AuthorityResolver is Events, Helpers {
address authority
) external payable returns (string memory _eventName, bytes memory _eventParam) {
require(checkAuthCount() > 1, "Removing-all-authorities");
AccountInterface(address(this)).disable(authority);
require(authority != address(0), "Not-valid-authority");
AccountInterface _dsa = AccountInterface(address(this));
if (_dsa.isAuth(authority)) {
_dsa.disable(authority);
} else {
authority = address(0);
}
_eventName = "LogRemoveAuth(address,address)";
_eventParam = abi.encode(msg.sender, authority);
@ -41,5 +53,5 @@ abstract contract AuthorityResolver is Events, Helpers {
}
contract ConnectV2Auth is AuthorityResolver {
string public constant name = "Auth-v1";
string public constant name = "Auth-v1.1";
}

View File

@ -0,0 +1,30 @@
pragma solidity ^0.7.0;
contract Events {
event LogDeposit(
address indexed stakingToken,
bytes32 indexed stakingType,
uint256 amount,
uint getId,
uint setId
);
event LogWithdrawAndClaimedReward(
address indexed stakingToken,
bytes32 indexed stakingType,
uint256 amount,
uint256 rewardAmt,
uint getId,
uint setIdAmount,
uint setIdReward
);
event LogClaimedReward(
address indexed rewardToken,
bytes32 indexed stakingType,
uint256 rewardAmt,
uint setId
);
}

View File

@ -0,0 +1,48 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { TokenInterface } from "../../common/interfaces.sol";
import { IStakingRewards, StakingERC20Mapping } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev Convert String to bytes32.
*/
function stringToBytes32(string memory str) internal pure returns (bytes32 result) {
require(bytes(str).length != 0, "string-empty");
// solium-disable-next-line security/no-inline-assembly
assembly {
result := mload(add(str, 32))
}
}
/**
* @dev Get staking data
*/
function getStakingData(string memory stakingName)
internal
view
returns (
IStakingRewards stakingContract,
TokenInterface stakingToken,
TokenInterface rewardToken,
bytes32 stakingType
)
{
stakingType = stringToBytes32(stakingName);
StakingERC20Mapping.StakingData memory stakingData = StakingERC20Mapping(getMappingAddr()).stakingMapping(stakingType);
require(stakingData.stakingPool != address(0) && stakingData.stakingToken != address(0), "Wrong Staking Name");
stakingContract = IStakingRewards(stakingData.stakingPool);
stakingToken = TokenInterface(stakingData.stakingToken);
rewardToken = TokenInterface(stakingData.rewardToken);
}
function getMappingAddr() internal virtual view returns (address) {
return 0xbE658233bA9990d86155b3902fd05a7AfC7eBdB5; // InstaMapping Address
}
}

View File

@ -0,0 +1,21 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
interface IStakingRewards {
function stake(uint256 amount) external;
function withdraw(uint256 amount) external;
function getReward() external;
function balanceOf(address) external view returns(uint);
}
interface StakingERC20Mapping {
struct StakingData {
address stakingPool;
address stakingToken;
address rewardToken;
}
function stakingMapping(bytes32) external view returns(StakingData memory);
}

View File

@ -0,0 +1,120 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/**
* @title Token Staking.
* @dev Stake ERC20 for earning rewards.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { Stores } from "../../common/stores.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
import { IStakingRewards, StakingERC20Mapping } from "./interface.sol";
contract Main is Helpers, Events {
/**
* @dev Deposit ERC20.
* @notice Deposit Tokens to staking pool.
* @param stakingPoolName staking pool name.
* @param amt staking token amount.
* @param getId ID to retrieve amount.
* @param setId ID stores the amount of staked tokens.
*/
function deposit(
string calldata stakingPoolName,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
(
IStakingRewards stakingContract,
TokenInterface stakingToken,
,
bytes32 stakingType
) = getStakingData(stakingPoolName);
_amt = _amt == uint(-1) ? stakingToken.balanceOf(address(this)) : _amt;
stakingToken.approve(address(stakingContract), _amt);
stakingContract.stake(_amt);
setUint(setId, _amt);
_eventName = "LogDeposit(address,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(address(stakingToken), stakingType, _amt, getId, setId);
}
/**
* @dev Withdraw ERC20.
* @notice Withdraw Tokens from the staking pool.
* @param stakingPoolName staking pool name.
* @param amt staking token amount.
* @param getId ID to retrieve amount.
* @param setIdAmount ID stores the amount of stake tokens withdrawn.
* @param setIdReward ID stores the amount of reward tokens claimed.
*/
function withdraw(
string calldata stakingPoolName,
uint amt,
uint getId,
uint setIdAmount,
uint setIdReward
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
(
IStakingRewards stakingContract,
TokenInterface stakingToken,
TokenInterface rewardToken,
bytes32 stakingType
) = getStakingData(stakingPoolName);
_amt = _amt == uint(-1) ? stakingContract.balanceOf(address(this)) : _amt;
uint intialBal = rewardToken.balanceOf(address(this));
stakingContract.withdraw(_amt);
stakingContract.getReward();
uint rewardAmt = sub(rewardToken.balanceOf(address(this)), intialBal);
setUint(setIdAmount, _amt);
setUint(setIdReward, rewardAmt);
{
_eventName = "LogWithdrawAndClaimedReward(address,bytes32,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(address(stakingToken), stakingType, _amt, rewardAmt, getId, setIdAmount, setIdReward);
}
}
/**
* @dev Claim Reward.
* @notice Claim Pending Rewards of tokens staked.
* @param stakingPoolName staking pool name.
* @param setId ID stores the amount of reward tokens claimed.
*/
function claimReward(
string calldata stakingPoolName,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
(
IStakingRewards stakingContract,
,
TokenInterface rewardToken,
bytes32 stakingType
) = getStakingData(stakingPoolName);
uint intialBal = rewardToken.balanceOf(address(this));
stakingContract.getReward();
uint finalBal = rewardToken.balanceOf(address(this));
uint rewardAmt = sub(finalBal, intialBal);
setUint(setId, rewardAmt);
_eventName = "LogClaimedReward(address,bytes32,uint256,uint256)";
_eventParam = abi.encode(address(rewardToken), stakingType, rewardAmt, setId);
}
}
contract connectV2StakeERC20 is Main {
string public constant name = "Stake-ERC20-v1.0";
}

View File

@ -0,0 +1,34 @@
pragma solidity ^0.7.0;
contract Events {
event LogDepositLiquidity(
address indexed pool,
uint256 amtA,
uint256 amtB,
uint256 mintAmount,
uint256[] getIds,
uint256 setId
);
event LogWithdrawLiquidity(
address indexed pool,
uint256 amountA,
uint256 amountB,
uint256 burnAmount,
uint256 getId,
uint256[] setIds
);
event LogSwapAndDepositLiquidity(
address indexed pool,
uint256 amtA,
uint256 amtB,
uint256 mintAmount,
bool zeroForOne,
uint swapAmount,
uint256 getId,
uint256 setId
);
}

View File

@ -0,0 +1,32 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { IGUniRouter, IGUniPool, IERC20 } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
IGUniRouter public constant gUniRouter = IGUniRouter(0x8CA6fa325bc32f86a12cC4964Edf1f71655007A7);
struct DepositAndSwap {
IGUniPool poolContract;
IERC20 _token0;
IERC20 _token1;
uint amount0;
uint amount1;
uint mintAmount;
}
struct Deposit {
IGUniPool poolContract;
IERC20 _token0;
IERC20 _token1;
uint amount0In;
uint amount1In;
uint mintAmount;
}
}

View File

@ -0,0 +1,120 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IGUniPool {
function token0() external view returns (IERC20);
function token1() external view returns (IERC20);
function mint(
uint256 amount,
address receiver
) external
returns (
uint256 amount0,
uint256 amount1,
uint256 mintAmount
);
function burn(
uint256 _burnAmount,
address _receiver
) external
returns (
uint256 amount0,
uint256 amount1,
uint128 liquidityBurned
);
function getMintAmounts(
uint256 amount0Max,
uint256 amount1Max
) external view
returns (
uint256 amount0,
uint256 amount1,
uint256 mintAmount
);
}
interface IGUniRouter {
function rebalanceAndAddLiquidity(
IGUniPool pool,
uint256 amount0In,
uint256 amount1In,
bool zeroForOne,
uint256 swapAmount,
uint160 swapThreshold,
uint256 amount0Min,
uint256 amount1Min,
address receiver
)
external
returns (
uint256 amount0,
uint256 amount1,
uint256 mintAmount
);
function rebalanceAndAddLiquidityETH(
IGUniPool pool,
uint256 amount0In,
uint256 amount1In,
bool zeroForOne,
uint256 swapAmount,
uint160 swapThreshold,
uint256 amount0Min,
uint256 amount1Min,
address receiver
)
external
payable
returns (
uint256 amount0,
uint256 amount1,
uint256 mintAmount
);
function removeLiquidity(
IGUniPool pool,
uint256 burnAmount,
uint256 amount0Min,
uint256 amount1Min,
address receiver
)
external
returns (
uint256 amount0,
uint256 amount1,
uint128 liquidityBurned
);
function removeLiquidityETH(
IGUniPool pool,
uint256 burnAmount,
uint256 amount0Min,
uint256 amount1Min,
address payable receiver
)
external
returns (
uint256 amount0,
uint256 amount1,
uint128 liquidityBurned
);
}
interface TokenInterface {
function approve(address, uint256) external;
function transfer(address, uint) external;
function transferFrom(address, address, uint) external;
function deposit() external payable;
function withdraw(uint) external;
function balanceOf(address) external view returns (uint);
function decimals() external view returns (uint);
}

View File

@ -0,0 +1,220 @@
pragma solidity ^0.7.0;
/**
* @title G-Uniswap V3 ERC20 Wrapper.
* @dev G-Uniswap V3 Wrapper to deposit and withdraw.
*/
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { TokenInterface } from "../../common/interfaces.sol";
import { IGUniPool, IERC20 } from "./interface.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract UniswapV3Resolver is Events, Helpers {
using SafeERC20 for IERC20;
/**
* @dev Deposit Liquidity.
* @notice Deposit Liquidity to Gelato Uniswap V3 pool.
* @param pool The address of pool.
* @param amt0Max Amount0 Max amount
* @param amt1Max Amount1 Max amount
* @param slippage use to calculate minimum deposit. 100% = 1e18
* @param getIds Array of IDs to retrieve amounts.
* @param setId ID stores the amount of pools tokens received.
*/
function deposit(
address pool,
uint256 amt0Max,
uint256 amt1Max,
uint slippage,
uint256[] calldata getIds,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
amt0Max = getUint(getIds[0], amt0Max);
amt1Max = getUint(getIds[1], amt1Max);
Deposit memory depositData;
depositData.poolContract = IGUniPool(pool);
(depositData.amount0In, depositData.amount1In, depositData.mintAmount) =
depositData.poolContract.getMintAmounts(amt0Max, amt1Max);
uint amt0Min = wmul(amt0Max, slippage);
uint amt1Min = wmul(amt1Max, slippage);
require(
depositData.amount0In >= amt0Min && depositData.amount1In >= amt1Min,
"below min amounts"
);
if (depositData.amount0In > 0) {
IERC20 _token0 = depositData.poolContract.token0();
convertEthToWeth(address(_token0) == wethAddr, TokenInterface(address(_token0)), depositData.amount0In);
_token0.safeApprove(address(pool), depositData.amount0In);
}
if (depositData.amount1In > 0) {
IERC20 _token1 = depositData.poolContract.token1();
convertEthToWeth(address(_token1) == wethAddr, TokenInterface(address(_token1)), depositData.amount1In);
_token1.safeApprove(address(pool), depositData.amount1In);
}
(uint amount0, uint amount1,) = depositData.poolContract.mint(depositData.mintAmount, address(this));
require(
amount0 == depositData.amount0In &&
amount1 == depositData.amount1In, "unexpected amounts deposited");
setUint(setId, depositData.mintAmount);
_eventName = "LogDepositLiquidity(address,uint256,uint256,uint256,uint256[],uint256)";
_eventParam = abi.encode(pool, amount0, amount1, depositData.mintAmount, getIds, setId);
}
/**
* @dev Withdraw Liquidity.
* @notice Withdraw Liquidity from Gelato Uniswap V3 pool.
* @param pool The address of pool.
* @param liqAmt Amount0 Max amount
* @param minAmtA Min AmountA amount
* @param minAmtB Min AmountB amount
* @param getId ID to retrieve liqAmt.
* @param setIds Array of IDs tp stores the amounts of pools tokens received.
*/
function withdraw(
address pool,
uint256 liqAmt,
uint256 minAmtA,
uint256 minAmtB,
uint256 getId,
uint256[] calldata setIds
) external payable returns (string memory _eventName, bytes memory _eventParam) {
liqAmt = getUint(getId, liqAmt);
IGUniPool poolContract = IGUniPool(pool);
(uint amount0, uint amount1, uint128 liquidityBurned) = poolContract.burn(liqAmt, address(this));
if (amount0 > 0) {
IERC20 _token0 = poolContract.token0();
convertWethToEth(address(_token0) == wethAddr, TokenInterface(address(_token0)), amount0);
}
if (amount1 > 0) {
IERC20 _token1 = poolContract.token1();
convertWethToEth(address(_token1) == wethAddr, TokenInterface(address(_token1)), amount1);
}
require(amount0 >= minAmtA && amount1 >= minAmtB, "received below minimum");
setUint(setIds[0], amount0);
setUint(setIds[1], amount1);
_eventName = "LogWithdrawLiquidity(address,uint256,uint256,uint256,uint256,uint256[])";
_eventParam = abi.encode(pool, amount0, amount1, uint256(liquidityBurned), getId, setIds);
}
/**
* @dev Swap & Deposit Liquidity.
* @notice Withdraw Liquidity to Gelato Uniswap V3 pool.
* @param pool The address of pool.
* @param amount0In amount of token0 to deposit.
* @param amount1In amount of token1 to deposit.
* @param zeroForOne Swap excess of one token to deposit in equal ratio.
* @param swapAmount Amount of tokens to swap
* @param swapThreshold Slippage that the swap could take.
* @param getId Not used anywhere here.
* @param setId Set the amount of tokens minted.
*/
function swapAndDeposit(
address pool,
uint256 amount0In,
uint256 amount1In,
bool zeroForOne,
uint256 swapAmount,
uint160 swapThreshold,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
DepositAndSwap memory depositAndSwap;
depositAndSwap.poolContract = IGUniPool(pool);
depositAndSwap._token0 = depositAndSwap.poolContract.token0();
depositAndSwap._token1 = depositAndSwap.poolContract.token1();
depositAndSwap.amount0;
depositAndSwap.amount1;
depositAndSwap.mintAmount;
if (address(depositAndSwap._token0) == wethAddr) {
depositAndSwap._token1.approve(address(gUniRouter), amount1In);
(depositAndSwap.amount0, depositAndSwap.amount1, depositAndSwap.mintAmount) =
gUniRouter.rebalanceAndAddLiquidityETH{value: amount0In}(
depositAndSwap.poolContract,
amount0In,
amount1In,
zeroForOne,
swapAmount,
swapThreshold,
0,
0,
address(this)
);
} else if (address(depositAndSwap._token1) == wethAddr) {
depositAndSwap._token0.approve(address(gUniRouter), amount0In);
(depositAndSwap.amount0, depositAndSwap.amount1,depositAndSwap. mintAmount) =
gUniRouter.rebalanceAndAddLiquidityETH{value: amount1In}(
depositAndSwap.poolContract,
amount0In,
amount1In,
zeroForOne,
swapAmount,
swapThreshold,
0,
0,
address(this)
);
} else {
depositAndSwap._token0.approve(address(gUniRouter), amount0In);
depositAndSwap._token1.approve(address(gUniRouter), amount1In);
(depositAndSwap.amount0, depositAndSwap.amount1, depositAndSwap.mintAmount) =
gUniRouter.rebalanceAndAddLiquidity(
depositAndSwap.poolContract,
amount0In,
amount1In,
zeroForOne,
swapAmount,
swapThreshold,
0,
0,
address(this)
);
}
setUint(setId, depositAndSwap.mintAmount);
_eventName = "LogSwapAndDepositLiquidity(address,uint256,uint256,uint256,bool,uint256,uint256,uint256)";
_eventParam = abi.encode(
pool,
depositAndSwap.amount0,
depositAndSwap.amount1,
depositAndSwap.mintAmount,
zeroForOne,
swapAmount,
getId,
setId
);
}
}
contract ConnectV2GUniswapV3ERC20 is UniswapV3Resolver {
string public constant name = "G-Uniswap-v3-ERC20-v1.0";
}

View File

@ -0,0 +1,27 @@
pragma solidity ^0.7.0;
contract Events {
event LogDeposit(
address indexed stakingToken,
uint256 amount,
uint getId,
uint setId
);
event LogWithdrawAndClaimedReward(
address indexed stakingToken,
uint256 amount,
uint256 rewardAmt,
uint getId,
uint setIdAmount,
uint setIdReward
);
event LogClaimedReward(
address indexed rewardToken,
uint256 rewardAmt,
uint setId
);
}

View File

@ -0,0 +1,24 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { TokenInterface } from "../../common/interfaces.sol";
import { IStakingRewards, IStakingRewardsFactory, IGUniPoolResolver } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
IGUniPoolResolver constant internal guniResolver =
IGUniPoolResolver(0x729BF02a9A786529Fc80498f8fd0051116061B13);
TokenInterface constant internal rewardToken = TokenInterface(0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb);
function getStakingContract(address stakingToken) internal view returns (address) {
IStakingRewardsFactory.StakingRewardsInfo memory stakingRewardsInfo =
guniResolver.getStakingFactory().stakingRewardsInfoByStakingToken(stakingToken);
return stakingRewardsInfo.stakingRewards;
}
}

View File

@ -0,0 +1,26 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
interface IStakingRewards {
function stake(uint256 amount) external;
function withdraw(uint256 amount) external;
function getReward() external;
function balanceOf(address) external view returns(uint);
}
interface IStakingRewardsFactory {
struct StakingRewardsInfo {
address stakingRewards;
uint rewardAmount;
}
function stakingRewardsInfoByStakingToken(address) external view returns(StakingRewardsInfo memory);
}
interface IGUniPoolResolver {
function getStakingFactory() external view returns(IStakingRewardsFactory);
}

View File

@ -0,0 +1,108 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/**
* @title G-UNI Staking.
* @dev Stake G-UNI for earning rewards.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { Stores } from "../../common/stores.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
import { IStakingRewards, IStakingRewardsFactory } from "./interface.sol";
contract Main is Helpers, Events {
/**
* @dev Deposit ERC20.
* @notice Deposit Tokens to staking pool.
* @param stakingToken staking token address.
* @param amt staking token amount.
* @param getId ID to retrieve amount.
* @param setId ID stores the amount of staked tokens.
*/
function deposit(
address stakingToken,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
IStakingRewards stakingContract = IStakingRewards(getStakingContract(stakingToken));
TokenInterface stakingTokenContract = TokenInterface(stakingToken);
_amt = _amt == uint(-1) ? stakingTokenContract.balanceOf(address(this)) : _amt;
stakingTokenContract.approve(address(stakingContract), _amt);
stakingContract.stake(_amt);
setUint(setId, _amt);
_eventName = "LogDeposit(address,uint256,uint256,uint256)";
_eventParam = abi.encode(address(stakingToken), _amt, getId, setId);
}
/**
* @dev Withdraw ERC20.
* @notice Withdraw Tokens from the staking pool.
* @param stakingToken staking token address.
* @param amt staking token amount.
* @param getId ID to retrieve amount.
* @param setIdAmount ID stores the amount of stake tokens withdrawn.
* @param setIdReward ID stores the amount of reward tokens claimed.
*/
function withdraw(
address stakingToken,
uint amt,
uint getId,
uint setIdAmount,
uint setIdReward
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
IStakingRewards stakingContract = IStakingRewards(getStakingContract(stakingToken));
_amt = _amt == uint(-1) ? stakingContract.balanceOf(address(this)) : _amt;
uint intialBal = rewardToken.balanceOf(address(this));
stakingContract.withdraw(_amt);
stakingContract.getReward();
uint rewardAmt = sub(rewardToken.balanceOf(address(this)), intialBal);
setUint(setIdAmount, _amt);
setUint(setIdReward, rewardAmt);
{
_eventName = "LogWithdrawAndClaimedReward(address,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(address(stakingToken), _amt, rewardAmt, getId, setIdAmount, setIdReward);
}
}
/**
* @dev Claim Reward.
* @notice Claim Pending Rewards of tokens staked.
* @param stakingToken staking token address.
* @param setId ID stores the amount of reward tokens claimed.
*/
function claimReward(
address stakingToken,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
IStakingRewards stakingContract = IStakingRewards(getStakingContract(stakingToken));
uint intialBal = rewardToken.balanceOf(address(this));
stakingContract.getReward();
uint finalBal = rewardToken.balanceOf(address(this));
uint rewardAmt = sub(finalBal, intialBal);
setUint(setId, rewardAmt);
_eventName = "LogClaimedReward(address,uint256,uint256)";
_eventParam = abi.encode(address(rewardToken), rewardAmt, setId);
}
}
contract connectV2StakeGUNI is Main {
string public constant name = "Stake-G-UNI-v1.0";
}

View File

@ -43,7 +43,7 @@ abstract contract Helpers is DSMath, Basic {
* @dev Gem Join address is ETH type collateral.
*/
function isEth(address tknAddr) internal pure returns (bool) {
return tknAddr == ethAddr ? true : false;
return tknAddr == wethAddr ? true : false;
}
/**

View File

@ -5,7 +5,7 @@ pragma solidity ^0.7.0;
* @dev Collateralized Borrowing.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { TokenInterface, AccountInterface } from "../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
import { VatLike, TokenJoinInterface } from "./interface.sol";
@ -44,6 +44,29 @@ abstract contract MakerResolver is Helpers, Events {
_eventParam = abi.encode(_vault, ilk);
}
/**
* @dev Transfer Vault
* @notice Transfer a MakerDAO Vault to "nextOwner"
* @param vault Vault ID to close.
* @param nextOwner Address of the next owner of the vault.
*/
function transfer(
uint vault,
address nextOwner
) external payable returns (string memory _eventName, bytes memory _eventParam) {
require(AccountInterface(address(this)).isAuth(nextOwner), "nextOwner-is-not-auth");
uint256 _vault = getVault(vault);
(bytes32 ilk,) = getVaultData(_vault);
require(managerContract.owns(_vault) == address(this), "not-owner");
managerContract.give(_vault, nextOwner);
_eventName = "LogTransfer(uint256,bytes32,address)";
_eventParam = abi.encode(_vault, ilk, nextOwner);
}
/**
* @dev Deposit ETH/ERC20_Token Collateral.
* @notice Deposit collateral to a MakerDAO vault
@ -495,6 +518,6 @@ abstract contract MakerResolver is Helpers, Events {
}
}
contract ConnectV2Maker is MakerResolver {
string public constant name = "MakerDao-v1";
contract ConnectV2MakerDAO is MakerResolver {
string public constant name = "MakerDAO-v1.1";
}

View File

@ -2,7 +2,7 @@ pragma solidity ^0.7.0;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { RootChainManagerInterface } from "./interface.sol";
import { RootChainManagerInterface, DepositManagerProxyInterface } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
@ -14,4 +14,9 @@ abstract contract Helpers is DSMath, Basic {
* @dev Polygon POS Bridge Manager
*/
RootChainManagerInterface internal constant migrator = RootChainManagerInterface(0xA0c68C638235ee32657e8f720a23ceC1bFc77C77);
/**
* @dev Polygon Plasma Bridge Manager
*/
DepositManagerProxyInterface internal constant migratorPlasma = DepositManagerProxyInterface(0x401F6c983eA34274ec46f84D70b31C151321188b);
}

View File

@ -2,10 +2,19 @@ pragma solidity ^0.7.0;
interface RootChainManagerInterface {
function depositEtherFor(address user) external payable;
function rootToChildToken(address user) external view returns(address);
function depositFor(
address user,
address rootToken,
bytes calldata depositData
) external;
function exit(bytes calldata inputData) external;
}
interface DepositManagerProxyInterface {
function depositERC20ForUser(
address _token,
address _user,
uint256 _amount
) external;
}

View File

@ -35,8 +35,13 @@ abstract contract PolygonBridgeResolver is Events, Helpers {
} else {
TokenInterface _token = TokenInterface(token);
_amt = _amt == uint(-1) ? _token.balanceOf(address(this)) : _amt;
_token.approve(erc20Predicate, _amt);
migrator.depositFor(targetDsa, token, abi.encode(_amt));
if (migrator.rootToChildToken(token) != address(0)) {
_token.approve(erc20Predicate, _amt);
migrator.depositFor(targetDsa, token, abi.encode(_amt));
} else {
_token.approve(address(migratorPlasma), _amt);
migratorPlasma.depositERC20ForUser(token, targetDsa, _amt);
}
}
setUint(setId, _amt);
@ -47,5 +52,5 @@ abstract contract PolygonBridgeResolver is Events, Helpers {
}
contract ConnectV2PolygonBridge is PolygonBridgeResolver {
string public constant name = "Polygon-Bridge-v1";
string public constant name = "Polygon-Bridge-v1.1";
}

View File

@ -0,0 +1,155 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { Basic } from "../../common/basic.sol";
import {
AaveV1ProviderInterface,
AaveV1Interface,
AaveV2LendingPoolProviderInterface,
AaveV2DataProviderInterface,
AaveV2Interface,
ComptrollerInterface,
CTokenInterface,
CompoundMappingInterface
} from "./interfaces.sol";
import { TokenInterface } from "../../common/interfaces.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract Helpers is Basic {
using SafeERC20 for IERC20;
enum Protocol {
Aave,
AaveV2,
Compound
}
address payable constant feeCollector = 0xb1DC62EC38E6E3857a887210C38418E4A17Da5B2;
/**
* @dev Return InstaDApp Mapping Address
*/
address constant internal getMappingAddr = 0xA8F9D4aA7319C54C04404765117ddBf9448E2082; // CompoundMapping Address
/**
* @dev Return Compound Comptroller Address
*/
address constant internal getComptrollerAddress = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B; // CompoundMapping Address
/**
* @dev get Aave Provider
*/
AaveV1ProviderInterface constant internal getAaveProvider =
AaveV1ProviderInterface(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8);
/**
* @dev get Aave Lending Pool Provider
*/
AaveV2LendingPoolProviderInterface constant internal getAaveV2Provider =
AaveV2LendingPoolProviderInterface(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5);
/**
* @dev get Aave Protocol Data Provider
*/
AaveV2DataProviderInterface constant internal getAaveV2DataProvider =
AaveV2DataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d);
/**
* @dev get Referral Code
*/
uint16 constant internal getReferralCode = 3228;
}
contract protocolHelpers is Helpers {
using SafeERC20 for IERC20;
function getWithdrawBalance(AaveV1Interface aave, address token) internal view returns (uint bal) {
(bal, , , , , , , , , ) = aave.getUserReserveData(token, address(this));
}
function getPaybackBalance(AaveV1Interface aave, address token) internal view returns (uint bal, uint fee) {
(, bal, , , , , fee, , , ) = aave.getUserReserveData(token, address(this));
}
function getTotalBorrowBalance(AaveV1Interface aave, address token) internal view returns (uint amt) {
(, uint bal, , , , , uint fee, , , ) = aave.getUserReserveData(token, address(this));
amt = add(bal, fee);
}
function getWithdrawBalanceV2(AaveV2DataProviderInterface aaveData, address token) internal view returns (uint bal) {
(bal, , , , , , , , ) = aaveData.getUserReserveData(token, address(this));
}
function getPaybackBalanceV2(AaveV2DataProviderInterface aaveData, address token, uint rateMode) internal view returns (uint bal) {
if (rateMode == 1) {
(, bal, , , , , , , ) = aaveData.getUserReserveData(token, address(this));
} else {
(, , bal, , , , , , ) = aaveData.getUserReserveData(token, address(this));
}
}
function getIsColl(AaveV1Interface aave, address token) internal view returns (bool isCol) {
(, , , , , , , , , isCol) = aave.getUserReserveData(token, address(this));
}
function getIsCollV2(AaveV2DataProviderInterface aaveData, address token) internal view returns (bool isCol) {
(, , , , , , , , isCol) = aaveData.getUserReserveData(token, address(this));
}
function getMaxBorrow(Protocol target, address token, CTokenInterface ctoken, uint rateMode) internal returns (uint amt) {
AaveV1Interface aaveV1 = AaveV1Interface(getAaveProvider.getLendingPool());
AaveV2DataProviderInterface aaveData = getAaveV2DataProvider;
if (target == Protocol.Aave) {
(uint _amt, uint _fee) = getPaybackBalance(aaveV1, token);
amt = _amt + _fee;
} else if (target == Protocol.AaveV2) {
amt = getPaybackBalanceV2(aaveData, token, rateMode);
} else if (target == Protocol.Compound) {
amt = ctoken.borrowBalanceCurrent(address(this));
}
}
function transferFees(address token, uint feeAmt) internal {
if (feeAmt > 0) {
if (token == ethAddr) {
feeCollector.transfer(feeAmt);
} else {
IERC20(token).safeTransfer(feeCollector, feeAmt);
}
}
}
function calculateFee(uint256 amount, uint256 fee, bool toAdd) internal pure returns(uint feeAmount, uint _amount){
feeAmount = wmul(amount, fee);
_amount = toAdd ? add(amount, feeAmount) : sub(amount, feeAmount);
}
function getTokenInterfaces(uint length, address[] memory tokens) internal pure returns (TokenInterface[] memory) {
TokenInterface[] memory _tokens = new TokenInterface[](length);
for (uint i = 0; i < length; i++) {
if (tokens[i] == ethAddr) {
_tokens[i] = TokenInterface(wethAddr);
} else {
_tokens[i] = TokenInterface(tokens[i]);
}
}
return _tokens;
}
function getCtokenInterfaces(uint length, string[] memory tokenIds) internal view returns (CTokenInterface[] memory) {
CTokenInterface[] memory _ctokens = new CTokenInterface[](length);
for (uint i = 0; i < length; i++) {
(address token, address cToken) = CompoundMappingInterface(getMappingAddr).getMapping(tokenIds[i]);
require(token != address(0) && cToken != address(0), "invalid token/ctoken address");
_ctokens[i] = CTokenInterface(cToken);
}
return _ctokens;
}
}

View File

@ -0,0 +1,202 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { protocolHelpers } from "../helpers.sol";
import {
AaveV1ProviderInterface,
AaveV1Interface,
AaveV1CoreInterface,
ATokenV1Interface,
CTokenInterface
// AaveV2LendingPoolProviderInterface,
// AaveV2DataProviderInterface,
// AaveV2Interface,
} from "../interfaces.sol";
import { TokenInterface } from "../../../common/interfaces.sol";
contract AaveV1Helpers is protocolHelpers {
struct AaveV1BorrowData {
AaveV1Interface aave;
uint length;
uint fee;
Protocol target;
TokenInterface[] tokens;
CTokenInterface[] ctokens;
uint[] amts;
uint[] borrowRateModes;
uint[] paybackRateModes;
}
struct AaveV1DepositData {
AaveV1Interface aave;
AaveV1CoreInterface aaveCore;
uint length;
uint fee;
TokenInterface[] tokens;
uint[] amts;
}
function _aaveV1BorrowOne(
AaveV1Interface aave,
uint fee,
Protocol target,
TokenInterface token,
CTokenInterface ctoken,
uint amt,
uint borrowRateMode,
uint paybackRateMode
) internal returns (uint) {
if (amt > 0) {
address _token = address(token) == wethAddr ? ethAddr : address(token);
if (amt == uint(-1)) {
amt = getMaxBorrow(target, address(token), ctoken, paybackRateMode);
}
(uint feeAmt, uint _amt) = calculateFee(amt, fee, true);
aave.borrow(_token, _amt, borrowRateMode, getReferralCode);
transferFees(_token, feeAmt);
}
return amt;
}
function _aaveV1Borrow(
AaveV1BorrowData memory data
) internal returns (uint[] memory) {
uint[] memory finalAmts = new uint[](data.length);
for (uint i = 0; i < data.length; i++) {
finalAmts[i] = _aaveV1BorrowOne(
data.aave,
data.fee,
data.target,
data.tokens[i],
data.ctokens[i],
data.amts[i],
data.borrowRateModes[i],
data.paybackRateModes[i]
);
}
return finalAmts;
}
function _aaveV1DepositOne(
AaveV1Interface aave,
AaveV1CoreInterface aaveCore,
uint fee,
TokenInterface token,
uint amt
) internal {
if (amt > 0) {
uint ethAmt;
(uint feeAmt, uint _amt) = calculateFee(amt, fee, false);
bool isEth = address(token) == wethAddr;
address _token = isEth ? ethAddr : address(token);
if (isEth) {
ethAmt = _amt;
} else {
token.approve(address(aaveCore), _amt);
}
transferFees(_token, feeAmt);
aave.deposit{value:ethAmt}(_token, _amt, getReferralCode);
if (!getIsColl(aave, _token))
aave.setUserUseReserveAsCollateral(_token, true);
}
}
function _aaveV1Deposit(
AaveV1DepositData memory data
) internal {
for (uint i = 0; i < data.length; i++) {
_aaveV1DepositOne(
data.aave,
data.aaveCore,
data.fee,
data.tokens[i],
data.amts[i]
);
}
}
function _aaveV1WithdrawOne(
AaveV1Interface aave,
AaveV1CoreInterface aaveCore,
TokenInterface token,
uint amt
) internal returns (uint) {
if (amt > 0) {
address _token = address(token) == wethAddr ? ethAddr : address(token);
ATokenV1Interface atoken = ATokenV1Interface(aaveCore.getReserveATokenAddress(_token));
if (amt == uint(-1)) {
amt = getWithdrawBalance(aave, _token);
}
atoken.redeem(amt);
}
return amt;
}
function _aaveV1Withdraw(
AaveV1Interface aave,
AaveV1CoreInterface aaveCore,
uint length,
TokenInterface[] memory tokens,
uint[] memory amts
) internal returns (uint[] memory) {
uint[] memory finalAmts = new uint[](length);
for (uint i = 0; i < length; i++) {
finalAmts[i] = _aaveV1WithdrawOne(aave, aaveCore, tokens[i], amts[i]);
}
return finalAmts;
}
function _aaveV1PaybackOne(
AaveV1Interface aave,
AaveV1CoreInterface aaveCore,
TokenInterface token,
uint amt
) internal returns (uint) {
if (amt > 0) {
uint ethAmt;
bool isEth = address(token) == wethAddr;
address _token = isEth ? ethAddr : address(token);
if (amt == uint(-1)) {
(uint _amt, uint _fee) = getPaybackBalance(aave, _token);
amt = _amt + _fee;
}
if (isEth) {
ethAmt = amt;
} else {
token.approve(address(aaveCore), amt);
}
aave.repay{value:ethAmt}(_token, amt, payable(address(this)));
}
return amt;
}
function _aaveV1Payback(
AaveV1Interface aave,
AaveV1CoreInterface aaveCore,
uint length,
TokenInterface[] memory tokens,
uint[] memory amts
) internal {
for (uint i = 0; i < length; i++) {
_aaveV1PaybackOne(aave, aaveCore, tokens[i], amts[i]);
}
}
}

View File

@ -0,0 +1,200 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { protocolHelpers } from "../helpers.sol";
import {
// AaveV1ProviderInterface,
// AaveV1Interface,
// AaveV1CoreInterface,
AaveV2LendingPoolProviderInterface,
AaveV2DataProviderInterface,
AaveV2Interface,
ATokenV1Interface,
CTokenInterface
} from "../interfaces.sol";
import { TokenInterface } from "../../../common/interfaces.sol";
contract AaveV2Helpers is protocolHelpers {
struct AaveV2BorrowData {
AaveV2Interface aave;
uint length;
uint fee;
Protocol target;
TokenInterface[] tokens;
CTokenInterface[] ctokens;
uint[] amts;
uint[] rateModes;
}
struct AaveV2PaybackData {
AaveV2Interface aave;
AaveV2DataProviderInterface aaveData;
uint length;
TokenInterface[] tokens;
uint[] amts;
uint[] rateModes;
}
struct AaveV2WithdrawData {
AaveV2Interface aave;
AaveV2DataProviderInterface aaveData;
uint length;
TokenInterface[] tokens;
uint[] amts;
}
function _aaveV2BorrowOne(
AaveV2Interface aave,
uint fee,
Protocol target,
TokenInterface token,
CTokenInterface ctoken,
uint amt,
uint rateMode
) internal returns (uint) {
if (amt > 0) {
bool isEth = address(token) == wethAddr;
address _token = isEth ? ethAddr : address(token);
if (amt == uint(-1)) {
amt = getMaxBorrow(target, _token, ctoken, rateMode);
}
(uint feeAmt, uint _amt) = calculateFee(amt, fee, true);
aave.borrow(address(token), _amt, rateMode, getReferralCode, address(this));
convertWethToEth(isEth, token, amt);
transferFees(_token, feeAmt);
}
return amt;
}
function _aaveV2Borrow(
AaveV2BorrowData memory data
) internal returns (uint[] memory) {
uint[] memory finalAmts = new uint[](data.length);
for (uint i = 0; i < data.length; i++) {
finalAmts[i] = _aaveV2BorrowOne(
data.aave,
data.fee,
data.target,
data.tokens[i],
data.ctokens[i],
data.amts[i],
data.rateModes[i]
);
}
return finalAmts;
}
function _aaveV2DepositOne(
AaveV2Interface aave,
AaveV2DataProviderInterface aaveData,
uint fee,
TokenInterface token,
uint amt
) internal {
if (amt > 0) {
(uint feeAmt, uint _amt) = calculateFee(amt, fee, false);
bool isEth = address(token) == wethAddr;
address _token = isEth ? ethAddr : address(token);
transferFees(_token, feeAmt);
convertEthToWeth(isEth, token, _amt);
token.approve(address(aave), _amt);
aave.deposit(address(token), _amt, address(this), getReferralCode);
if (!getIsCollV2(aaveData, address(token))) {
aave.setUserUseReserveAsCollateral(address(token), true);
}
}
}
function _aaveV2Deposit(
AaveV2Interface aave,
AaveV2DataProviderInterface aaveData,
uint length,
uint fee,
TokenInterface[] memory tokens,
uint[] memory amts
) internal {
for (uint i = 0; i < length; i++) {
_aaveV2DepositOne(aave, aaveData, fee, tokens[i], amts[i]);
}
}
function _aaveV2WithdrawOne(
AaveV2Interface aave,
AaveV2DataProviderInterface aaveData,
TokenInterface token,
uint amt
) internal returns (uint _amt) {
if (amt > 0) {
bool isEth = address(token) == wethAddr;
aave.withdraw(address(token), amt, address(this));
_amt = amt == uint(-1) ? getWithdrawBalanceV2(aaveData, address(token)) : amt;
convertWethToEth(isEth, token, _amt);
}
}
function _aaveV2Withdraw(
AaveV2WithdrawData memory data
) internal returns (uint[] memory) {
uint[] memory finalAmts = new uint[](data.length);
for (uint i = 0; i < data.length; i++) {
finalAmts[i] = _aaveV2WithdrawOne(
data.aave,
data.aaveData,
data.tokens[i],
data.amts[i]
);
}
return finalAmts;
}
function _aaveV2PaybackOne(
AaveV2Interface aave,
AaveV2DataProviderInterface aaveData,
TokenInterface token,
uint amt,
uint rateMode
) internal returns (uint _amt) {
if (amt > 0) {
bool isEth = address(token) == wethAddr;
_amt = amt == uint(-1) ? getPaybackBalanceV2(aaveData, address(token), rateMode) : amt;
convertEthToWeth(isEth, token, _amt);
token.approve(address(aave), _amt);
aave.repay(address(token), _amt, rateMode, address(this));
}
}
function _aaveV2Payback(
AaveV2PaybackData memory data
) internal {
for (uint i = 0; i < data.length; i++) {
_aaveV2PaybackOne(
data.aave,
data.aaveData,
data.tokens[i],
data.amts[i],
data.rateModes[i]
);
}
}
}

View File

@ -0,0 +1,160 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { protocolHelpers } from "../helpers.sol";
import {
ComptrollerInterface,
CTokenInterface,
CompoundMappingInterface,
CETHInterface
} from "../interfaces.sol";
import { TokenInterface } from "../../../common/interfaces.sol";
contract CompoundHelpers is protocolHelpers {
struct CompoundBorrowData {
uint length;
uint fee;
Protocol target;
CTokenInterface[] ctokens;
TokenInterface[] tokens;
uint[] amts;
uint[] rateModes;
}
function _compEnterMarkets(uint length, CTokenInterface[] memory ctokens) internal {
ComptrollerInterface troller = ComptrollerInterface(getComptrollerAddress);
address[] memory _cTokens = new address[](length);
for (uint i = 0; i < length; i++) {
_cTokens[i] = address(ctokens[i]);
}
troller.enterMarkets(_cTokens);
}
function _compBorrowOne(
uint fee,
CTokenInterface ctoken,
TokenInterface token,
uint amt,
Protocol target,
uint rateMode
) internal returns (uint) {
if (amt > 0) {
address _token = address(token) == wethAddr ? ethAddr : address(token);
if (amt == uint(-1)) {
amt = getMaxBorrow(target, address(token), ctoken, rateMode);
}
(uint feeAmt, uint _amt) = calculateFee(amt, fee, true);
require(ctoken.borrow(_amt) == 0, "borrow-failed-collateral?");
transferFees(_token, feeAmt);
}
return amt;
}
function _compBorrow(
CompoundBorrowData memory data
) internal returns (uint[] memory) {
uint[] memory finalAmts = new uint[](data.length);
for (uint i = 0; i < data.length; i++) {
finalAmts[i] = _compBorrowOne(
data.fee,
data.ctokens[i],
data.tokens[i],
data.amts[i],
data.target,
data.rateModes[i]
);
}
return finalAmts;
}
function _compDepositOne(uint fee, CTokenInterface ctoken, TokenInterface token, uint amt) internal {
if (amt > 0) {
address _token = address(token) == wethAddr ? ethAddr : address(token);
(uint feeAmt, uint _amt) = calculateFee(amt, fee, false);
if (_token != ethAddr) {
token.approve(address(ctoken), _amt);
require(ctoken.mint(_amt) == 0, "deposit-failed");
} else {
CETHInterface(address(ctoken)).mint{value:_amt}();
}
transferFees(_token, feeAmt);
}
}
function _compDeposit(
uint length,
uint fee,
CTokenInterface[] memory ctokens,
TokenInterface[] memory tokens,
uint[] memory amts
) internal {
for (uint i = 0; i < length; i++) {
_compDepositOne(fee, ctokens[i], tokens[i], amts[i]);
}
}
function _compWithdrawOne(CTokenInterface ctoken, TokenInterface token, uint amt) internal returns (uint) {
if (amt > 0) {
if (amt == uint(-1)) {
bool isEth = address(token) == wethAddr;
uint initalBal = isEth ? address(this).balance : token.balanceOf(address(this));
require(ctoken.redeem(ctoken.balanceOf(address(this))) == 0, "withdraw-failed");
uint finalBal = isEth ? address(this).balance : token.balanceOf(address(this));
amt = sub(finalBal, initalBal);
} else {
require(ctoken.redeemUnderlying(amt) == 0, "withdraw-failed");
}
}
return amt;
}
function _compWithdraw(
uint length,
CTokenInterface[] memory ctokens,
TokenInterface[] memory tokens,
uint[] memory amts
) internal returns(uint[] memory) {
uint[] memory finalAmts = new uint[](length);
for (uint i = 0; i < length; i++) {
finalAmts[i] = _compWithdrawOne(ctokens[i], tokens[i], amts[i]);
}
return finalAmts;
}
function _compPaybackOne(CTokenInterface ctoken, TokenInterface token, uint amt) internal returns (uint) {
if (amt > 0) {
if (amt == uint(-1)) {
amt = ctoken.borrowBalanceCurrent(address(this));
}
if (address(token) != wethAddr) {
token.approve(address(ctoken), amt);
require(ctoken.repayBorrow(amt) == 0, "repay-failed.");
} else {
CETHInterface(address(ctoken)).repayBorrow{value:amt}();
}
}
return amt;
}
function _compPayback(
uint length,
CTokenInterface[] memory ctokens,
TokenInterface[] memory tokens,
uint[] memory amts
) internal {
for (uint i = 0; i < length; i++) {
_compPaybackOne(ctokens[i], tokens[i], amts[i]);
}
}
}

View File

@ -0,0 +1,113 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
// Compound Helpers
interface CTokenInterface {
function mint(uint mintAmount) external returns (uint);
function redeem(uint redeemTokens) external returns (uint);
function borrow(uint borrowAmount) external returns (uint);
function repayBorrow(uint repayAmount) external returns (uint);
function borrowBalanceCurrent(address account) external returns (uint);
function redeemUnderlying(uint redeemAmount) external returns (uint);
function balanceOf(address owner) external view returns (uint256 balance);
}
interface CETHInterface {
function mint() external payable;
function repayBorrow() external payable;
}
interface CompoundMappingInterface {
function cTokenMapping(string calldata tokenId) external view returns (address);
function getMapping(string calldata tokenId) external view returns (address, address);
}
interface ComptrollerInterface {
function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);
}
// End Compound Helpers
// Aave v1 Helpers
interface AaveV1Interface {
function deposit(address _reserve, uint256 _amount, uint16 _referralCode) external payable;
function redeemUnderlying(
address _reserve,
address payable _user,
uint256 _amount,
uint256 _aTokenBalanceAfterRedeem
) external;
function setUserUseReserveAsCollateral(address _reserve, bool _useAsCollateral) external;
function getUserReserveData(address _reserve, address _user) external view returns (
uint256 currentATokenBalance,
uint256 currentBorrowBalance,
uint256 principalBorrowBalance,
uint256 borrowRateMode,
uint256 borrowRate,
uint256 liquidityRate,
uint256 originationFee,
uint256 variableBorrowIndex,
uint256 lastUpdateTimestamp,
bool usageAsCollateralEnabled
);
function borrow(address _reserve, uint256 _amount, uint256 _interestRateMode, uint16 _referralCode) external;
function repay(address _reserve, uint256 _amount, address payable _onBehalfOf) external payable;
}
interface AaveV1ProviderInterface {
function getLendingPool() external view returns (address);
function getLendingPoolCore() external view returns (address);
}
interface AaveV1CoreInterface {
function getReserveATokenAddress(address _reserve) external view returns (address);
}
interface ATokenV1Interface {
function redeem(uint256 _amount) external;
function balanceOf(address _user) external view returns(uint256);
function principalBalanceOf(address _user) external view returns(uint256);
function allowance(address, address) external view returns (uint);
function approve(address, uint) external;
function transfer(address, uint) external returns (bool);
function transferFrom(address, address, uint) external returns (bool);
}
// End Aave v1 Helpers
// Aave v2 Helpers
interface AaveV2Interface {
function deposit(address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode) external;
function withdraw(address _asset, uint256 _amount, address _to) external;
function borrow(
address _asset,
uint256 _amount,
uint256 _interestRateMode,
uint16 _referralCode,
address _onBehalfOf
) external;
function repay(address _asset, uint256 _amount, uint256 _rateMode, address _onBehalfOf) external;
function setUserUseReserveAsCollateral(address _asset, bool _useAsCollateral) external;
}
interface AaveV2LendingPoolProviderInterface {
function getLendingPool() external view returns (address);
}
// Aave Protocol Data Provider
interface AaveV2DataProviderInterface {
function getUserReserveData(address _asset, address _user) external view returns (
uint256 currentATokenBalance,
uint256 currentStableDebt,
uint256 currentVariableDebt,
uint256 principalStableDebt,
uint256 scaledVariableDebt,
uint256 stableBorrowRate,
uint256 liquidityRate,
uint40 stableRateLastUpdated,
bool usageAsCollateralEnabled
);
}
// End Aave v2 Helpers

View File

@ -0,0 +1,339 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/**
* @title Refinance.
* @dev Refinancing.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import {
AaveV1ProviderInterface,
AaveV1Interface,
AaveV1CoreInterface,
AaveV2LendingPoolProviderInterface,
AaveV2DataProviderInterface,
AaveV2Interface,
ComptrollerInterface,
CTokenInterface,
CompoundMappingInterface
} from "./interfaces.sol";
import { AaveV1Helpers } from "./helpers/aaveV1.sol";
import { AaveV2Helpers } from "./helpers/aaveV2.sol";
import { CompoundHelpers } from "./helpers/compound.sol";
contract RefinanceResolver is CompoundHelpers, AaveV1Helpers, AaveV2Helpers {
struct RefinanceData {
Protocol source;
Protocol target;
uint collateralFee;
uint debtFee;
address[] tokens;
string[] ctokenIds;
uint[] borrowAmts;
uint[] withdrawAmts;
uint[] borrowRateModes;
uint[] paybackRateModes;
}
struct RefinanceInternalData {
AaveV2Interface aaveV2;
AaveV1Interface aaveV1;
AaveV1CoreInterface aaveCore;
AaveV2DataProviderInterface aaveData;
uint[] depositAmts;
uint[] paybackAmts;
TokenInterface[] tokens;
CTokenInterface[] _ctokens;
}
function _refinance(RefinanceData calldata data)
internal returns (string memory _eventName, bytes memory _eventParam)
{
require(data.source != data.target, "source-and-target-unequal");
uint length = data.tokens.length;
require(data.borrowAmts.length == length, "length-mismatch");
require(data.withdrawAmts.length == length, "length-mismatch");
require(data.borrowRateModes.length == length, "length-mismatch");
require(data.paybackRateModes.length == length, "length-mismatch");
require(data.ctokenIds.length == length, "length-mismatch");
RefinanceInternalData memory refinanceInternalData;
refinanceInternalData.aaveV2 = AaveV2Interface(getAaveV2Provider.getLendingPool());
refinanceInternalData.aaveV1 = AaveV1Interface(getAaveProvider.getLendingPool());
refinanceInternalData.aaveCore = AaveV1CoreInterface(getAaveProvider.getLendingPoolCore());
refinanceInternalData.aaveData = getAaveV2DataProvider;
refinanceInternalData.depositAmts;
refinanceInternalData.paybackAmts;
refinanceInternalData.tokens = getTokenInterfaces(length, data.tokens);
refinanceInternalData._ctokens = getCtokenInterfaces(length, data.ctokenIds);
if (data.source == Protocol.Aave && data.target == Protocol.AaveV2) {
AaveV2BorrowData memory _aaveV2BorrowData;
_aaveV2BorrowData.aave = refinanceInternalData.aaveV2;
_aaveV2BorrowData.length = length;
_aaveV2BorrowData.fee = data.debtFee;
_aaveV2BorrowData.target = data.source;
_aaveV2BorrowData.tokens = refinanceInternalData.tokens;
_aaveV2BorrowData.ctokens = refinanceInternalData._ctokens;
_aaveV2BorrowData.amts = data.borrowAmts;
_aaveV2BorrowData.rateModes = data.borrowRateModes;
{
refinanceInternalData.paybackAmts = _aaveV2Borrow(_aaveV2BorrowData);
_aaveV1Payback(
refinanceInternalData.aaveV1,
refinanceInternalData.aaveCore,
length,
refinanceInternalData.tokens,
refinanceInternalData.paybackAmts
);
refinanceInternalData.depositAmts = _aaveV1Withdraw(
refinanceInternalData.aaveV1,
refinanceInternalData.aaveCore,
length,
refinanceInternalData.tokens,
data.withdrawAmts
);
_aaveV2Deposit(
refinanceInternalData.aaveV2,
refinanceInternalData.aaveData,
length,
data.collateralFee,
refinanceInternalData.tokens,
refinanceInternalData.depositAmts
);
}
} else if (data.source == Protocol.Aave && data.target == Protocol.Compound) {
_compEnterMarkets(length, refinanceInternalData._ctokens);
CompoundBorrowData memory _compoundBorrowData;
_compoundBorrowData.length = length;
_compoundBorrowData.fee = data.debtFee;
_compoundBorrowData.target = data.source;
_compoundBorrowData.ctokens = refinanceInternalData._ctokens;
_compoundBorrowData.tokens = refinanceInternalData.tokens;
_compoundBorrowData.amts = data.borrowAmts;
_compoundBorrowData.rateModes = data.borrowRateModes;
refinanceInternalData.paybackAmts = _compBorrow(_compoundBorrowData);
_aaveV1Payback(
refinanceInternalData.aaveV1,
refinanceInternalData.aaveCore,
length,
refinanceInternalData.tokens,
refinanceInternalData.paybackAmts
);
refinanceInternalData.depositAmts = _aaveV1Withdraw(
refinanceInternalData.aaveV1,
refinanceInternalData.aaveCore,
length,
refinanceInternalData.tokens,
data.withdrawAmts
);
_compDeposit(
length,
data.collateralFee,
refinanceInternalData._ctokens,
refinanceInternalData.tokens,
refinanceInternalData.depositAmts
);
} else if (data.source == Protocol.AaveV2 && data.target == Protocol.Aave) {
AaveV1BorrowData memory _aaveV1BorrowData;
AaveV2PaybackData memory _aaveV2PaybackData;
AaveV2WithdrawData memory _aaveV2WithdrawData;
{
_aaveV1BorrowData.aave = refinanceInternalData.aaveV1;
_aaveV1BorrowData.length = length;
_aaveV1BorrowData.fee = data.debtFee;
_aaveV1BorrowData.target = data.source;
_aaveV1BorrowData.tokens = refinanceInternalData.tokens;
_aaveV1BorrowData.ctokens = refinanceInternalData._ctokens;
_aaveV1BorrowData.amts = data.borrowAmts;
_aaveV1BorrowData.borrowRateModes = data.borrowRateModes;
_aaveV1BorrowData.paybackRateModes = data.paybackRateModes;
refinanceInternalData.paybackAmts = _aaveV1Borrow(_aaveV1BorrowData);
}
{
_aaveV2PaybackData.aave = refinanceInternalData.aaveV2;
_aaveV2PaybackData.aaveData = refinanceInternalData.aaveData;
_aaveV2PaybackData.length = length;
_aaveV2PaybackData.tokens = refinanceInternalData.tokens;
_aaveV2PaybackData.amts = refinanceInternalData.paybackAmts;
_aaveV2PaybackData.rateModes = data.paybackRateModes;
_aaveV2Payback(_aaveV2PaybackData);
}
{
_aaveV2WithdrawData.aave = refinanceInternalData.aaveV2;
_aaveV2WithdrawData.aaveData = refinanceInternalData.aaveData;
_aaveV2WithdrawData.length = length;
_aaveV2WithdrawData.tokens = refinanceInternalData.tokens;
_aaveV2WithdrawData.amts = data.withdrawAmts;
refinanceInternalData.depositAmts = _aaveV2Withdraw(_aaveV2WithdrawData);
}
{
AaveV1DepositData memory _aaveV1DepositData;
_aaveV1DepositData.aave = refinanceInternalData.aaveV1;
_aaveV1DepositData.aaveCore = refinanceInternalData.aaveCore;
_aaveV1DepositData.length = length;
_aaveV1DepositData.fee = data.collateralFee;
_aaveV1DepositData.tokens = refinanceInternalData.tokens;
_aaveV1DepositData.amts = refinanceInternalData.depositAmts;
_aaveV1Deposit(_aaveV1DepositData);
}
} else if (data.source == Protocol.AaveV2 && data.target == Protocol.Compound) {
_compEnterMarkets(length, refinanceInternalData._ctokens);
{
CompoundBorrowData memory _compoundBorrowData;
_compoundBorrowData.length = length;
_compoundBorrowData.fee = data.debtFee;
_compoundBorrowData.target = data.source;
_compoundBorrowData.ctokens = refinanceInternalData._ctokens;
_compoundBorrowData.tokens = refinanceInternalData.tokens;
_compoundBorrowData.amts = data.borrowAmts;
_compoundBorrowData.rateModes = data.borrowRateModes;
refinanceInternalData.paybackAmts = _compBorrow(_compoundBorrowData);
}
AaveV2PaybackData memory _aaveV2PaybackData;
_aaveV2PaybackData.aave = refinanceInternalData.aaveV2;
_aaveV2PaybackData.aaveData = refinanceInternalData.aaveData;
_aaveV2PaybackData.length = length;
_aaveV2PaybackData.tokens = refinanceInternalData.tokens;
_aaveV2PaybackData.amts = refinanceInternalData.paybackAmts;
_aaveV2PaybackData.rateModes = data.paybackRateModes;
_aaveV2Payback(_aaveV2PaybackData);
{
AaveV2WithdrawData memory _aaveV2WithdrawData;
_aaveV2WithdrawData.aave = refinanceInternalData.aaveV2;
_aaveV2WithdrawData.aaveData = refinanceInternalData.aaveData;
_aaveV2WithdrawData.length = length;
_aaveV2WithdrawData.tokens = refinanceInternalData.tokens;
_aaveV2WithdrawData.amts = data.withdrawAmts;
refinanceInternalData.depositAmts = _aaveV2Withdraw(_aaveV2WithdrawData);
}
_compDeposit(
length,
data.collateralFee,
refinanceInternalData._ctokens,
refinanceInternalData.tokens,
refinanceInternalData.depositAmts
);
} else if (data.source == Protocol.Compound && data.target == Protocol.Aave) {
AaveV1BorrowData memory _aaveV1BorrowData;
_aaveV1BorrowData.aave = refinanceInternalData.aaveV1;
_aaveV1BorrowData.length = length;
_aaveV1BorrowData.fee = data.debtFee;
_aaveV1BorrowData.target = data.source;
_aaveV1BorrowData.tokens = refinanceInternalData.tokens;
_aaveV1BorrowData.ctokens = refinanceInternalData._ctokens;
_aaveV1BorrowData.amts = data.borrowAmts;
_aaveV1BorrowData.borrowRateModes = data.borrowRateModes;
_aaveV1BorrowData.paybackRateModes = data.paybackRateModes;
refinanceInternalData.paybackAmts = _aaveV1Borrow(_aaveV1BorrowData);
{
_compPayback(
length,
refinanceInternalData._ctokens,
refinanceInternalData.tokens,
refinanceInternalData.paybackAmts
);
refinanceInternalData.depositAmts = _compWithdraw(
length,
refinanceInternalData._ctokens,
refinanceInternalData.tokens,
data.withdrawAmts
);
}
{
AaveV1DepositData memory _aaveV1DepositData;
_aaveV1DepositData.aave = refinanceInternalData.aaveV1;
_aaveV1DepositData.aaveCore = refinanceInternalData.aaveCore;
_aaveV1DepositData.length = length;
_aaveV1DepositData.fee = data.collateralFee;
_aaveV1DepositData.tokens = refinanceInternalData.tokens;
_aaveV1DepositData.amts = refinanceInternalData.depositAmts;
_aaveV1Deposit(_aaveV1DepositData);
}
} else if (data.source == Protocol.Compound && data.target == Protocol.AaveV2) {
AaveV2BorrowData memory _aaveV2BorrowData;
_aaveV2BorrowData.aave = refinanceInternalData.aaveV2;
_aaveV2BorrowData.length = length;
_aaveV2BorrowData.fee = data.debtFee;
_aaveV2BorrowData.target = data.source;
_aaveV2BorrowData.tokens = refinanceInternalData.tokens;
_aaveV2BorrowData.ctokens = refinanceInternalData._ctokens;
_aaveV2BorrowData.amts = data.borrowAmts;
_aaveV2BorrowData.rateModes = data.borrowRateModes;
refinanceInternalData.paybackAmts = _aaveV2Borrow(_aaveV2BorrowData);
_compPayback(length, refinanceInternalData._ctokens, refinanceInternalData.tokens, refinanceInternalData.paybackAmts);
refinanceInternalData.depositAmts = _compWithdraw(
length,
refinanceInternalData._ctokens,
refinanceInternalData.tokens,
data.withdrawAmts
);
_aaveV2Deposit(
refinanceInternalData.aaveV2,
refinanceInternalData.aaveData,
length,
data.collateralFee,
refinanceInternalData.tokens,
refinanceInternalData.depositAmts
);
} else {
revert("invalid-options");
}
}
/**
* @dev Refinance
* @notice Refinancing between AaveV1, AaveV2 and Compound
* @param data refinance data.
*/
function refinance(RefinanceData calldata data)
external payable returns (string memory _eventName, bytes memory _eventParam) {
(_eventName, _eventParam) = _refinance(data);
}
}
contract ConnectV2Refinance is RefinanceResolver {
string public name = "Refinance-v1.0";
}

View File

@ -57,7 +57,7 @@ abstract contract Helpers is DSMath, Basic {
* @dev Collateral Join address is ETH type collateral.
*/
function isEth(address tknAddr) internal pure returns (bool) {
return tknAddr == ethAddr ? true : false;
return tknAddr == wethAddr ? true : false;
}
/**

View File

@ -0,0 +1,6 @@
pragma solidity ^0.7.0;
contract Events {
event LogDeposit(uint256 tokenAmt, uint256 getId, uint256 setId);
event LogWithdraw(uint256 tokenAmt, uint256 getId, uint256 setId);
}

View File

@ -0,0 +1,8 @@
pragma solidity ^0.7.0;
import { TokenInterface } from "../../common/interfaces.sol";
abstract contract Helpers {
TokenInterface constant internal wethContract = TokenInterface(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
}

View File

@ -0,0 +1,65 @@
pragma solidity ^0.7.0;
/**
* @title WETH.
* @dev Wrap and Unwrap WETH.
*/
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { Events } from "./events.sol";
import { Helpers } from "./helpers.sol";
abstract contract Resolver is Events, DSMath, Basic, Helpers {
/**
* @dev Deposit ETH into WETH.
* @notice Wrap ETH into WETH
* @param amt The amount of ETH to deposit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of ETH deposited.
*/
function deposit(
uint256 amt,
uint256 getId,
uint256 setId
) public payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
_amt = _amt == uint(-1) ? address(this).balance : _amt;
wethContract.deposit{value: _amt}();
setUint(setId, _amt);
_eventName = "LogDeposit(uint256,uint256,uint256)";
_eventParam = abi.encode(_amt, getId, setId);
}
/**
* @dev Withdraw ETH from WETH from Smart Account
* @notice Unwrap ETH from WETH
* @param amt The amount of weth to withdraw. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of ETH withdrawn.
*/
function withdraw(
uint amt,
uint getId,
uint setId
) public payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
_amt = _amt == uint(-1) ? wethContract.balanceOf(address(this)) : _amt;
wethContract.approve(wethAddr, _amt);
wethContract.withdraw(_amt);
setUint(setId, _amt);
_eventName = "LogWithdraw(uint256,uint256,uint256)";
_eventParam = abi.encode(_amt, getId, setId);
}
}
contract ConnectV2WETH is Resolver {
string constant public name = "WETH-v1.0";
}

View File

@ -0,0 +1,462 @@
pragma solidity ^0.7.0;
interface TokenInterface {
function approve(address, uint256) external;
function transfer(address, uint) external;
function transferFrom(address, address, uint) external;
function deposit() external payable;
function withdraw(uint) external;
function balanceOf(address) external view returns (uint);
function decimals() external view returns (uint);
}
interface MemoryInterface {
function getUint(uint id) external returns (uint num);
function setUint(uint id, uint val) external;
}
interface InstaMapping {
function cTokenMapping(address) external view returns (address);
function gemJoinMapping(bytes32) external view returns (address);
}
interface AccountInterface {
function enable(address) external;
function disable(address) external;
function isAuth(address) external view returns (bool);
}
abstract contract Stores {
/**
* @dev Return ethereum address
*/
address constant internal ethAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/**
* @dev Return Wrapped ETH address
*/
address constant internal wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
/**
* @dev Return memory variable address
*/
MemoryInterface constant internal instaMemory = MemoryInterface(0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F);
/**
* @dev Return InstaDApp Mapping Addresses
*/
InstaMapping constant internal instaMapping = InstaMapping(0xe81F70Cc7C0D46e12d70efc60607F16bbD617E88);
/**
* @dev Get Uint value from InstaMemory Contract.
*/
function getUint(uint getId, uint val) internal returns (uint returnVal) {
returnVal = getId == 0 ? val : instaMemory.getUint(getId);
}
/**
* @dev Set Uint value in InstaMemory Contract.
*/
function setUint(uint setId, uint val) virtual internal {
if (setId != 0) instaMemory.setUint(setId, val);
}
}
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
contract DSMath {
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function add(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(x, y);
}
function sub(uint x, uint y) internal virtual pure returns (uint z) {
z = SafeMath.sub(x, y);
}
function mul(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.mul(x, y);
}
function div(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.div(x, y);
}
function wmul(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(SafeMath.mul(x, y), WAD / 2) / WAD;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(SafeMath.mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(SafeMath.mul(x, RAY), y / 2) / y;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(SafeMath.mul(x, y), RAY / 2) / RAY;
}
function toInt(uint x) internal pure returns (int y) {
y = int(x);
require(y >= 0, "int-overflow");
}
function toRad(uint wad) internal pure returns (uint rad) {
rad = mul(wad, 10 ** 27);
}
}
abstract contract Basic is DSMath, Stores {
function convert18ToDec(uint _dec, uint256 _amt) internal pure returns (uint256 amt) {
amt = (_amt / 10 ** (18 - _dec));
}
function convertTo18(uint _dec, uint256 _amt) internal pure returns (uint256 amt) {
amt = mul(_amt, 10 ** (18 - _dec));
}
function getTokenBal(TokenInterface token) internal view returns(uint _amt) {
_amt = address(token) == ethAddr ? address(this).balance : token.balanceOf(address(this));
}
function getTokensDec(TokenInterface buyAddr, TokenInterface sellAddr) internal view returns(uint buyDec, uint sellDec) {
buyDec = address(buyAddr) == ethAddr ? 18 : buyAddr.decimals();
sellDec = address(sellAddr) == ethAddr ? 18 : sellAddr.decimals();
}
function encodeEvent(string memory eventName, bytes memory eventParam) internal pure returns (bytes memory) {
return abi.encode(eventName, eventParam);
}
function changeEthAddress(address buy, address sell) internal pure returns(TokenInterface _buy, TokenInterface _sell){
_buy = buy == ethAddr ? TokenInterface(wethAddr) : TokenInterface(buy);
_sell = sell == ethAddr ? TokenInterface(wethAddr) : TokenInterface(sell);
}
function convertEthToWeth(bool isEth, TokenInterface token, uint amount) internal {
if(isEth) token.deposit{value: amount}();
}
function convertWethToEth(bool isEth, TokenInterface token, uint amount) internal {
if(isEth) {
token.approve(address(token), amount);
token.withdraw(amount);
}
}
}
interface RootChainManagerInterface {
function rootToChildToken(address user) external view returns(address);
function depositEtherFor(address user) external payable;
function depositFor(
address user,
address rootToken,
bytes calldata depositData
) external;
function exit(bytes calldata inputData) external;
}
interface DepositManagerProxyInterface {
function depositERC20ForUser(
address _token,
address _user,
uint256 _amount
) external;
}
abstract contract Helpers is DSMath, Basic {
/**
* @dev Polygon POS Bridge ERC20 Predicate
*/
address internal constant erc20Predicate = 0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf;
/**
* @dev Polygon POS Bridge Manager
*/
RootChainManagerInterface internal constant migrator = RootChainManagerInterface(0xA0c68C638235ee32657e8f720a23ceC1bFc77C77);
/**
* @dev Polygon Plasma Bridge Manager
*/
DepositManagerProxyInterface internal constant migratorPlasma = DepositManagerProxyInterface(0x401F6c983eA34274ec46f84D70b31C151321188b);
}
contract Events {
event LogDeposit(
address targetDsa,
address token,
uint256 amt,
uint256 getId,
uint256 setId
);
event LogWithdraw(bytes proof);
}
abstract contract PolygonBridgeResolver is Events, Helpers {
/**
* @dev Deposit assets to the bridge.
* @notice Deposit assets to the bridge.
* @param targetDsa The address to receive the token on Polygon
* @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt The amount of tokens to deposit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens deposit.
*/
function deposit(
address targetDsa,
address token,
uint256 amt,
uint256 getId,
uint256 setId
) external payable {
uint _amt = getUint(getId, amt);
if (token == ethAddr) {
_amt = _amt == uint(-1) ? address(this).balance : _amt;
migrator.depositEtherFor{value: _amt}(targetDsa);
} else {
TokenInterface _token = TokenInterface(token);
_amt = _amt == uint(-1) ? _token.balanceOf(address(this)) : _amt;
if (migrator.rootToChildToken(token) != address(0)) {
_token.approve(erc20Predicate, _amt);
migrator.depositFor(targetDsa, token, abi.encode(_amt));
} else {
_token.approve(address(migratorPlasma), _amt);
migratorPlasma.depositERC20ForUser(token, targetDsa, _amt);
}
}
setUint(setId, _amt);
emit LogDeposit(targetDsa, token, _amt, getId, setId);
}
}
contract ConnectPolygonBridge is PolygonBridgeResolver {
/**
* @dev Connector Details
*/
function connectorID() public pure returns(uint _type, uint _id) {
(_type, _id) = (1, 100);
}
string public constant name = "Polygon-Bridge-v1.1";
}

View File

@ -0,0 +1,119 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
interface ConnectorsInterface {
function chief(address) external view returns (bool);
}
interface IndexInterface {
function master() external view returns (address);
}
contract BytesHelper {
/**
* @dev Convert String to bytes32.
*/
function stringToBytes32(string memory str) internal pure returns (bytes32 result) {
require(bytes(str).length != 0, "String-Empty");
// solium-disable-next-line security/no-inline-assembly
assembly {
result := mload(add(str, 32))
}
}
/**
* @dev Convert bytes32 to String.
*/
function bytes32ToString(bytes32 _bytes32) internal pure returns (string memory) {
bytes32 _temp;
uint count;
for (uint256 i; i < 32; i++) {
_temp = _bytes32[i];
if( _temp != bytes32(0)) {
count += 1;
}
}
bytes memory bytesArray = new bytes(count);
for (uint256 i; i < count; i++) {
bytesArray[i] = (_bytes32[i]);
}
return (string(bytesArray));
}
}
contract Helpers is BytesHelper {
address public constant connectorsV2 = 0x97b0B3A8bDeFE8cB9563a3c610019Ad10DB8aD11;
address public constant instaIndex = 0x2971AdFa57b20E5a416aE5a708A8655A9c74f723;
mapping (bytes32 => StakingData) public stakingMapping;
struct StakingData {
address stakingPool;
address stakingToken;
address rewardToken;
}
event LogAddStakingMapping(
string stakingName,
bytes32 stakingType,
address stakingAddress,
address stakingToken,
address rewardToken
);
event LogRemoveStakingMapping(
string stakingName,
bytes32 stakingType,
address stakingAddress,
address stakingToken,
address rewardToken
);
modifier isChief virtual {
require(
ConnectorsInterface(connectorsV2).chief(msg.sender) ||
IndexInterface(instaIndex).master() == msg.sender, "not-Chief");
_;
}
function addStakingMapping(
string memory stakingName,
address stakingAddress,
address stakingToken,
address rewardToken
) public isChief {
require(stakingAddress != address(0), "stakingAddress-not-vaild");
require(stakingToken != address(0), "stakingToken-not-vaild");
require(rewardToken != address(0), "rewardToken-not-vaild");
require(bytes(stakingName).length <= 32, "Length-exceeds");
bytes32 stakeType = stringToBytes32(stakingName);
require(stakingMapping[stakeType].stakingPool == address(0), "StakingPool-already-added");
require(stakingMapping[stakeType].stakingToken == address(0), "StakingToken-already-added");
require(stakingMapping[stakeType].rewardToken == address(0), "rewardToken-already-added");
stakingMapping[stakeType] = StakingData(
stakingAddress,
stakingToken,
rewardToken
);
emit LogAddStakingMapping(stakingName, stakeType, stakingAddress, stakingToken, rewardToken);
}
function removeStakingMapping(string memory stakingName, address stakingAddress) public isChief {
require(stakingAddress != address(0), "stakingAddress-not-vaild");
bytes32 stakeType = stringToBytes32(stakingName);
require(stakingMapping[stakeType].stakingPool == stakingAddress, "different-staking-pool");
emit LogRemoveStakingMapping(
stakingName,
stakeType,
stakingAddress,
stakingMapping[stakeType].stakingToken,
stakingMapping[stakeType].rewardToken
);
delete stakingMapping[stakeType];
}
}
contract InstaStakingERC20Mapping is Helpers {
string constant public name = "Staking-ERC20-Mapping-v1";
}

View File

@ -33,6 +33,11 @@ abstract contract IncentivesResolver is Helpers, Events {
_amt = incentives.claimRewards(assets, _amt, address(this));
TokenInterface wmatic = TokenInterface(wmaticAddr);
uint256 wmaticAmount = wmatic.balanceOf(address(this));
convertWmaticToMatic(wmaticAmount > 0, wmatic, wmaticAmount);
setUint(setId, _amt);
_eventName = "LogClaimed(address[],uint256,uint256,uint256)";

View File

@ -1,17 +1,27 @@
{
"1" : {
"1INCH-A": "0x6C7256cf7C003dD85683339F75DdE9971f98f2FD",
"1INCH-A": "0x2A6d6d4EE84015F7D64B4d1F66a409bA3f2BAC00",
"1INCH-B": "0x36880391afb430e99d43fe94217446b56d4f2c5b",
"AAVE-V1-A": "0x127d8cD0E2b2E0366D522DeA53A787bfE9002C14",
"AAVE-V2-A": "0x497Bc53507DF17e60F731e9534cff74E8BC9DBb8",
"AUTHORITY-A": "0x6CE3e607C808b4f4C26B7F6aDAeB619e49CAbb25",
"AUTHORITY-A": "0x351Bb32e90C35647Df7a584f3c1a3A0c38F31c68",
"BASIC-A": "0x9926955e0Dd681Dc303370C52f4Ad0a4dd061687",
"COMP-A": "0xB446e325D44C52b93eC122Bf76301f235f90B9c9",
"COMPOUND-A": "0x911F4e4e762AeFA6F2Fc1b24e6B1A928200a88a8",
"MAKERDAO-A": "0x839c2D3aDe63DF5b0b8F3E57D5e145057Ab41556",
"MAKERDAO-A": "0x29AA7b765008b5dDbD687413B7F0D6E9d349F765",
"UNISWAP-A": "0xA4BF319968986D2352FA1c550D781bBFCCE3FcaB",
"POLYGON-BRIDGE-A": "0x697860CeE594c577F18f71cAf3d8B68D913c7366",
"POLYGON-BRIDGE-A": "0x1b79B302132370B434fb7807b36CB72FB0510aD5",
"AAVE-CLAIM-A": "0x611C1FA59Aa1d6352c4C8bD44882063c6aEE85E0",
"AAVE-STAKE-A": "0xf73c94402bc24148b744083ed02654eec2c37d5b"
"AAVE-STAKE-A": "0xf73c94402bc24148b744083ed02654eec2c37d5b",
"G-UNISWAP-A": "0x2fca923c7535083f25f761dcf289d7d81f024dda",
"INST-STAKING-A": "0x37a63939e128d284e0eae5d3e517aad44f5204d4",
"AAVE-V2-IMPORT-B": "0x6fe05374924830B6aC98849f75A3D5766E51Ef10",
"COMPOUND-IMPORT-B": "0xdA101870ca6136539628F28041E1B55baf4EB6C0",
"INSTAPOOL-A": "0x5806Af7AB22E2916fA582Ff05731Bf7C682387B2",
"MAKERDAO-CLAIM-A": "0x2f8cBE650af98602a215b6482F2aD60893C5A4E8",
"WETH-A": "0x22075fa719eFb02Ca3cF298AFa9C974B7465E5D3",
"REFINANCE-A": "0x9eA34bE6dA51aa9F6408FeA79c946FDCFA424442"
"INST-A": "0x52C2C4a0db049255fF345EB9D3Fb1f555b7a924A"
},
"137" : {
"AAVE-V2-A": "0xE84d8010Afc3663919F44685cB53ED88866da3eE",
@ -19,4 +29,5 @@
"BASIC-A": "0x1cAF5EC802ca602E98139AD96A8f2B7BC524264E",
"AAVE-CLAIM-A": "0xC7Cb1dE2721BFC0E0DA1b9D526bCdC54eF1C0eFC",
"PARASWAP-A": "0xFb3a1D56eD56F046721B9aCa749895100754578b"
}
}

View File

@ -2,7 +2,7 @@ require("@nomiclabs/hardhat-waffle");
require("@nomiclabs/hardhat-ethers");
require("@tenderly/hardhat-tenderly");
require("@nomiclabs/hardhat-etherscan");
require("@nomiclabs/hardhat-web3")
require("@nomiclabs/hardhat-web3");
require("hardhat-deploy");
require("hardhat-deploy-ethers");
require("dotenv").config();
@ -12,6 +12,10 @@ const { utils } = require("ethers");
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const ALCHEMY_ID = process.env.ALCHEMY_ID;
if (!process.env.ALCHEMY_ID) {
throw new Error("ENV Variable ALCHEMY_ID not set!");
}
/**
* @type import('hardhat/config').HardhatUserConfig
*/
@ -19,16 +23,16 @@ module.exports = {
solidity: {
compilers: [
{
version: "0.7.6"
version: "0.7.6",
},
{
version: "0.6.0"
version: "0.6.0",
},
{
version: "0.6.2"
version: "0.6.2",
},
{
version: "0.6.5"
version: "0.6.5",
},
],
},
@ -42,27 +46,30 @@ module.exports = {
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
accounts: [`0x${PRIVATE_KEY}`],
timeout: 150000,
gasPrice: parseInt(utils.parseUnits("132", "gwei"))
gasPrice: parseInt(utils.parseUnits("34", "gwei")),
},
hardhat: {
forking: {
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
blockNumber: 12433781,
blockNumber: 12696000,
},
blockGasLimit: 12000000
blockGasLimit: 12000000,
},
matic: {
url: "https://rpc-mainnet.maticvigil.com/",
accounts: [`0x${PRIVATE_KEY}`],
timeout: 150000,
gasPrice: parseInt(utils.parseUnits("1", "gwei"))
gasPrice: parseInt(utils.parseUnits("1", "gwei")),
},
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
apiKey: process.env.ETHERSCAN_API_KEY,
},
tenderly: {
project: process.env.TENDERLY_PROJECT,
username: process.env.TENDERLY_USERNAME
username: process.env.TENDERLY_USERNAME,
},
mocha: {
timeout: 100 * 1000,
},
};

8477
package-lock.json generated

File diff suppressed because it is too large Load Diff

78
scripts/addLiquidity.js Normal file
View File

@ -0,0 +1,78 @@
const { ethers } = require("hardhat");
const impersonateAccounts = require("./impersonate");
const mineTx = async (tx) => {
await (await tx).wait();
};
const tokenMapping = {
usdc: {
impersonateSigner: "0xfcb19e6a322b27c06842a71e8c725399f049ae3a",
address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
abi: [
"function mint(address _to, uint256 _amount) external returns (bool);",
],
process: async function(owner, to, amt) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.mint(to, amt));
},
},
dai: {
impersonateSigner: "0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503",
abi: ["function transfer(address to, uint value)"],
address: "0x6b175474e89094c44da98b954eedeac495271d0f",
process: async function(owner, to, amt) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.transfer(to, amt));
},
},
usdt: {
impersonateSigner: "0xc6cde7c39eb2f0f0095f41570af89efc2c1ea828",
address: "0xdac17f958d2ee523a2206206994597c13d831ec7",
abi: [
"function issue(uint amount)",
"function transfer(address to, uint value)",
],
process: async function(owner, address, amt) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.issue(amt));
await mineTx(contract.transfer(address, amt));
},
},
wbtc: {
impersonateSigner: "0xCA06411bd7a7296d7dbdd0050DFc846E95fEBEB7",
address: "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
abi: ["function mint(address _to, uint256 _amount) public returns (bool)"],
process: async function(owner, address, amt) {
const contract = new ethers.Contract(this.address, this.abi, owner);
await mineTx(contract.mint(address, amt));
},
},
};
module.exports = async (tokenName, address, amt) => {
const [signer] = await ethers.getSigners();
tokenName = tokenName.toLowerCase();
if (!tokenMapping[tokenName]) {
throw new Error(
"Add liquidity doesn't support the following token: ",
tokenName
);
}
const token = tokenMapping[tokenName];
const [impersonatedSigner] = await impersonateAccounts([
token.impersonateSigner,
]);
// send 1 eth to cover any tx costs.
await signer.sendTransaction({
to: impersonatedSigner.address,
value: ethers.utils.parseEther("1"),
});
await token.process(impersonatedSigner, address, amt);
};

View File

@ -0,0 +1 @@
[{"type":"event","name":"LogFlashBorrow","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"tokenAmt","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LogFlashMultiBorrow","inputs":[{"type":"address[]","name":"token","internalType":"address[]","indexed":false},{"type":"uint256[]","name":"tokenAmts","internalType":"uint256[]","indexed":false}],"anonymous":false},{"type":"event","name":"LogFlashMultiPayback","inputs":[{"type":"address[]","name":"token","internalType":"address[]","indexed":false},{"type":"uint256[]","name":"tokenAmts","internalType":"uint256[]","indexed":false}],"anonymous":false},{"type":"event","name":"LogFlashPayback","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"tokenAmt","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"payable","outputs":[{"type":"string","name":"_eventName","internalType":"string"},{"type":"bytes","name":"_eventParam","internalType":"bytes"}],"name":"flashBorrowAndCast","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amt","internalType":"uint256"},{"type":"uint256","name":"route","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"string","name":"_eventName","internalType":"string"},{"type":"bytes","name":"_eventParam","internalType":"bytes"}],"name":"flashMultiBorrowAndCast","inputs":[{"type":"address[]","name":"tokens","internalType":"address[]"},{"type":"uint256[]","name":"amts","internalType":"uint256[]"},{"type":"uint256","name":"route","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"string","name":"_eventName","internalType":"string"},{"type":"bytes","name":"_eventParam","internalType":"bytes"}],"name":"flashMultiPayback","inputs":[{"type":"address[]","name":"tokens","internalType":"address[]"},{"type":"uint256[]","name":"amts","internalType":"uint256[]"},{"type":"uint256[]","name":"getId","internalType":"uint256[]"},{"type":"uint256[]","name":"setId","internalType":"uint256[]"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"string","name":"_eventName","internalType":"string"},{"type":"bytes","name":"_eventParam","internalType":"bytes"}],"name":"flashPayback","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amt","internalType":"uint256"},{"type":"uint256","name":"getId","internalType":"uint256"},{"type":"uint256","name":"setId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract InstaFlashV2Interface"}],"name":"instaPool","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]}]

View File

@ -7,6 +7,7 @@ module.exports = {
"Basic-v1": require("./abi/connectors/basic.json"),
basic: require("./abi/connectors/basic.json"),
auth: require("./abi/connectors/auth.json"),
"INSTAPOOL-A": require("./abi/connectors/instapool.json"),
},
basic: {
erc20: require("./abi/basics/erc20.json"),

View File

@ -2,6 +2,7 @@ module.exports = {
connectors: {
basic: "0xe5398f279175962E56fE4c5E0b62dc7208EF36c6",
auth: "0xd1aff9f2acf800c876c409100d6f39aea93fc3d9",
"INSTAPOOL-A": "0x5806af7ab22e2916fa582ff05731bf7c682387b2",
},
core: {
connectorsV2: "0x97b0B3A8bDeFE8cB9563a3c610019Ad10DB8aD11",

View File

@ -0,0 +1,16 @@
const abis = require("./constant/abis");
const addresses = require("./constant/addresses");
const { web3 } = hre;
const encodeSpells = require("./encodeSpells.js")
module.exports = function (spells) {
const encodeSpellsData = encodeSpells(spells);
const targetType = "string[]";
let argTypes = [targetType, "bytes[]"];
return web3.eth.abi.encodeParameters(argTypes, [
encodeSpellsData[0],
encodeSpellsData[1],
]);
};

View File

@ -1,23 +1,25 @@
const hre = require("hardhat");
const { ethers, waffle } = hre;
const { ethers } = hre;
const addresses = require("./constant/addresses");
const abis = require("./constant/abis");
const { provider, deployContract } = waffle
module.exports = async function() {
const [_, __, ___, wallet3] = await ethers.getSigners();
const instaIndex = new ethers.Contract(
addresses.core.instaIndex,
abis.core.instaIndex,
wallet3
);
module.exports = async function () {
const instaIndex = await ethers.getContractAt(abis.core.instaIndex, addresses.core.instaIndex)
const masterAddress = await instaIndex.master(); // TODO: make it constant?
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [masterAddress],
});
await wallet3.sendTransaction({
to: masterAddress,
value: ethers.utils.parseEther("10"),
});
const masterAddress = await instaIndex.master(); // TODO: make it constant?
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [ masterAddress]
})
const [wallet0, wallet1, wallet2, wallet3] = await ethers.getSigners()
await wallet3.sendTransaction({
to: masterAddress,
value: ethers.utils.parseEther("10")
});
return await ethers.getSigner(masterAddress);
return await ethers.getSigner(masterAddress);
};

15
scripts/impersonate.js Normal file
View File

@ -0,0 +1,15 @@
const { ethers, network } = require("hardhat");
module.exports = async (accounts) => {
const signers = [];
for (const account of accounts) {
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [account],
});
signers.push(await ethers.getSigner(account));
}
return signers;
};

151
test/aave/v1.test.js Normal file
View File

@ -0,0 +1,151 @@
const { expect } = require("chai");
const hre = require("hardhat");
const abis = require("../../scripts/constant/abis");
const addresses = require("../../scripts/constant/addresses");
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector");
const getMasterSigner = require("../../scripts/getMasterSigner");
const buildDSAv2 = require("../../scripts/buildDSAv2");
const ConnectV2AaveV1 = require("../../artifacts/contracts/mainnet/connectors/aave/v1/main.sol/ConnectV2AaveV1.json");
const { parseEther } = require("@ethersproject/units");
const encodeSpells = require("../../scripts/encodeSpells");
const tokens = require("../../scripts/constant/tokens");
const constants = require("../../scripts/constant/constant");
const addLiquidity = require("../../scripts/addLiquidity");
const { ethers } = hre;
describe("Aave V1", function() {
const connectorName = "AAVEV1-TEST-A";
let wallet0, wallet1;
let dsaWallet0;
let instaConnectorsV2;
let connector;
let masterSigner;
before(async () => {
[wallet0, wallet1] = await ethers.getSigners();
masterSigner = await getMasterSigner();
instaConnectorsV2 = await ethers.getContractAt(
abis.core.connectorsV2,
addresses.core.connectorsV2
);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2AaveV1,
signer: masterSigner,
connectors: instaConnectorsV2,
});
console.log("Connector address", connector.address);
});
it("should have contracts deployed", async () => {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!masterSigner.address).to.be.true;
});
describe("DSA wallet setup", function() {
it("Should build DSA v2", async function() {
dsaWallet0 = await buildDSAv2(wallet0.address);
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH into DSA wallet", async function() {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: parseEther("10"),
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(
parseEther("10")
);
});
});
describe("Main", function() {
it("should deposit ETH in Aave V1", async function() {
const amt = parseEther("1");
const spells = [
{
connector: connectorName,
method: "deposit",
args: [tokens.eth.address, amt, 0, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.eq(
parseEther("9")
);
});
it("Should borrow and payback DAI from Aave V1", async function() {
const amt = parseEther("100"); // 100 DAI
// add a little amount of dai to cover any shortfalls
await addLiquidity("dai", dsaWallet0.address, parseEther("1"));
const spells = [
{
connector: connectorName,
method: "borrow",
args: [tokens.dai.address, amt, 0, 0],
},
{
connector: connectorName,
method: "payback",
// FIXME: we need to pass max_value because of roundoff/shortfall errors
args: [tokens.dai.address, constants.max_value, 0, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(
ethers.utils.parseEther("9")
);
});
it("Should deposit all ETH in Aave V1", async function() {
const spells = [
{
connector: connectorName,
method: "deposit",
args: [tokens.eth.address, constants.max_value, 0, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(
ethers.utils.parseEther("0")
);
});
it("Should withdraw all ETH from Aave V1", async function() {
const spells = [
{
connector: connectorName,
method: "withdraw",
args: [tokens.eth.address, constants.max_value, 0, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(
ethers.utils.parseEther("10")
);
});
});
});

214
test/aave/v2.test.js Normal file
View File

@ -0,0 +1,214 @@
const { expect } = require("chai");
const hre = require("hardhat");
const abis = require("../../scripts/constant/abis");
const addresses = require("../../scripts/constant/addresses");
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector");
const getMasterSigner = require("../../scripts/getMasterSigner");
const buildDSAv2 = require("../../scripts/buildDSAv2");
const ConnectV2AaveV2 = require("../../artifacts/contracts/mainnet/connectors/aave/v2/main.sol/ConnectV2AaveV2.json");
const { parseEther } = require("@ethersproject/units");
const encodeSpells = require("../../scripts/encodeSpells");
const tokens = require("../../scripts/constant/tokens");
const constants = require("../../scripts/constant/constant");
const addLiquidity = require("../../scripts/addLiquidity");
const { ethers } = hre;
describe("Aave V2", function() {
const connectorName = "AAVEV2-TEST-A";
let wallet0, wallet1;
let dsaWallet0;
let instaConnectorsV2;
let connector;
let masterSigner;
before(async () => {
[wallet0, wallet1] = await ethers.getSigners();
masterSigner = await getMasterSigner();
instaConnectorsV2 = await ethers.getContractAt(
abis.core.connectorsV2,
addresses.core.connectorsV2
);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: ConnectV2AaveV2,
signer: masterSigner,
connectors: instaConnectorsV2,
});
console.log("Connector address", connector.address);
});
it("should have contracts deployed", async () => {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!masterSigner.address).to.be.true;
});
describe("DSA wallet setup", function() {
it("Should build DSA v2", async function() {
dsaWallet0 = await buildDSAv2(wallet0.address);
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH into DSA wallet", async function() {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: parseEther("10"),
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(
parseEther("10")
);
});
});
describe("Main", function() {
it("should deposit ETH in Aave V2", async function() {
const amt = parseEther("1");
const spells = [
{
connector: connectorName,
method: "deposit",
args: [tokens.eth.address, amt, 0, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.eq(
parseEther("9")
);
});
it("Should borrow and payback DAI from Aave V2", async function() {
const amt = parseEther("100"); // 100 DAI
const setId = "83478237";
const spells = [
{
connector: connectorName,
method: "borrow",
args: [tokens.dai.address, amt, 2, 0, setId],
},
{
connector: connectorName,
method: "payback",
args: [tokens.dai.address, amt, 2, setId, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(
ethers.utils.parseEther("9")
);
});
it("Should borrow and payback half DAI from Aave V2", async function() {
const amt = parseEther("100"); // 100 DAI
// const setId = "83478237";
await addLiquidity("dai", dsaWallet0.address, parseEther("1"));
let spells = [
{
connector: connectorName,
method: "borrow",
args: [tokens.dai.address, amt, 2, 0, 0],
},
{
connector: connectorName,
method: "payback",
args: [tokens.dai.address, amt.div(2), 2, 0, 0],
},
];
let tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(
ethers.utils.parseEther("9")
);
spells = [
{
connector: connectorName,
method: "payback",
args: [tokens.dai.address, constants.max_value, 2, 0, 0],
},
];
tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(
ethers.utils.parseEther("9")
);
});
it("Should deposit all ETH in Aave V2", async function() {
const spells = [
{
connector: connectorName,
method: "deposit",
args: [tokens.eth.address, constants.max_value, 0, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(
ethers.utils.parseEther("0")
);
});
it("Should withdraw all ETH from Aave V2", async function() {
const spells = [
{
connector: connectorName,
method: "withdraw",
args: [tokens.eth.address, constants.max_value, 0, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(
ethers.utils.parseEther("10")
);
});
it("should deposit and withdraw", async () => {
const amt = parseEther("1"); // 1 eth
const setId = "834782373";
const spells = [
{
connector: connectorName,
method: "deposit",
args: [tokens.eth.address, amt, 0, setId],
},
{
connector: connectorName,
method: "withdraw",
args: [tokens.eth.address, amt, setId, 0],
},
];
const tx = await dsaWallet0
.connect(wallet0)
.cast(...encodeSpells(spells), wallet1.address);
await tx.wait();
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(
ethers.utils.parseEther("10")
);
});
});
});

View File

@ -124,4 +124,4 @@ describe("Compound", function () {
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
});
})
})
})

View File

@ -0,0 +1,109 @@
const { expect } = require("chai");
const hre = require("hardhat");
const { web3, deployments, waffle, ethers } = hre;
const { provider, deployContract } = waffle
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js")
const buildDSAv2 = require("../../scripts/buildDSAv2")
const encodeSpells = require("../../scripts/encodeSpells.js")
const encodeFlashcastData = require("../../scripts/encodeFlashcastData.js")
const getMasterSigner = require("../../scripts/getMasterSigner")
const addresses = require("../../scripts/constant/addresses");
const abis = require("../../scripts/constant/abis");
const constants = require("../../scripts/constant/constant");
const tokens = require("../../scripts/constant/tokens");
const connectV2CompoundArtifacts = require("../../artifacts/contracts/mainnet/connectors/compound/main.sol/ConnectV2Compound.json")
describe("Instapool", function () {
const connectorName = "COMPOUND-TEST-A"
let dsaWallet0
let masterSigner;
let instaConnectorsV2;
let connector;
const wallets = provider.getWallets()
const [wallet0, wallet1, wallet2, wallet3] = wallets
before(async () => {
masterSigner = await getMasterSigner(wallet3)
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: connectV2CompoundArtifacts,
signer: masterSigner,
connectors: instaConnectorsV2
})
console.log("Connector address", connector.address)
})
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!masterSigner.address).to.be.true;
});
describe("DSA wallet setup", function () {
it("Should build DSA v2", async function () {
dsaWallet0 = await buildDSAv2(wallet0.address)
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
});
});
describe("Main", function () {
it("Should take 100 ETH flashloan from Instapool", async function () {
const amount = ethers.utils.parseEther("1") // 1 ETH
const flashloanAmount = ethers.utils.parseEther("100") // 100 ETH
const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
const IdOne = "2878734423"
const IdTwo = "783243246"
const spells = [
{
connector: connectorName,
method: "deposit",
args: ["ETH-A", flashloanAmount, 0, IdOne]
},
{
connector: connectorName,
method: "withdraw",
args: ["ETH-A", amount, IdOne, IdTwo]
},
{
connector: "INSTAPOOL-A",
method: "flashPayback",
args: [ethAddress, flashloanAmount, IdTwo, 0],
}
]
const calldata = encodeFlashcastData(spells);
const spells2 = [
{
connector: "INSTAPOOL-A",
method: "flashBorrowAndCast",
args: [
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
flashloanAmount,
0, // route
calldata,
],
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells2), wallet1.address)
const receipt = await tx.wait()
});
})
})