More connectors

This commit is contained in:
Mubaris NK 2021-02-13 14:41:50 +05:30
parent b8f007c589
commit 4ee46422cf
No known key found for this signature in database
GPG Key ID: 9AC09AD0F8D68561
15 changed files with 1153 additions and 0 deletions

View File

@ -0,0 +1,8 @@
pragma solidity ^0.7.0;
contract Events {
event LogDeposit(address indexed token, uint marketId, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogWithdraw(address indexed token, uint marketId, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogBorrow(address indexed token, uint marketId, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogPayback(address indexed token, uint marketId, uint256 tokenAmt, uint256 getId, uint256 setId);
}

View File

@ -0,0 +1,72 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { SoloMarginContract } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev Solo Margin
*/
SoloMarginContract internal constant solo = SoloMarginContract(0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e);
/**
* @dev Get Dydx Actions args.
*/
function getActionsArgs(uint256 marketId, uint256 amt, bool sign) internal view returns (SoloMarginContract.ActionArgs[] memory) {
SoloMarginContract.ActionArgs[] memory actions = new SoloMarginContract.ActionArgs[](1);
SoloMarginContract.AssetAmount memory amount = SoloMarginContract.AssetAmount(
sign,
SoloMarginContract.AssetDenomination.Wei,
SoloMarginContract.AssetReference.Delta,
amt
);
bytes memory empty;
SoloMarginContract.ActionType action = sign ? SoloMarginContract.ActionType.Deposit : SoloMarginContract.ActionType.Withdraw;
actions[0] = SoloMarginContract.ActionArgs(
action,
0,
amount,
marketId,
0,
address(this),
0,
empty
);
return actions;
}
/**
* @dev Get Dydx Acccount arg
*/
function getAccountArgs() internal view returns (SoloMarginContract.Info[] memory) {
SoloMarginContract.Info[] memory accounts = new SoloMarginContract.Info[](1);
accounts[0] = (SoloMarginContract.Info(address(this), 0));
return accounts;
}
/**
* @dev Get Dydx Position
*/
function getDydxPosition(uint256 marketId) internal returns (uint tokenBal, bool tokenSign) {
SoloMarginContract.Wei memory tokenWeiBal = solo.getAccountWei(getAccountArgs()[0], marketId);
tokenBal = tokenWeiBal.value;
tokenSign = tokenWeiBal.sign;
}
/**
* @dev Get Dydx Market ID from token Address
*/
function getMarketId(address token) internal view returns (uint _marketId) {
uint markets = solo.getNumMarkets();
address _token = token == ethAddr ? wethAddr : token;
for (uint i = 0; i < markets; i++) {
if (_token == solo.getMarketTokenAddress(i)) {
_marketId = i;
break;
}
}
}
}

View File

@ -0,0 +1,61 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
interface SoloMarginContract {
struct Info {
address owner;
uint256 number;
}
enum ActionType {
Deposit,
Withdraw,
Transfer,
Buy,
Sell,
Trade,
Liquidate,
Vaporize,
Call
}
enum AssetDenomination {
Wei,
Par
}
enum AssetReference {
Delta,
Target
}
struct AssetAmount {
bool sign;
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
struct ActionArgs {
ActionType actionType;
uint256 accountId;
AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
bytes data;
}
struct Wei {
bool sign;
uint256 value;
}
function operate(Info[] calldata accounts, ActionArgs[] calldata actions) external;
function getAccountWei(Info calldata account, uint256 marketId) external returns (Wei memory);
function getNumMarkets() external view returns (uint256);
function getMarketTokenAddress(uint256 marketId) external view returns (address);
}

View File

@ -0,0 +1,160 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { TokenInterface } from "../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract DyDxResolver is Events, Helpers {
/**
* @dev Deposit ETH/ERC20_Token.
* @param token token address to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt token amount to deposit.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function deposit(
address token,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _marketId = getMarketId(token);
(uint depositedAmt, bool sign) = getDydxPosition(_marketId);
require(depositedAmt == 0 || sign, "token-borrowed");
if (token == ethAddr) {
TokenInterface tokenContract = TokenInterface(wethAddr);
_amt = _amt == uint(-1) ? address(this).balance : _amt;
tokenContract.deposit{value: _amt}();
tokenContract.approve(address(solo), _amt);
} else {
TokenInterface tokenContract = TokenInterface(token);
_amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt;
tokenContract.approve(address(solo), _amt);
}
solo.operate(getAccountArgs(), getActionsArgs(_marketId, _amt, true));
setUint(setId, _amt);
_eventName = "LogDeposit(address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _marketId, _amt, getId, setId);
}
/**
* @dev Withdraw ETH/ERC20_Token.
* @param token token address to withdraw.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt token amount to withdraw.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function withdraw(
address token,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _marketId = getMarketId(token);
(uint depositedAmt, bool sign) = getDydxPosition(_marketId);
require(sign, "try-payback");
_amt = _amt == uint(-1) ? depositedAmt : _amt;
require(_amt <= depositedAmt, "withdraw-exceeds");
solo.operate(getAccountArgs(), getActionsArgs(_marketId, _amt, false));
if (token == ethAddr) {
TokenInterface tokenContract = TokenInterface(wethAddr);
tokenContract.approve(address(tokenContract), _amt);
tokenContract.withdraw(_amt);
}
setUint(setId, _amt);
_eventName = "LogWithdraw(address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _marketId, _amt, getId, setId);
}
/**
* @dev Borrow ETH/ERC20_Token.
* @param token token address to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt token amount to borrow.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function borrow(
address token,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _marketId = getMarketId(token);
(uint borrowedAmt, bool sign) = getDydxPosition(_marketId);
require(borrowedAmt == 0 || !sign, "token-deposited");
solo.operate(getAccountArgs(), getActionsArgs(_marketId, _amt, false));
if (token == ethAddr) {
TokenInterface tokenContract = TokenInterface(wethAddr);
tokenContract.approve(address(tokenContract), _amt);
tokenContract.withdraw(_amt);
}
setUint(setId, _amt);
_eventName = "LogBorrow(address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _marketId, _amt, getId, setId);
}
/**
* @dev Payback borrowed ETH/ERC20_Token.
* @param token token address to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt token amount to payback.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function payback(
address token,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _marketId = getMarketId(token);
(uint borrowedAmt, bool sign) = getDydxPosition(_marketId);
require(!sign, "try-withdraw");
_amt = _amt == uint(-1) ? borrowedAmt : _amt;
require(_amt <= borrowedAmt, "payback-exceeds");
if (token == ethAddr) {
TokenInterface tokenContract = TokenInterface(wethAddr);
require(address(this).balance >= _amt, "not-enough-eth");
tokenContract.deposit{value: _amt}();
tokenContract.approve(address(solo), _amt);
} else {
TokenInterface tokenContract = TokenInterface(token);
require(tokenContract.balanceOf(address(this)) >= _amt, "not-enough-token");
tokenContract.approve(address(solo), _amt);
}
solo.operate(getAccountArgs(), getActionsArgs(_marketId, _amt, true));
setUint(setId, _amt);
_eventName = "LogPayback(address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _marketId, _amt, getId, setId);
}
}
contract ConnectDydx is DyDxResolver {
string public name = "Dydx-v1";
}

View File

@ -0,0 +1,5 @@
pragma solidity ^0.7.0;
contract Events {
event LogDydxFlashLoan(address indexed token, uint256 tokenAmt);
}

View File

@ -0,0 +1,5 @@
pragma solidity ^0.7.0;
interface DydxFlashInterface {
function initiateFlashLoan(address _token, uint256 _amount, bytes calldata data) external;
}

View File

@ -0,0 +1,38 @@
pragma solidity ^0.7.0;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { TokenInterface, AccountInterface } from "../../common/interfaces.sol";
import { Events } from "./events.sol";
import { DydxFlashInterface } from "./interface.sol";
abstract contract FlashLoanResolver is DSMath, Basic, Events {
address internal constant dydxAddr = address(0); // check9898 - change to dydx flash contract address
/**
* @dev Borrow Flashloan and Cast spells.
* @param token Token Address.
* @param tokenAmt Token Amount.
* @param data targets & data for cast.
*/
function borrowAndCast(
address token,
uint tokenAmt,
bytes memory data
) public payable returns (string memory _eventName, bytes memory _eventParam) {
AccountInterface(address(this)).enable(dydxAddr);
address _token = token == ethAddr ? wethAddr : token;
DydxFlashInterface(dydxAddr).initiateFlashLoan(_token, tokenAmt, data);
AccountInterface(address(this)).disable(dydxAddr);
_eventName = "LogDydxFlashLoan(address,uint256)";
_eventParam = abi.encode(token, tokenAmt);
}
}
contract ConnectDydxFlashLoan is FlashLoanResolver {
string public constant name = "dydx-flashloan-v1";
}

View File

@ -0,0 +1,30 @@
pragma solidity ^0.7.0;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
abstract contract FeeResolver is DSMath, Basic {
/**
* @dev Calculate fee
*/
function calculateFee(
uint amount,
uint fee,
uint getId,
uint setId,
uint setIdFee
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amount);
uint feeAmt = wmul(_amt, fee);
uint totalAmt = add(_amt, feeAmt);
setUint(setId, totalAmt);
setUint(setIdFee, feeAmt);
}
}
contract ConnectFee is FeeResolver {
string public constant name = "Fee-v1";
}

View File

@ -0,0 +1,45 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { Task, Provider, TaskSpec, TaskReceipt } from "./interface.sol";
contract Events {
event LogMultiProvide(
address indexed executor,
TaskSpec[] indexed taskspecs,
address[] indexed modules,
uint256 ethToDeposit,
uint256 getId,
uint256 setId
);
event LogSubmitTask(
Provider indexed provider,
Task indexed task,
uint256 indexed expiryDate
);
event LogSubmitTaskCycle(
Provider indexed provider,
Task[] indexed tasks,
uint256 indexed expiryDate
);
event LogSubmitTaskChain(
Provider indexed provider,
Task[] indexed tasks,
uint256 indexed expiryDate
);
event LogMultiUnprovide(
TaskSpec[] indexed taskspecs,
address[] indexed modules,
uint256 ethToWithdraw,
uint256 getId,
uint256 setId
);
event LogMultiCancelTasks(
TaskReceipt[] indexed taskReceipt
);
}

View File

@ -0,0 +1,119 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
// Gelato Data Types
struct Provider {
address addr; // if msg.sender == provider => self-Provider
address module; // e.g. DSA Provider Module
}
struct Condition {
address inst; // can be AddressZero for self-conditional Actions
bytes data; // can be bytes32(0) for self-conditional Actions
}
enum Operation { Call, Delegatecall }
enum DataFlow { None, In, Out, InAndOut }
struct Action {
address addr;
bytes data;
Operation operation;
DataFlow dataFlow;
uint256 value;
bool termsOkCheck;
}
struct Task {
Condition[] conditions; // optional
Action[] actions;
uint256 selfProviderGasLimit; // optional: 0 defaults to gelatoMaxGas
uint256 selfProviderGasPriceCeil; // optional: 0 defaults to NO_CEIL
}
struct TaskReceipt {
uint256 id;
address userProxy;
Provider provider;
uint256 index;
Task[] tasks;
uint256 expiryDate;
uint256 cycleId; // auto-filled by GelatoCore. 0 for non-cyclic/chained tasks
uint256 submissionsLeft;
}
struct TaskSpec {
address[] conditions; // Address: optional AddressZero for self-conditional actions
Action[] actions;
uint256 gasPriceCeil;
}
// Gelato Interface
interface IGelatoInterface {
/**
* @dev API to submit a single Task.
*/
function submitTask(
Provider calldata _provider,
Task calldata _task,
uint256 _expiryDate
)
external;
/**
* @dev A Gelato Task Cycle consists of 1 or more Tasks that automatically submit
* the next one, after they have been executed, where the total number of tasks can
* be only be an even number
*/
function submitTaskCycle(
Provider calldata _provider,
Task[] calldata _tasks,
uint256 _expiryDate,
uint256 _cycles
)
external;
/**
* @dev A Gelato Task Chain consists of 1 or more Tasks that automatically submit
* the next one, after they have been executed, where the total number of tasks can
* be an odd number
*/
function submitTaskChain(
Provider calldata _provider,
Task[] calldata _tasks,
uint256 _expiryDate,
uint256 _sumOfRequestedTaskSubmits
)
external;
/**
* @dev Cancel multiple tasks at once
*/
function multiCancelTasks(TaskReceipt[] calldata _taskReceipts) external;
/**
* @dev Whitelist new executor, TaskSpec(s) and Module(s) in one tx
*/
function multiProvide(
address _executor,
TaskSpec[] calldata _taskSpecs,
address[] calldata _modules
)
external
payable;
/**
* @dev De-Whitelist TaskSpec(s), Module(s) and withdraw funds from gelato in one tx
*/
function multiUnprovide(
uint256 _withdrawAmount,
TaskSpec[] calldata _taskSpecs,
address[] calldata _modules
)
external;
}

View File

@ -0,0 +1,167 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { IGelatoInterface, Task, Provider, TaskSpec, TaskReceipt } from "./interface.sol";
import { Events } from "./events.sol";
abstract contract GelatoResolver is DSMath, Basic, Events {
IGelatoInterface internal constant gelato = IGelatoInterface(0x1d681d76ce96E4d70a88A00EBbcfc1E47808d0b8);
// ===== Gelato ENTRY APIs ======
/**
* @dev Enables first time users to pre-fund eth, whitelist an executor & register the
* ProviderModuleDSA.sol to be able to use Gelato
* @param _executor address of single execot node or gelato'S decentralized execution market
* @param _taskSpecs enables external providers to whitelist TaskSpecs on gelato
* @param _modules address of ProviderModuleDSA
* @param _ethToDeposit amount of eth to deposit on Gelato, only for self-providers
*/
function multiProvide(
address _executor,
TaskSpec[] calldata _taskSpecs,
address[] calldata _modules,
uint256 _ethToDeposit,
uint256 _getId,
uint256 _setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint256 ethToDeposit = getUint(_getId, _ethToDeposit);
ethToDeposit = ethToDeposit == uint(-1) ? address(this).balance : ethToDeposit;
gelato.multiProvide{value: ethToDeposit}(
_executor,
_taskSpecs,
_modules
);
setUint(_setId, ethToDeposit);
_eventName = "LogMultiProvide(address,TaskSpec[],address[],uint256,uint256,uint256)";
_eventParam = abi.encode(_executor, _taskSpecs, _modules, ethToDeposit, _getId, _setId);
}
/**
* @dev Submits a single, one-time task to Gelato
* @param _provider Consists of proxy module address (DSA) and provider address ()
* who will pay for the transaction execution
* @param _task Task specifying the condition and the action connectors
* @param _expiryDate Default 0, othweise timestamp after which the task expires
*/
function submitTask(
Provider calldata _provider,
Task calldata _task,
uint256 _expiryDate
) external payable returns (string memory _eventName, bytes memory _eventParam) {
gelato.submitTask(_provider, _task, _expiryDate);
_eventName = "LogSubmitTask(Provider,Task,uint256)";
_eventParam = abi.encode(_provider, _task, _expiryDate);
}
/**
* @dev Submits single or mulitple Task Sequences to Gelato
* @param _provider Consists of proxy module address (DSA) and provider address ()
* who will pay for the transaction execution
* @param _tasks A sequence of Tasks, can be a single or multiples
* @param _expiryDate Default 0, othweise timestamp after which the task expires
* @param _cycles How often the Task List should be executed, e.g. 5 times
*/
function submitTaskCycle(
Provider calldata _provider,
Task[] calldata _tasks,
uint256 _expiryDate,
uint256 _cycles
) external payable returns (string memory _eventName, bytes memory _eventParam) {
gelato.submitTaskCycle(
_provider,
_tasks,
_expiryDate,
_cycles
);
_eventName = "LogSubmitTaskCycle(Provider,Task[],uint256)";
_eventParam = abi.encode(_provider, _tasks, _expiryDate);
}
/**
* @dev Submits single or mulitple Task Chains to Gelato
* @param _provider Consists of proxy module address (DSA) and provider address ()
* who will pay for the transaction execution
* @param _tasks A sequence of Tasks, can be a single or multiples
* @param _expiryDate Default 0, othweise timestamp after which the task expires
* @param _sumOfRequestedTaskSubmits The TOTAL number of Task auto-submits
* that should have occured once the cycle is complete
*/
function submitTaskChain(
Provider calldata _provider,
Task[] calldata _tasks,
uint256 _expiryDate,
uint256 _sumOfRequestedTaskSubmits
) external payable returns (string memory _eventName, bytes memory _eventParam) {
gelato.submitTaskChain(
_provider,
_tasks,
_expiryDate,
_sumOfRequestedTaskSubmits
);
_eventName = "LogSubmitTaskChain(Provider,Task[],uint256)";
_eventParam = abi.encode(_provider, _tasks, _expiryDate);
}
// ===== Gelato EXIT APIs ======
/**
* @dev Withdraws funds from Gelato, de-whitelists TaskSpecs and Provider Modules
* in one tx
* @param _withdrawAmount Amount of ETH to withdraw from Gelato
* @param _taskSpecs List of Task Specs to de-whitelist, default empty []
* @param _modules List of Provider Modules to de-whitelist, default empty []
*/
function multiUnprovide(
uint256 _withdrawAmount,
TaskSpec[] calldata _taskSpecs,
address[] calldata _modules,
uint256 _getId,
uint256 _setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint256 withdrawAmount = getUint(_getId, _withdrawAmount);
uint256 balanceBefore = address(this).balance;
gelato.multiUnprovide(
withdrawAmount,
_taskSpecs,
_modules
);
uint256 actualWithdrawAmount = sub(address(this).balance, balanceBefore);
setUint(_setId, actualWithdrawAmount);
_eventName = "LogMultiUnprovide(TaskSpec[],address[],uint256,uint256,uint256)";
_eventParam = abi.encode(_taskSpecs, _modules, actualWithdrawAmount, _getId, _setId);
}
/**
* @dev Cancels outstanding Tasks
* @param _taskReceipts List of Task Receipts to cancel
*/
function multiCancelTasks(TaskReceipt[] calldata _taskReceipts)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
gelato.multiCancelTasks(_taskReceipts);
_eventName = "LogMultiCancelTasks(TaskReceipt[])";
_eventParam = abi.encode(_taskReceipts);
}
}
contract ConnectGelato is GelatoResolver {
string public name = "Gelato-v1.0";
}

View File

@ -0,0 +1,53 @@
pragma solidity ^0.7.0;
contract Events {
event LogDepositLiquidity(address indexed token, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogWithdrawLiquidity(address indexed token, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogFlashBorrow(
address indexed token,
uint256 tokenAmt,
uint256 getId,
uint256 setId
);
event LogFlashPayback(
address indexed token,
uint256 tokenAmt,
uint256 feeCollected,
uint256 getId,
uint256 setId
);
event LogFlashPaybackOrigin(
address indexed origin,
address indexed token,
uint256 tokenAmt,
uint256 feeCollected,
uint256 originFeeAmt,
uint256 getId,
uint256 setId
);
event LogMultiBorrow(
address[] tokens,
uint256[] amts,
uint256[] getId,
uint256[] setId
);
event LogMultiPayback(
address[] tokens,
uint256[] getId,
uint256[] setId
);
event LogMultiPaybackOrigin(
address indexed origin,
address[] tokens,
// uint256[] amts,
// uint256[] feeCollected,
// uint256[] originFeeAmt,
uint256[] getId,
uint256[] setId
);
}

View File

@ -0,0 +1,81 @@
pragma solidity ^0.7.0;
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { InstaPoolFeeInterface, LiqudityInterface } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
using SafeERC20 for IERC20;
/**
* @dev Instapool Helper
*/
LiqudityInterface internal constant instaPool = LiqudityInterface(0x06cB7C24990cBE6b9F99982f975f9147c000fec6);
/**
* @dev Instapool Fee
*/
InstaPoolFeeInterface internal constant instaPoolFee = InstaPoolFeeInterface(0xAaA91046C1D1a210017e36394C83bD5070dadDa5);
function _transfer(address payable to, IERC20 token, uint _amt) internal {
address(token) == ethAddr ?
to.transfer(_amt) :
token.safeTransfer(to, _amt);
}
function _getBalance(IERC20 token) internal view returns (uint256) {
return address(token) == ethAddr ?
address(this).balance :
token.balanceOf(address(this));
}
function calculateTotalFeeAmt(IERC20 token, uint amt) internal view returns (uint totalAmt) {
uint fee = instaPoolFee.fee();
uint flashAmt = instaPool.borrowedToken(address(token));
if (fee == 0) {
totalAmt = amt;
} else {
uint feeAmt = wmul(flashAmt, fee);
totalAmt = add(amt, feeAmt);
}
}
function calculateFeeAmt(IERC20 token, uint amt) internal view returns (address feeCollector, uint feeAmt) {
uint fee = instaPoolFee.fee();
feeCollector = instaPoolFee.feeCollector();
if (fee == 0) {
feeAmt = 0;
} else {
feeAmt = wmul(amt, fee);
uint totalAmt = add(amt, feeAmt);
uint totalBal = _getBalance(token);
require(totalBal >= totalAmt - 10, "Not-enough-balance");
feeAmt = totalBal > totalAmt ? feeAmt : sub(totalBal, amt);
}
}
function calculateFeeAmtOrigin(IERC20 token, uint amt)
internal
view
returns (
address feeCollector,
uint poolFeeAmt,
uint originFee
)
{
uint feeAmt;
(feeCollector, feeAmt) = calculateFeeAmt(token, amt);
if (feeAmt == 0) {
poolFeeAmt = 0;
originFee = 0;
} else {
originFee = wmul(feeAmt, 20 * 10 ** 16); // 20%
poolFeeAmt = sub(feeAmt, originFee);
}
}
}

View File

@ -0,0 +1,31 @@
pragma solidity ^0.7.0;
interface LiqudityInterface {
function deposit(address, uint) external payable;
function withdraw(address, uint) external;
function accessLiquidity(address[] calldata, uint[] calldata) external;
function returnLiquidity(address[] calldata) external payable;
function isTknAllowed(address) external view returns(bool);
function tknToCTkn(address) external view returns(address);
function liquidityBalance(address, address) external view returns(uint);
function borrowedToken(address) external view returns(uint);
}
interface InstaPoolFeeInterface {
function fee() external view returns(uint);
function feeCollector() external view returns(address);
}
interface CTokenInterface {
function borrowBalanceCurrent(address account) external returns (uint);
function balanceOf(address owner) external view returns (uint256 balance);
function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint); // For ERC20
}
interface CETHInterface {
function borrowBalanceCurrent(address account) external returns (uint);
function repayBorrowBehalf(address borrower) external payable;
}

View File

@ -0,0 +1,278 @@
pragma solidity ^0.7.0;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { TokenInterface } from "../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract LiquidityManage is Helpers, Events {
/**
* @dev Deposit Liquidity in InstaPool.
* @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt token amount.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function deposit(
address token,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint ethAmt;
if (token == ethAddr) {
_amt = _amt == uint(-1) ? address(this).balance : _amt;
ethAmt = _amt;
} else {
IERC20 tokenContract = IERC20(token);
_amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt;
tokenContract.approve(address(instaPool), _amt);
}
instaPool.deposit{value: ethAmt}(token, _amt);
setUint(setId, _amt);
emit LogDepositLiquidity(token, _amt, getId, setId);
_eventName = "LogDepositLiquidity(address,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _amt, getId, setId);
}
/**
* @dev Withdraw Liquidity in InstaPool.
* @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt token amount.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function withdraw(
address token,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
instaPool.withdraw(token, _amt);
setUint(setId, _amt);
_eventName = "LogWithdrawLiquidity(address,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _amt, getId, setId);
}
}
abstract contract LiquidityAccessHelper is LiquidityManage {
/**
* @dev Add Fee Amount to borrowed flashloan/
* @param amt Get token amount at this ID from `InstaMemory` Contract.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function addFeeAmount(address token, uint amt, uint getId, uint setId) external payable {
uint _amt = getUint(getId, amt);
require(_amt != 0, "amt-is-0");
uint totalFee = calculateTotalFeeAmt(IERC20(token), _amt);
setUint(setId, totalFee);
}
}
contract LiquidityAccess is LiquidityAccessHelper {
/**
* @dev Access Token Liquidity from InstaPool.
* @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amt token amount.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function flashBorrow(
address token,
uint amt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
address[] memory _tknAddrs = new address[](1);
_tknAddrs[0] = token;
uint[] memory _amts = new uint[](1);
_amts[0] = _amt;
instaPool.accessLiquidity(_tknAddrs, _amts);
setUint(setId, _amt);
_eventName = "LogFlashBorrow(address,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _amt, getId, setId);
}
/**
* @dev Return Token Liquidity from InstaPool.
* @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function flashPayback(
address token,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = instaPool.borrowedToken(token);
IERC20 tokenContract = IERC20(token);
(address feeCollector, uint feeAmt) = calculateFeeAmt(tokenContract, _amt);
address[] memory _tknAddrs = new address[](1);
_tknAddrs[0] = token;
_transfer(payable(address(instaPool)), tokenContract, _amt);
instaPool.returnLiquidity(_tknAddrs);
if (feeAmt > 0) _transfer(payable(feeCollector), tokenContract, feeAmt);
setUint(setId, _amt);
_eventName = "LogFlashPayback(address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(token, _amt, feeAmt, getId, setId);
}
/**
* @dev Return Token Liquidity from InstaPool and Transfer 20% of Collected Fee to `origin`.
* @param origin origin address to transfer 20% of the collected fee.
* @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function flashPaybackOrigin(
address origin,
address token,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
require(origin != address(0), "origin-is-address(0)");
uint _amt = instaPool.borrowedToken(token);
IERC20 tokenContract = IERC20(token);
(address feeCollector, uint poolFeeAmt, uint originFeeAmt) = calculateFeeAmtOrigin(tokenContract, _amt);
address[] memory _tknAddrs = new address[](1);
_tknAddrs[0] = token;
_transfer(payable(address(instaPool)), tokenContract, _amt);
instaPool.returnLiquidity(_tknAddrs);
if (poolFeeAmt > 0) {
_transfer(payable(feeCollector), tokenContract, poolFeeAmt);
_transfer(payable(origin), tokenContract, originFeeAmt);
}
setUint(setId, _amt);
_eventName = "LogFlashPaybackOrigin(address,address,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(origin, token, _amt, poolFeeAmt, originFeeAmt, getId, setId);
}
}
contract LiquidityAccessMulti is LiquidityAccess {
/**
* @dev Access Multiple Token liquidity from InstaPool.
* @param tokens Array of token addresses.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param amts Array of token amount.
* @param getId get token amounts at this IDs from `InstaMemory` Contract.
* @param setId set token amounts at this IDs in `InstaMemory` Contract.
*/
function flashMultiBorrow(
address[] calldata tokens,
uint[] calldata amts,
uint[] calldata getId,
uint[] calldata setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _length = tokens.length;
uint[] memory _amts = new uint[](_length);
for (uint i = 0; i < _length; i++) {
_amts[i] = getUint(getId[i], amts[i]);
}
instaPool.accessLiquidity(tokens, _amts);
for (uint i = 0; i < _length; i++) {
setUint(setId[i], _amts[i]);
}
_eventName = "LogMultiBorrow(address[],uint256[],uint256[],uint256[])";
_eventParam = abi.encode(tokens, amts, getId, setId);
}
/**
* @dev Return Multiple token liquidity from InstaPool.
* @param tokens Array of token addresses.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param getId get token amounts at this IDs from `InstaMemory` Contract.
* @param setId set token amounts at this IDs in `InstaMemory` Contract.
*/
function flashMultiPayback(
address[] calldata tokens,
uint[] calldata getId,
uint[] calldata setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _length = tokens.length;
for (uint i = 0; i < _length; i++) {
uint _amt = instaPool.borrowedToken(tokens[i]);
IERC20 tokenContract = IERC20(tokens[i]);
(address feeCollector, uint feeAmt) = calculateFeeAmt(tokenContract, _amt);
_transfer(payable(address(instaPool)), tokenContract, _amt);
if (feeAmt > 0) _transfer(payable(feeCollector), tokenContract, feeAmt);
setUint(setId[i], _amt);
}
instaPool.returnLiquidity(tokens);
_eventName = "LogMultiPayback(address[],uint256[],uint256[])";
_eventParam = abi.encode(tokens, getId, setId);
}
// TODO - Fix stack too deep
// /**
// * @dev Return Multiple token liquidity from InstaPool and Tranfer 20% of the Fee to Origin.
// * @param tokens Array of token addresses.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
// * @param getId get token amounts at this IDs from `InstaMemory` Contract.
// * @param setId set token amounts at this IDs in `InstaMemory` Contract.
// */
// function flashMultiPaybackOrigin(
// address origin,
// address[] calldata tokens,
// uint[] calldata getId,
// uint[] calldata setId
// ) external payable returns (string memory _eventName, bytes memory _eventParam) {
// uint _length = tokens.length;
// for (uint i = 0; i < _length; i++) {
// uint _amt = instaPool.borrowedToken(tokens[i]);
// IERC20 tokenContract = IERC20(tokens[i]);
// (address feeCollector, uint poolFeeAmt, uint originFeeAmt) = calculateFeeAmtOrigin(tokenContract, _amt);
// _transfer(payable(address(instaPool)), tokenContract, _amt);
// if (poolFeeAmt > 0) {
// _transfer(payable(feeCollector), tokenContract, poolFeeAmt);
// _transfer(payable(origin), tokenContract, originFeeAmt);
// }
// setUint(setId[i], _amt);
// }
// instaPool.returnLiquidity(tokens);
// _eventName = "LogMultiPaybackOrigin(address,address[],uint256[],uint256[])";
// _eventParam = abi.encode(origin, tokens, getId, setId);
// }
}
contract ConnectInstaPool is LiquidityAccessMulti {
string public name = "InstaPool-v2.1";
}