2021-04-09 01:03:40 +00:00
pragma solidity ^ 0 . 7 . 0 ;
pragma experimental ABIEncoderV2 ;
import " @openzeppelin/contracts/token/ERC20/IERC20.sol " ;
import " @openzeppelin/contracts/token/ERC20/SafeERC20.sol " ;
2021-04-14 23:04:22 +00:00
import " @openzeppelin/contracts/utils/Address.sol " ;
2021-04-09 01:03:40 +00:00
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 ;
2021-04-16 16:34:49 +00:00
MigrationInterface public constant migrationAddr = MigrationInterface ( 0xE3901a1bb3EefBF6bc90c201076e9068b646C1f3 ) ; // TODO @thrilok209: Chnage to Migration address
2021-04-09 01:03:40 +00:00
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 " ) ;
2021-04-14 23:04:22 +00:00
( bytes memory callData , uint ethAmt ) = abi . decode (
2021-04-09 01:03:40 +00:00
data ,
2021-04-14 23:04:22 +00:00
( bytes , uint )
2021-04-09 01:03:40 +00:00
) ;
wethContract . transfer ( address ( migrationAddr ) , ethAmt ) ;
2021-04-16 16:35:31 +00:00
Address . functionCall ( address ( migrationAddr ) , callData ) ;
2021-04-09 01:03:40 +00:00
}
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 ( ) ;
2021-04-15 16:33:16 +00:00
wethContract . approve ( soloAddr , ethAmt + 2 ) ;
2021-04-09 01:03:40 +00:00
solo . operate ( accountInfos , operations ) ;
}
}
contract InstaPool is DydxFlashloaner {
constructor ( ) public {
wethContract . approve ( wethAddr , uint ( - 1 ) ) ;
}
receive ( ) external payable { }
2021-04-16 16:34:49 +00:00
}