dsa-polygon-migration/contracts/liquidity.sol
2021-04-09 06:33:40 +05:30

315 lines
8.8 KiB
Solidity

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 {}
}