mirror of
https://github.com/Instadapp/dsa-polygon-migration.git
synced 2024-07-29 22:27:58 +00:00
added flashloan contract
This commit is contained in:
parent
4b21f93f02
commit
449f8aeefe
315
contracts/liquidity.sol
Normal file
315
contracts/liquidity.sol
Normal file
|
@ -0,0 +1,315 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||
import { DSMath } from "./common/math.sol";
|
||||
|
||||
interface Account {
|
||||
struct Info {
|
||||
address owner; // The address that owns the account
|
||||
uint256 number; // A nonce that allows a single address to control many accounts
|
||||
}
|
||||
}
|
||||
|
||||
interface ListInterface {
|
||||
function accountID(address) external view returns (uint64);
|
||||
}
|
||||
|
||||
interface Actions {
|
||||
enum ActionType {
|
||||
Deposit, // supply tokens
|
||||
Withdraw, // borrow tokens
|
||||
Transfer, // transfer balance between accounts
|
||||
Buy, // buy an amount of some token (publicly)
|
||||
Sell, // sell an amount of some token (publicly)
|
||||
Trade, // trade tokens against another account
|
||||
Liquidate, // liquidate an undercollateralized or expiring account
|
||||
Vaporize, // use excess tokens to zero-out a completely negative account
|
||||
Call // send arbitrary data to an address
|
||||
}
|
||||
|
||||
struct ActionArgs {
|
||||
ActionType actionType;
|
||||
uint256 accountId;
|
||||
Types.AssetAmount amount;
|
||||
uint256 primaryMarketId;
|
||||
uint256 secondaryMarketId;
|
||||
address otherAddress;
|
||||
uint256 otherAccountId;
|
||||
bytes data;
|
||||
}
|
||||
|
||||
struct DepositArgs {
|
||||
Types.AssetAmount amount;
|
||||
Account.Info account;
|
||||
uint256 market;
|
||||
address from;
|
||||
}
|
||||
|
||||
struct WithdrawArgs {
|
||||
Types.AssetAmount amount;
|
||||
Account.Info account;
|
||||
uint256 market;
|
||||
address to;
|
||||
}
|
||||
|
||||
struct CallArgs {
|
||||
Account.Info account;
|
||||
address callee;
|
||||
bytes data;
|
||||
}
|
||||
}
|
||||
|
||||
interface Types {
|
||||
enum AssetDenomination {
|
||||
Wei, // the amount is denominated in wei
|
||||
Par // the amount is denominated in par
|
||||
}
|
||||
|
||||
enum AssetReference {
|
||||
Delta, // the amount is given as a delta from the current value
|
||||
Target // the amount is given as an exact number to end up at
|
||||
}
|
||||
|
||||
struct AssetAmount {
|
||||
bool sign; // true if positive
|
||||
AssetDenomination denomination;
|
||||
AssetReference ref;
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
struct Wei {
|
||||
bool sign; // true if positive
|
||||
uint256 value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface ISoloMargin {
|
||||
struct OperatorArg {
|
||||
address operator;
|
||||
bool trusted;
|
||||
}
|
||||
|
||||
function getMarketTokenAddress(uint256 marketId)
|
||||
external
|
||||
view
|
||||
returns (address);
|
||||
|
||||
function getNumMarkets() external view returns (uint256);
|
||||
|
||||
|
||||
function operate(
|
||||
Account.Info[] calldata accounts,
|
||||
Actions.ActionArgs[] calldata actions
|
||||
) external;
|
||||
|
||||
function getAccountWei(Account.Info calldata account, uint256 marketId)
|
||||
external
|
||||
view
|
||||
returns (Types.Wei memory);
|
||||
}
|
||||
|
||||
contract DydxFlashloanBase {
|
||||
function _getMarketIdFromTokenAddress(address _solo, address token)
|
||||
internal
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
ISoloMargin solo = ISoloMargin(_solo);
|
||||
|
||||
uint256 numMarkets = solo.getNumMarkets();
|
||||
|
||||
address curToken;
|
||||
for (uint256 i = 0; i < numMarkets; i++) {
|
||||
curToken = solo.getMarketTokenAddress(i);
|
||||
|
||||
if (curToken == token) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
revert("No marketId found for provided token");
|
||||
}
|
||||
|
||||
function _getAccountInfo() internal view returns (Account.Info memory) {
|
||||
return Account.Info({owner: address(this), number: 1});
|
||||
}
|
||||
|
||||
function _getWithdrawAction(uint marketId, uint256 amount)
|
||||
internal
|
||||
view
|
||||
returns (Actions.ActionArgs memory)
|
||||
{
|
||||
return
|
||||
Actions.ActionArgs({
|
||||
actionType: Actions.ActionType.Withdraw,
|
||||
accountId: 0,
|
||||
amount: Types.AssetAmount({
|
||||
sign: false,
|
||||
denomination: Types.AssetDenomination.Wei,
|
||||
ref: Types.AssetReference.Delta,
|
||||
value: amount
|
||||
}),
|
||||
primaryMarketId: marketId,
|
||||
secondaryMarketId: 0,
|
||||
otherAddress: address(this),
|
||||
otherAccountId: 0,
|
||||
data: ""
|
||||
});
|
||||
}
|
||||
|
||||
function _getCallAction(bytes memory data)
|
||||
internal
|
||||
view
|
||||
returns (Actions.ActionArgs memory)
|
||||
{
|
||||
return
|
||||
Actions.ActionArgs({
|
||||
actionType: Actions.ActionType.Call,
|
||||
accountId: 0,
|
||||
amount: Types.AssetAmount({
|
||||
sign: false,
|
||||
denomination: Types.AssetDenomination.Wei,
|
||||
ref: Types.AssetReference.Delta,
|
||||
value: 0
|
||||
}),
|
||||
primaryMarketId: 0,
|
||||
secondaryMarketId: 0,
|
||||
otherAddress: address(this),
|
||||
otherAccountId: 0,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
function _getDepositAction(uint marketId, uint256 amount)
|
||||
internal
|
||||
view
|
||||
returns (Actions.ActionArgs memory)
|
||||
{
|
||||
return
|
||||
Actions.ActionArgs({
|
||||
actionType: Actions.ActionType.Deposit,
|
||||
accountId: 0,
|
||||
amount: Types.AssetAmount({
|
||||
sign: true,
|
||||
denomination: Types.AssetDenomination.Wei,
|
||||
ref: Types.AssetReference.Delta,
|
||||
value: amount
|
||||
}),
|
||||
primaryMarketId: marketId,
|
||||
secondaryMarketId: 0,
|
||||
otherAddress: address(this),
|
||||
otherAccountId: 0,
|
||||
data: ""
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @title ICallee
|
||||
* @author dYdX
|
||||
*
|
||||
* Interface that Callees for Solo must implement in order to ingest data.
|
||||
*/
|
||||
interface ICallee {
|
||||
|
||||
// ============ Public Functions ============
|
||||
|
||||
/**
|
||||
* Allows users to send this contract arbitrary data.
|
||||
*
|
||||
* @param sender The msg.sender to Solo
|
||||
* @param accountInfo The account from which the data is being sent
|
||||
* @param data Arbitrary data given by the sender
|
||||
*/
|
||||
function callFunction(
|
||||
address sender,
|
||||
Account.Info calldata accountInfo,
|
||||
bytes calldata data
|
||||
)
|
||||
external;
|
||||
}
|
||||
interface IndexInterface {
|
||||
function master() external view returns (address);
|
||||
}
|
||||
|
||||
interface TokenInterface {
|
||||
function approve(address, uint256) external;
|
||||
function transfer(address, uint) external;
|
||||
function transferFrom(address, address, uint) external;
|
||||
function deposit() external payable;
|
||||
function withdraw(uint) external;
|
||||
function balanceOf(address) external view returns (uint);
|
||||
function decimals() external view returns (uint);
|
||||
}
|
||||
|
||||
struct AaveDataRaw {
|
||||
address targetDsa;
|
||||
uint[] supplyAmts;
|
||||
uint[] variableBorrowAmts;
|
||||
uint[] stableBorrowAmts;
|
||||
address[] supplyTokens;
|
||||
address[] borrowTokens;
|
||||
}
|
||||
|
||||
interface MigrationInterface {
|
||||
function migrateFlashCallback(AaveDataRaw calldata _data, address dsa, uint ethAmt) external;
|
||||
}
|
||||
|
||||
contract Setup {
|
||||
address public constant soloAddr = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
|
||||
address public constant wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
MigrationInterface public constant migrationAddr = MigrationInterface(address(0)); // TODO: Migration address
|
||||
|
||||
TokenInterface wethContract = TokenInterface(wethAddr);
|
||||
ISoloMargin solo = ISoloMargin(soloAddr);
|
||||
|
||||
}
|
||||
|
||||
contract DydxFlashloaner is Setup, ICallee, DydxFlashloanBase, DSMath {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
function callFunction(
|
||||
address sender,
|
||||
Account.Info memory account,
|
||||
bytes memory data
|
||||
) public override {
|
||||
require(sender == address(this), "not-same-sender");
|
||||
require(msg.sender == soloAddr, "not-solo-dydx-sender");
|
||||
|
||||
(AaveDataRaw memory _data, address dsa, uint ethAmt) = abi.decode(
|
||||
data,
|
||||
(AaveDataRaw, address, uint)
|
||||
);
|
||||
|
||||
wethContract.transfer(address(migrationAddr), ethAmt);
|
||||
|
||||
migrationAddr.migrateFlashCallback(_data, dsa, ethAmt);
|
||||
}
|
||||
|
||||
function initiateFlashLoan(bytes memory data, uint ethAmt) external {
|
||||
require(msg.sender == address(migrationAddr), "not-migration-contract");
|
||||
uint marketId = _getMarketIdFromTokenAddress(soloAddr, wethAddr); // TODO: set Static market ID?
|
||||
|
||||
Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);
|
||||
|
||||
operations[0] = _getWithdrawAction(marketId, ethAmt);
|
||||
operations[1] = _getCallAction(data);
|
||||
operations[2] = _getDepositAction(marketId, ethAmt + 2);
|
||||
|
||||
Account.Info[] memory accountInfos = new Account.Info[](1);
|
||||
accountInfos[0] = _getAccountInfo();
|
||||
|
||||
solo.operate(accountInfos, operations);
|
||||
}
|
||||
}
|
||||
|
||||
contract InstaPool is DydxFlashloaner {
|
||||
constructor() public {
|
||||
wethContract.approve(wethAddr, uint(-1));
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
}
|
|
@ -228,6 +228,13 @@ contract MigrateResolver is LiquidityResolver {
|
|||
_migrate(_data, msg.sender);
|
||||
}
|
||||
|
||||
function migrateFlashCallback(AaveDataRaw calldata _data, address dsa, uint ethAmt) external {
|
||||
require(false); // TODO: flash loan contract
|
||||
// TODO: deposit ETH in Aave
|
||||
_migrate(_data, dsa);
|
||||
// TODO: withdraw ETH from Aave
|
||||
}
|
||||
|
||||
function migrateWithFlash(AaveDataRaw calldata _data, uint ethAmt) external {
|
||||
bytes memory data = abi.encode(_data, msg.sender, ethAmt);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user