Skip to content

Instantly share code, notes, and snippets.

@kendricktan
Created October 15, 2020 11:59
Show Gist options
  • Save kendricktan/c8363a4572d4d7c857ee2f89daf0a2de to your computer and use it in GitHub Desktop.
Save kendricktan/c8363a4572d4d7c857ee2f89daf0a2de to your computer and use it in GitHub Desktop.
shortdai solc-input.json
{
"language": "Solidity",
"sources": {
"contracts/CloseShortDAI.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport \"./weth/WETH.sol\";\n\nimport \"./dydx/DydxFlashloanBase.sol\";\nimport \"./dydx/IDydx.sol\";\n\nimport \"./maker/IDssCdpManager.sol\";\nimport \"./maker/IDssProxyActions.sol\";\nimport \"./maker/DssActionsBase.sol\";\n\nimport \"./curve/ICurveFiCurve.sol\";\n\nimport \"./Constants.sol\";\n\ncontract CloseShortDAI is ICallee, DydxFlashloanBase, DssActionsBase {\n struct CSDParams {\n uint256 cdpId; // CdpId to close\n address curvePool; // Which curve pool to use\n uint256 mintAmountDAI; // Amount of DAI to mint\n uint256 withdrawAmountUSDC; // Amount of USDC to withdraw from vault\n uint256 flashloanAmountWETH; // Amount of WETH flashloaned\n }\n\n function callFunction(\n address sender,\n Account.Info memory account,\n bytes memory data\n ) public override {\n CSDParams memory csdp = abi.decode(data, (CSDParams));\n\n // Step 1. Have Flashloaned WETH\n // Open WETH CDP in Maker, then Mint out some DAI\n uint256 wethCdp = _openLockGemAndDraw(\n Constants.MCD_JOIN_ETH_A,\n Constants.ETH_A_ILK,\n csdp.flashloanAmountWETH,\n csdp.mintAmountDAI\n );\n\n // Step 2.\n // Use flashloaned DAI to repay entire vault and withdraw USDC\n _wipeAllAndFreeGem(\n Constants.MCD_JOIN_USDC_A,\n csdp.cdpId,\n csdp.withdrawAmountUSDC\n );\n\n // Step 3.\n // Converts USDC to DAI on CurveFi (To repay loan)\n // DAI = 0 index, USDC = 1 index\n ICurveFiCurve curve = ICurveFiCurve(csdp.curvePool);\n // Calculate amount of USDC needed to exchange to repay flashloaned DAI\n // Allow max of 5% slippage (otherwise no profits lmao)\n uint256 usdcBal = IERC20(Constants.USDC).balanceOf(address(this));\n require(\n IERC20(Constants.USDC).approve(address(curve), usdcBal),\n \"erc20-approve-curvepool-failed\"\n );\n curve.exchange_underlying(int128(1), int128(0), usdcBal, 0);\n\n // Step 4.\n // Repay DAI loan back to WETH CDP and FREE WETH\n _wipeAllAndFreeGem(\n Constants.MCD_JOIN_ETH_A,\n wethCdp,\n csdp.flashloanAmountWETH\n );\n }\n\n function flashloanAndClose(\n address _sender,\n address _solo,\n address _curvePool,\n uint256 _cdpId,\n uint256 _ethUsdRatio18 // 1 ETH = <X> DAI?\n ) external payable {\n require(msg.value == 2, \"!fee\");\n\n ISoloMargin solo = ISoloMargin(_solo);\n\n uint256 marketId = _getMarketIdFromTokenAddress(_solo, Constants.WETH);\n\n // Supplied = How much we want to withdraw\n // Borrowed = How much we want to loan\n (\n uint256 withdrawAmountUSDC,\n uint256 mintAmountDAI\n ) = _getSuppliedAndBorrow(Constants.MCD_JOIN_USDC_A, _cdpId);\n\n // Given, ETH price, calculate how much WETH we need to flashloan\n // Dividing by 2 to gives us 200% col ratio\n uint256 flashloanAmountWETH = mintAmountDAI.mul(1 ether).div(\n _ethUsdRatio18.div(2)\n );\n\n require(\n IERC20(Constants.WETH).balanceOf(_solo) >= flashloanAmountWETH,\n \"!weth-supply\"\n );\n\n // Wrap ETH into WETH\n WETH(Constants.WETH).deposit{value: msg.value}();\n WETH(Constants.WETH).approve(_solo, flashloanAmountWETH.add(msg.value));\n\n Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);\n\n operations[0] = _getWithdrawAction(marketId, flashloanAmountWETH);\n operations[1] = _getCallAction(\n abi.encode(\n CSDParams({\n mintAmountDAI: mintAmountDAI,\n withdrawAmountUSDC: withdrawAmountUSDC,\n flashloanAmountWETH: flashloanAmountWETH,\n cdpId: _cdpId,\n curvePool: _curvePool\n })\n )\n );\n operations[2] = _getDepositAction(\n marketId,\n flashloanAmountWETH.add(msg.value)\n );\n\n Account.Info[] memory accountInfos = new Account.Info[](1);\n accountInfos[0] = _getAccountInfo();\n\n solo.operate(accountInfos, operations);\n\n // Convert DAI leftovers to USDC\n uint256 daiBal = IERC20(Constants.DAI).balanceOf(address(this));\n require(\n IERC20(Constants.DAI).approve(_curvePool, daiBal),\n \"erc20-approve-curvepool-failed\"\n );\n ICurveFiCurve(_curvePool).exchange_underlying(\n int128(0),\n int128(1),\n daiBal,\n 0\n );\n\n // Refund leftovers\n IERC20(Constants.USDC).transfer(\n _sender,\n IERC20(Constants.USDC).balanceOf(address(this))\n );\n }\n}\n"
},
"@openzeppelin/contracts/math/SafeMath.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n"
},
"contracts/weth/WETH.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.2;\n\ninterface WETH {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n\n function approve(address guy, uint256 wad) external returns (bool);\n\n function transfer(address dst, uint256 wad) external returns (bool);\n}\n"
},
"contracts/dydx/DydxFlashloanBase.sol": {
"content": "// SPDX-License-Identifier:\npragma solidity >=0.6.0 <0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport \"./IDydx.sol\";\n\ncontract DydxFlashloanBase {\n using SafeMath for uint256;\n\n // -- Internal Helper functions -- //\n\n function _getMarketIdFromTokenAddress(address _solo, address token)\n internal\n view\n returns (uint256)\n {\n ISoloMargin solo = ISoloMargin(_solo);\n\n uint256 numMarkets = solo.getNumMarkets();\n\n address curToken;\n for (uint256 i = 0; i < numMarkets; i++) {\n curToken = solo.getMarketTokenAddress(i);\n\n if (curToken == token) {\n return i;\n }\n }\n\n revert(\"No marketId found for provided token\");\n }\n\n function _getRepaymentAmount() internal pure returns (uint256) {\n // Needs to be overcollateralize\n // Needs to provide +2 wei to be safe\n return 2;\n }\n\n function _getAccountInfo() internal view returns (Account.Info memory) {\n return Account.Info({owner: address(this), number: 1});\n }\n\n function _getWithdrawAction(uint256 marketId, uint256 amount)\n internal\n view\n returns (Actions.ActionArgs memory)\n {\n return\n Actions.ActionArgs({\n actionType: Actions.ActionType.Withdraw,\n accountId: 0,\n amount: Types.AssetAmount({\n sign: false,\n denomination: Types.AssetDenomination.Wei,\n ref: Types.AssetReference.Delta,\n value: amount\n }),\n primaryMarketId: marketId,\n secondaryMarketId: 0,\n otherAddress: address(this),\n otherAccountId: 0,\n data: \"\"\n });\n }\n\n function _getCallAction(bytes memory data)\n internal\n view\n returns (Actions.ActionArgs memory)\n {\n return\n Actions.ActionArgs({\n actionType: Actions.ActionType.Call,\n accountId: 0,\n amount: Types.AssetAmount({\n sign: false,\n denomination: Types.AssetDenomination.Wei,\n ref: Types.AssetReference.Delta,\n value: 0\n }),\n primaryMarketId: 0,\n secondaryMarketId: 0,\n otherAddress: address(this),\n otherAccountId: 0,\n data: data\n });\n }\n\n function _getDepositAction(uint256 marketId, uint256 amount)\n internal\n view\n returns (Actions.ActionArgs memory)\n {\n return\n Actions.ActionArgs({\n actionType: Actions.ActionType.Deposit,\n accountId: 0,\n amount: Types.AssetAmount({\n sign: true,\n denomination: Types.AssetDenomination.Wei,\n ref: Types.AssetReference.Delta,\n value: amount\n }),\n primaryMarketId: marketId,\n secondaryMarketId: 0,\n otherAddress: address(this),\n otherAccountId: 0,\n data: \"\"\n });\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"
},
"contracts/dydx/IDydx.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\npragma experimental ABIEncoderV2;\n\nlibrary Account {\n enum Status {Normal, Liquid, Vapor}\n struct Info {\n address owner; // The address that owns the account\n uint256 number; // A nonce that allows a single address to control many accounts\n }\n struct Storage {\n mapping(uint256 => Types.Par) balances; // Mapping from marketId to principal\n Status status;\n }\n}\n\nlibrary Actions {\n enum ActionType {\n Deposit, // supply tokens\n Withdraw, // borrow tokens\n Transfer, // transfer balance between accounts\n Buy, // buy an amount of some token (externally)\n Sell, // sell an amount of some token (externally)\n Trade, // trade tokens against another account\n Liquidate, // liquidate an undercollateralized or expiring account\n Vaporize, // use excess tokens to zero-out a completely negative account\n Call // send arbitrary data to an address\n }\n\n struct ActionArgs {\n ActionType actionType;\n uint256 accountId;\n Types.AssetAmount amount;\n uint256 primaryMarketId;\n uint256 secondaryMarketId;\n address otherAddress;\n uint256 otherAccountId;\n bytes data;\n }\n\n struct DepositArgs {\n Types.AssetAmount amount;\n Account.Info account;\n uint256 market;\n address from;\n }\n\n struct WithdrawArgs {\n Types.AssetAmount amount;\n Account.Info account;\n uint256 market;\n address to;\n }\n\n struct CallArgs {\n Account.Info account;\n address callee;\n bytes data;\n }\n}\n\nlibrary Decimal {\n struct D256 {\n uint256 value;\n }\n}\n\nlibrary Types {\n enum AssetDenomination {\n Wei, // the amount is denominated in wei\n Par // the amount is denominated in par\n }\n\n enum AssetReference {\n Delta, // the amount is given as a delta from the current value\n Target // the amount is given as an exact number to end up at\n }\n\n struct AssetAmount {\n bool sign; // true if positive\n AssetDenomination denomination;\n AssetReference ref;\n uint256 value;\n }\n\n struct TotalPar {\n uint128 borrow;\n uint128 supply;\n }\n\n struct Par {\n bool sign; // true if positive\n uint128 value;\n }\n\n struct Wei {\n bool sign; // true if positive\n uint256 value;\n }\n}\n\ninterface ISoloMargin {\n function getMarketTokenAddress(uint256 marketId)\n external\n view\n returns (address);\n\n function getNumMarkets() external view returns (uint256);\n\n function operate(\n Account.Info[] calldata accounts,\n Actions.ActionArgs[] calldata actions\n ) external;\n}\n\ninterface ICallee {\n // ============ external Functions ============\n\n /**\n * Allows users to send this contract arbitrary data.\n *\n * @param sender The msg.sender to Solo\n * @param accountInfo The account from which the data is being sent\n * @param data Arbitrary data given by the sender\n */\n function callFunction(\n address sender,\n Account.Info calldata accountInfo,\n bytes calldata data\n ) external;\n}\n"
},
"contracts/maker/IDssCdpManager.sol": {
"content": "// SPDX-License-Identifier: MIT\n// Address: 0x5ef30b9986345249bc32d8928B7ee64DE9435E39\npragma solidity >=0.6.0 <0.7.0;\n\ninterface IDssCdpManager {\n function cdpAllow(\n uint256 cdp,\n address usr,\n uint256 ok\n ) external;\n\n function cdpCan(\n address,\n uint256,\n address\n ) external view returns (uint256);\n\n function cdpi() external view returns (uint256);\n\n function count(address) external view returns (uint256);\n\n function enter(address src, uint256 cdp) external;\n\n function first(address) external view returns (uint256);\n\n function flux(\n bytes32 ilk,\n uint256 cdp,\n address dst,\n uint256 wad\n ) external;\n\n function flux(\n uint256 cdp,\n address dst,\n uint256 wad\n ) external;\n\n function frob(\n uint256 cdp,\n int256 dink,\n int256 dart\n ) external;\n\n function give(uint256 cdp, address dst) external;\n\n function ilks(uint256) external view returns (bytes32);\n\n function last(address) external view returns (uint256);\n\n function list(uint256) external view returns (uint256 prev, uint256 next);\n\n function move(\n uint256 cdp,\n address dst,\n uint256 rad\n ) external;\n\n function open(bytes32 ilk, address usr) external returns (uint256);\n\n function owns(uint256) external view returns (address);\n\n function quit(uint256 cdp, address dst) external;\n\n function shift(uint256 cdpSrc, uint256 cdpDst) external;\n\n function urnAllow(address usr, uint256 ok) external;\n\n function urnCan(address, address) external view returns (uint256);\n\n function urns(uint256) external view returns (address);\n\n function vat() external view returns (address);\n}\n"
},
"contracts/maker/IDssProxyActions.sol": {
"content": "// SPDX-License-Identifier: MIT\n// Address: 0x82ecD135Dce65Fbc6DbdD0e4237E0AF93FFD5038\npragma solidity >=0.6.0 <0.7.0;\n\ninterface IDssProxyActions {\n function cdpAllow(\n address manager,\n uint256 cdp,\n address usr,\n uint256 ok\n ) external;\n\n function daiJoin_join(\n address apt,\n address urn,\n uint256 wad\n ) external;\n\n function draw(\n address manager,\n address jug,\n address daiJoin,\n uint256 cdp,\n uint256 wad\n ) external;\n\n function enter(\n address manager,\n address src,\n uint256 cdp\n ) external;\n\n function ethJoin_join(address apt, address urn) external payable;\n\n function exitETH(\n address manager,\n address ethJoin,\n uint256 cdp,\n uint256 wad\n ) external;\n\n function exitGem(\n address manager,\n address gemJoin,\n uint256 cdp,\n uint256 amt\n ) external;\n\n function flux(\n address manager,\n uint256 cdp,\n address dst,\n uint256 wad\n ) external;\n\n function freeETH(\n address manager,\n address ethJoin,\n uint256 cdp,\n uint256 wad\n ) external;\n\n function freeGem(\n address manager,\n address gemJoin,\n uint256 cdp,\n uint256 amt\n ) external;\n\n function frob(\n address manager,\n uint256 cdp,\n int256 dink,\n int256 dart\n ) external;\n\n function gemJoin_join(\n address apt,\n address urn,\n uint256 amt,\n bool transferFrom\n ) external;\n\n function give(\n address manager,\n uint256 cdp,\n address usr\n ) external;\n\n function giveToProxy(\n address proxyRegistry,\n address manager,\n uint256 cdp,\n address dst\n ) external;\n\n function hope(address obj, address usr) external;\n\n function lockETH(\n address manager,\n address ethJoin,\n uint256 cdp\n ) external payable;\n\n function lockETHAndDraw(\n address manager,\n address jug,\n address ethJoin,\n address daiJoin,\n uint256 cdp,\n uint256 wadD\n ) external payable;\n\n function lockGem(\n address manager,\n address gemJoin,\n uint256 cdp,\n uint256 amt,\n bool transferFrom\n ) external;\n\n function lockGemAndDraw(\n address manager,\n address jug,\n address gemJoin,\n address daiJoin,\n uint256 cdp,\n uint256 amtC,\n uint256 wadD,\n bool transferFrom\n ) external;\n\n function makeGemBag(address gemJoin) external returns (address bag);\n\n function move(\n address manager,\n uint256 cdp,\n address dst,\n uint256 rad\n ) external;\n\n function nope(address obj, address usr) external;\n\n function open(\n address manager,\n bytes32 ilk,\n address usr\n ) external returns (uint256 cdp);\n\n function openLockETHAndDraw(\n address manager,\n address jug,\n address ethJoin,\n address daiJoin,\n bytes32 ilk,\n uint256 wadD\n ) external payable returns (uint256 cdp);\n\n function openLockGNTAndDraw(\n address manager,\n address jug,\n address gntJoin,\n address daiJoin,\n bytes32 ilk,\n uint256 amtC,\n uint256 wadD\n ) external returns (address bag, uint256 cdp);\n\n function openLockGemAndDraw(\n address manager,\n address jug,\n address gemJoin,\n address daiJoin,\n bytes32 ilk,\n uint256 amtC,\n uint256 wadD,\n bool transferFrom\n ) external returns (uint256 cdp);\n\n function quit(\n address manager,\n uint256 cdp,\n address dst\n ) external;\n\n function safeLockETH(\n address manager,\n address ethJoin,\n uint256 cdp,\n address owner\n ) external payable;\n\n function safeLockGem(\n address manager,\n address gemJoin,\n uint256 cdp,\n uint256 amt,\n bool transferFrom,\n address owner\n ) external;\n\n function safeWipe(\n address manager,\n address daiJoin,\n uint256 cdp,\n uint256 wad,\n address owner\n ) external;\n\n function safeWipeAll(\n address manager,\n address daiJoin,\n uint256 cdp,\n address owner\n ) external;\n\n function shift(\n address manager,\n uint256 cdpSrc,\n uint256 cdpOrg\n ) external;\n\n function transfer(\n address gem,\n address dst,\n uint256 amt\n ) external;\n\n function urnAllow(\n address manager,\n address usr,\n uint256 ok\n ) external;\n\n function wipe(\n address manager,\n address daiJoin,\n uint256 cdp,\n uint256 wad\n ) external;\n\n function wipeAll(\n address manager,\n address daiJoin,\n uint256 cdp\n ) external;\n\n function wipeAllAndFreeETH(\n address manager,\n address ethJoin,\n address daiJoin,\n uint256 cdp,\n uint256 wadC\n ) external;\n\n function wipeAllAndFreeGem(\n address manager,\n address gemJoin,\n address daiJoin,\n uint256 cdp,\n uint256 amtC\n ) external;\n\n function wipeAndFreeETH(\n address manager,\n address ethJoin,\n address daiJoin,\n uint256 cdp,\n uint256 wadC,\n uint256 wadD\n ) external;\n\n function wipeAndFreeGem(\n address manager,\n address gemJoin,\n address daiJoin,\n uint256 cdp,\n uint256 amtC,\n uint256 wadD\n ) external;\n}\n"
},
"contracts/maker/DssActionsBase.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport \"../Constants.sol\";\nimport \"./IDssCdpManager.sol\";\n\ninterface GemLike {\n function approve(address, uint256) external;\n\n function transfer(address, uint256) external;\n\n function transferFrom(\n address,\n address,\n uint256\n ) external;\n\n function deposit() external payable;\n\n function withdraw(uint256) external;\n}\n\ninterface GemJoinLike {\n function dec() external returns (uint256);\n\n function gem() external returns (address);\n\n function join(address, uint256) external payable;\n\n function exit(address, uint256) external;\n}\n\ninterface VatLike {\n function can(address, address) external view returns (uint256);\n\n function ilks(bytes32)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function dai(address) external view returns (uint256);\n\n function urns(bytes32, address) external view returns (uint256, uint256);\n\n function frob(\n bytes32,\n address,\n address,\n address,\n int256,\n int256\n ) external;\n\n function hope(address) external;\n\n function move(\n address,\n address,\n uint256\n ) external;\n}\n\ninterface JugLike {\n function drip(bytes32) external returns (uint256);\n\n function ilks(bytes32) external view returns (uint256, uint256);\n}\n\ninterface DaiJoinLike {\n function vat() external returns (VatLike);\n\n function dai() external returns (GemLike);\n\n function join(address, uint256) external payable;\n\n function exit(address, uint256) external;\n}\n\ncontract DssActionsBase {\n uint256 constant RAY = 10**27;\n\n using SafeMath for uint256;\n\n function _convertTo18(address gemJoin, uint256 amt)\n internal\n returns (uint256 wad)\n {\n // For those collaterals that have less than 18 decimals precision we need to do the conversion before passing to frob function\n // Adapters will automatically handle the difference of precision\n wad = amt.mul(10**(18 - GemJoinLike(gemJoin).dec()));\n }\n\n function _toInt(uint256 x) internal pure returns (int256 y) {\n y = int256(x);\n require(y >= 0, \"int-overflow\");\n }\n\n function _toRad(uint256 wad) internal pure returns (uint256 rad) {\n rad = wad.mul(10**27);\n }\n\n function _gemJoin_join(\n address apt,\n address urn,\n uint256 wad,\n bool transferFrom\n ) internal {\n // Only executes for tokens that have approval/transferFrom implementation\n if (transferFrom) {\n // Tokens already in address(this)\n // GemLike(GemJoinLike(apt).gem()).transferFrom(msg.sender, address(this), wad);\n // Approves adapter to take the token amount\n GemLike(GemJoinLike(apt).gem()).approve(apt, wad);\n }\n // Joins token collateral into the vat\n GemJoinLike(apt).join(urn, wad);\n }\n\n function _daiJoin_join(\n address apt,\n address urn,\n uint256 wad\n ) internal {\n // Contract already has tokens\n // Gets DAI from the user's wallet\n // DaiJoinLike(apt).dai().transferFrom(msg.sender, address(this), wad);\n // Approves adapter to take the DAI amount\n DaiJoinLike(apt).dai().approve(apt, wad);\n // Joins DAI into the vat\n DaiJoinLike(apt).join(urn, wad);\n }\n\n function _getDrawDart(\n address vat,\n address jug,\n address urn,\n bytes32 ilk,\n uint256 wad\n ) internal returns (int256 dart) {\n // Updates stability fee rate\n uint256 rate = JugLike(jug).drip(ilk);\n\n // Gets DAI balance of the urn in the vat\n uint256 dai = VatLike(vat).dai(urn);\n\n // If there was already enough DAI in the vat balance, just exits it without adding more debt\n if (dai < wad.mul(RAY)) {\n // Calculates the needed dart so together with the existing dai in the vat is enough to exit wad amount of DAI tokens\n dart = _toInt(wad.mul(RAY).sub(dai) / rate);\n // This is neeeded due lack of precision. It might need to sum an extra dart wei (for the given DAI wad amount)\n dart = uint256(dart).mul(rate) < wad.mul(RAY) ? dart + 1 : dart;\n }\n }\n\n function _getWipeDart(\n address vat,\n uint256 dai,\n address urn,\n bytes32 ilk\n ) internal view returns (int256 dart) {\n // Gets actual rate from the vat\n (, uint256 rate, , , ) = VatLike(vat).ilks(ilk);\n // Gets actual art value of the urn\n (, uint256 art) = VatLike(vat).urns(ilk, urn);\n\n // Uses the whole dai balance in the vat to reduce the debt\n dart = _toInt(dai / rate);\n // Checks the calculated dart is not higher than urn.art (total debt), otherwise uses its value\n dart = uint256(dart) <= art ? -dart : -_toInt(art);\n }\n\n function _getWipeAllWad(\n address vat,\n address usr,\n address urn,\n bytes32 ilk\n ) internal view returns (uint256 wad) {\n // Gets actual rate from the vat\n (, uint256 rate, , , ) = VatLike(vat).ilks(ilk);\n // Gets actual art value of the urn\n (, uint256 art) = VatLike(vat).urns(ilk, urn);\n // Gets actual dai amount in the urn\n uint256 dai = VatLike(vat).dai(usr);\n\n uint256 rad = art.mul(rate).sub(dai);\n wad = rad / RAY;\n\n // If the rad precision has some dust, it will need to request for 1 extra wad wei\n wad = wad.mul(RAY) < rad ? wad + 1 : wad;\n }\n\n function _getSuppliedAndBorrow(address gemJoin, uint256 cdp)\n internal\n returns (uint256, uint256)\n {\n IDssCdpManager manager = IDssCdpManager(Constants.CDP_MANAGER);\n\n address vat = manager.vat();\n bytes32 ilk = manager.ilks(cdp);\n\n // Gets actual rate from the vat\n (, uint256 rate, , , ) = VatLike(vat).ilks(ilk);\n // Gets actual art value of the urn\n (uint256 supplied, uint256 art) = VatLike(vat).urns(\n ilk,\n manager.urns(cdp)\n );\n // Gets actual dai amount in the urn\n uint256 dai = VatLike(vat).dai(manager.owns(cdp));\n\n uint256 rad = art.mul(rate).sub(dai);\n uint256 wad = rad / RAY;\n\n // If the rad precision has some dust, it will need to request for 1 extra wad wei\n uint256 borrowed = wad.mul(RAY) < rad ? wad + 1 : wad;\n\n // Convert back to native units\n supplied = supplied.div(10**(18 - GemJoinLike(gemJoin).dec()));\n\n return (supplied, borrowed);\n }\n\n function _lockGemAndDraw(\n address gemJoin,\n uint256 cdp,\n uint256 wadC,\n uint256 wadD\n ) internal {\n IDssCdpManager manager = IDssCdpManager(Constants.CDP_MANAGER);\n\n address urn = manager.urns(cdp);\n address vat = manager.vat();\n bytes32 ilk = manager.ilks(cdp);\n\n // Receives ETH amount, converts it to WETH and joins it into the vat\n _gemJoin_join(gemJoin, urn, wadC, true);\n\n // Locks GEM amount into the CDP and generates debt\n manager.frob(\n cdp,\n _toInt(_convertTo18(gemJoin, wadC)),\n _getDrawDart(vat, Constants.MCD_JUG, urn, ilk, wadD)\n );\n\n // Moves the DAI amount (balance in the vat in rad) to proxy's address\n manager.move(cdp, address(this), _toRad(wadD));\n\n // Allows adapter to access to proxy's DAI balance in the vat\n if (\n VatLike(vat).can(address(this), address(Constants.MCD_JOIN_DAI)) ==\n 0\n ) {\n VatLike(vat).hope(Constants.MCD_JOIN_DAI);\n }\n // Exits DAI to the user's wallet as a token\n DaiJoinLike(Constants.MCD_JOIN_DAI).exit(address(this), wadD);\n }\n\n function _wipeAllAndFreeGem(\n address gemJoin,\n uint256 cdp,\n uint256 amtC\n ) internal {\n IDssCdpManager manager = IDssCdpManager(Constants.CDP_MANAGER);\n\n address vat = manager.vat();\n address urn = manager.urns(cdp);\n bytes32 ilk = manager.ilks(cdp);\n (, uint256 art) = VatLike(vat).urns(ilk, urn);\n\n // Joins DAI amount into the vat\n _daiJoin_join(\n Constants.MCD_JOIN_DAI,\n urn,\n _getWipeAllWad(vat, urn, urn, ilk)\n );\n uint256 wadC = _convertTo18(gemJoin, amtC);\n // Paybacks debt to the CDP and unlocks token amount from it\n manager.frob(cdp, -_toInt(wadC), -int256(art));\n // Moves the amount from the CDP urn to proxy's address\n manager.flux(cdp, address(this), wadC);\n // Exits token amount to the user's wallet as a token\n GemJoinLike(gemJoin).exit(address(this), amtC);\n }\n\n function _openLockGemAndDraw(\n address gemJoin,\n bytes32 ilk,\n uint256 amtC,\n uint256 wadD\n ) internal returns (uint256 cdp) {\n cdp = IDssCdpManager(Constants.CDP_MANAGER).open(ilk, address(this));\n _lockGemAndDraw(gemJoin, cdp, amtC, wadD);\n }\n}\n"
},
"contracts/Constants.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\n\nlibrary Constants {\n address constant CDP_MANAGER = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;\n address constant PROXY_ACTIONS = 0x82ecD135Dce65Fbc6DbdD0e4237E0AF93FFD5038;\n address constant MCD_JOIN_ETH_A = 0x2F0b23f53734252Bda2277357e97e1517d6B042A;\n address constant MCD_JOIN_USDC_A = 0xA191e578a6736167326d05c119CE0c90849E84B7;\n address constant MCD_JOIN_DAI = 0x9759A6Ac90977b93B58547b4A71c78317f391A28;\n address constant MCD_JUG = 0x19c0976f590D67707E62397C87829d896Dc0f1F1;\n address constant MCD_END = 0xaB14d3CE3F733CACB76eC2AbE7d2fcb00c99F3d5;\n\n address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n address constant UNISWAPV2_ROUTER2 = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;\n\n bytes32 constant USDC_A_ILK = bytes32(\"USDC-A\");\n bytes32 constant ETH_A_ILK = bytes32(\"ETH-A\");\n\n // OneSplit Flags\n uint256 constant ONE_SPLIT_CURVE_ONLY_FLAGS = 3758411776;\n uint256 constant ONE_SPLIT_PARTS = 10;\n}\n"
},
"contracts/curve/ICurveFiCurve.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\n\ninterface ICurveFiCurve {\n function get_virtual_price() external view returns (uint256 out);\n\n function add_liquidity(uint256[2] calldata amounts, uint256 deadline)\n external;\n\n function get_dy(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256 out);\n\n function get_dy_underlying(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256 out);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 dx,\n uint256 min_dy\n ) external;\n\n function exchange(\n int128 i,\n int128 j,\n uint256 dx,\n uint256 min_dy,\n uint256 deadline\n ) external;\n\n function exchange_underlying(\n int128 i,\n int128 j,\n uint256 dx,\n uint256 min_dy\n ) external;\n\n function exchange_underlying(\n int128 i,\n int128 j,\n uint256 dx,\n uint256 min_dy,\n uint256 deadline\n ) external;\n\n function remove_liquidity(\n uint256 _amount,\n uint256 deadline,\n uint256[2] calldata min_amounts\n ) external;\n\n function remove_liquidity_imbalance(\n uint256[2] calldata amounts,\n uint256 deadline\n ) external;\n\n function commit_new_parameters(\n int128 amplification,\n int128 new_fee,\n int128 new_admin_fee\n ) external;\n\n function apply_new_parameters() external;\n\n function revert_new_parameters() external;\n\n function commit_transfer_ownership(address _owner) external;\n\n function apply_transfer_ownership() external;\n\n function revert_transfer_ownership() external;\n\n function withdraw_admin_fees() external;\n\n function coins(int128 arg0) external returns (address out);\n\n function underlying_coins(int128 arg0) external returns (address out);\n\n function balances(int128 arg0) external returns (uint256 out);\n\n function A() external returns (int128 out);\n\n function fee() external returns (int128 out);\n\n function admin_fee() external returns (int128 out);\n\n function owner() external returns (address out);\n\n function admin_actions_deadline() external returns (uint256 out);\n\n function transfer_ownership_deadline() external returns (uint256 out);\n\n function future_A() external returns (int128 out);\n\n function future_fee() external returns (int128 out);\n\n function future_admin_fee() external returns (int128 out);\n\n function future_owner() external returns (address out);\n}\n"
},
"contracts/maker/IDSProxy.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\n\ninterface IDSProxy {\n function authority() external view returns (address);\n\n function cache() external view returns (address);\n\n function execute(address _target, bytes calldata _data)\n external\n payable\n returns (bytes memory response);\n\n function execute(bytes calldata _code, bytes calldata _data)\n external\n payable\n returns (address target, bytes memory response);\n\n function owner() external view returns (address);\n\n function setAuthority(address authority_) external;\n\n function setCache(address _cacheAddr) external returns (bool);\n\n function setOwner(address owner_) external;\n}\n"
},
"contracts/maker/IGetCdps.sol": {
"content": "// SPDX-License-Identifier: MIT\n// Address: 0x36a724Bd100c39f0Ea4D3A20F7097eE01A8Ff573\npragma solidity >=0.6.0 <0.7.0;\n\ninterface IGetCdps {\n function getCdpsAsc(address manager, address guy)\n external\n view\n returns (\n uint256[] memory ids,\n address[] memory urns,\n bytes32[] memory ilks\n );\n\n function getCdpsDesc(address manager, address guy)\n external\n view\n returns (\n uint256[] memory ids,\n address[] memory urns,\n bytes32[] memory ilks\n );\n}\n"
},
"contracts/maker/IProxyRegistry.sol": {
"content": "// SPDX-License-Identifier: MIT\n// Address: 0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4\npragma solidity >=0.6.0 <0.7.0;\n\ninterface IProxyRegistry {\n function build() external returns (address proxy);\n\n function proxies(address) external view returns (address);\n\n function build(address owner) external returns (address proxy);\n}\n"
},
"contracts/Migrations.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.21 <0.7.0;\n\ncontract Migrations {\n address public owner;\n uint public last_completed_migration;\n\n constructor() public {\n owner = msg.sender;\n }\n\n modifier restricted() {\n if (msg.sender == owner) _;\n }\n\n function setCompleted(uint completed) public restricted {\n last_completed_migration = completed;\n }\n}\n"
},
"contracts/onesplit/IOneSplit.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\n\ninterface IOneSplit {\n function getExpectedReturn(\n address fromToken,\n address destToken,\n uint256 amount,\n uint256 parts,\n uint256 flags // See constants in IOneSplit.sol\n )\n external\n view\n returns (uint256 returnAmount, uint256[] memory distribution);\n\n function swap(\n address fromToken,\n address destToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata distribution,\n uint256 flags\n ) external payable returns (uint256 returnAmount);\n}\n"
},
"contracts/OpenShortDAI.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport \"./onesplit/IOneSplit.sol\";\n\nimport \"./weth/WETH.sol\";\n\nimport \"./dydx/DydxFlashloanBase.sol\";\nimport \"./dydx/IDydx.sol\";\n\nimport \"./maker/IDssCdpManager.sol\";\nimport \"./maker/IDssProxyActions.sol\";\nimport \"./maker/DssActionsBase.sol\";\n\nimport \"./curve/ICurveFiCurve.sol\";\n\nimport \"./Constants.sol\";\n\ncontract OpenShortDAI is ICallee, DydxFlashloanBase, DssActionsBase {\n // LeveragedShortDAI Params\n struct OSDParams {\n uint256 cdpId; // CDP Id to leverage\n uint256 mintAmountDAI; // Amount of DAI to mint\n uint256 flashloanAmountWETH; // Amount of WETH flashloaned\n address curvePool;\n }\n\n function callFunction(\n address sender,\n Account.Info memory account,\n bytes memory data\n ) public override {\n OSDParams memory osdp = abi.decode(data, (OSDParams));\n\n // Step 1. Have Flashloaned WETH\n // Open WETH CDP in Maker, then Mint out some DAI\n uint256 wethCdp = _openLockGemAndDraw(\n Constants.MCD_JOIN_ETH_A,\n Constants.ETH_A_ILK,\n osdp.flashloanAmountWETH,\n osdp.mintAmountDAI\n );\n\n // Step 2.\n // Converts Flashloaned DAI to USDC on CurveFi\n // DAI = 0 index, USDC = 1 index\n // require(\n // IERC20(Constants.DAI).approve(osdp.curvePool, osdp.mintAmountDAI),\n // \"!curvepool-approved\"\n // );\n // ICurveFiCurve(osdp.curvePool).exchange_underlying(\n // int128(0),\n // int128(1),\n // osdp.mintAmountDAI,\n // 0\n // );\n IOneSplit oneSplit = IOneSplit(\n 0xC586BeF4a0992C495Cf22e1aeEE4E446CECDee0E\n );\n (uint256 returnAmount, uint256[] memory distribution) = oneSplit\n .getExpectedReturn(\n Constants.DAI,\n Constants.USDC,\n osdp.mintAmountDAI,\n Constants.ONE_SPLIT_PARTS,\n Constants.ONE_SPLIT_CURVE_ONLY_FLAGS\n );\n oneSplit.swap(\n Constants.DAI,\n Constants.USDC,\n osdp.mintAmountDAI,\n 0,\n distribution,\n Constants.ONE_SPLIT_CURVE_ONLY_FLAGS\n );\n\n // Step 3.\n // Locks up USDC and borrow just enough DAI to repay WETH CDP\n uint256 supplyAmount = IERC20(Constants.USDC).balanceOf(address(this));\n _lockGemAndDraw(\n Constants.MCD_JOIN_USDC_A,\n osdp.cdpId,\n supplyAmount,\n osdp.mintAmountDAI\n );\n\n // Step 4.\n // Repay DAI loan back to WETH CDP and FREE WETH\n _wipeAllAndFreeGem(\n Constants.MCD_JOIN_ETH_A,\n wethCdp,\n osdp.flashloanAmountWETH\n );\n }\n\n function flashloanAndOpen(\n address _sender,\n address _solo,\n address _curvePool,\n uint256 _cdpId,\n uint256 _initialMarginUSDC,\n uint256 _mintAmountDAI,\n uint256 _flashloanAmountWETH\n ) external payable {\n require(msg.value == 2, \"!fee\");\n\n require(\n IERC20(Constants.WETH).balanceOf(_solo) >= _flashloanAmountWETH,\n \"!weth-supply\"\n );\n\n // Gets USDC\n require(\n IERC20(Constants.USDC).transferFrom(\n msg.sender,\n address(this),\n _initialMarginUSDC\n ),\n \"initial-margin-transferFrom-failed\"\n );\n\n ISoloMargin solo = ISoloMargin(_solo);\n\n // Get marketId from token address\n uint256 marketId = _getMarketIdFromTokenAddress(_solo, Constants.WETH);\n\n // Wrap ETH into WETH\n WETH(Constants.WETH).deposit{value: msg.value}();\n WETH(Constants.WETH).approve(\n _solo,\n _flashloanAmountWETH.add(msg.value)\n );\n\n // 1. Withdraw $\n // 2. Call callFunction(...)\n // 3. Deposit back $\n Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);\n\n operations[0] = _getWithdrawAction(marketId, _flashloanAmountWETH);\n operations[1] = _getCallAction(\n // Encode OSDParams for callFunction\n abi.encode(\n OSDParams({\n mintAmountDAI: _mintAmountDAI,\n flashloanAmountWETH: _flashloanAmountWETH,\n cdpId: _cdpId,\n curvePool: _curvePool\n })\n )\n );\n operations[2] = _getDepositAction(\n marketId,\n _flashloanAmountWETH.add(msg.value)\n );\n\n Account.Info[] memory accountInfos = new Account.Info[](1);\n accountInfos[0] = _getAccountInfo();\n\n solo.operate(accountInfos, operations);\n\n // Refund user any ERC20 leftover\n IERC20(Constants.DAI).transfer(\n _sender,\n IERC20(Constants.DAI).balanceOf(address(this))\n );\n IERC20(Constants.USDC).transfer(\n _sender,\n IERC20(Constants.USDC).balanceOf(address(this))\n );\n }\n}\n"
},
"contracts/ShortDAIActions.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport \"./dydx/DydxFlashloanBase.sol\";\nimport \"./dydx/IDydx.sol\";\n\nimport \"./maker/IDssCdpManager.sol\";\nimport \"./maker/IDssProxyActions.sol\";\nimport \"./maker/DssActionsBase.sol\";\n\nimport \"./OpenShortDAI.sol\";\nimport \"./CloseShortDAI.sol\";\nimport \"./VaultStats.sol\";\n\nimport \"./curve/ICurveFiCurve.sol\";\n\nimport \"./Constants.sol\";\n\ncontract ShortDAIActions {\n using SafeMath for uint256;\n\n function _openUSDCACdp() internal returns (uint256) {\n return\n IDssCdpManager(Constants.CDP_MANAGER).open(\n bytes32(\"USDC-A\"),\n address(this)\n );\n }\n\n // Entry point for proxy contracts\n function flashloanAndOpen(\n address _osd,\n address _solo,\n address _curvePool,\n uint256 _cdpId, // Set 0 for new vault\n uint256 _initialMarginUSDC, // Initial USDC margin\n uint256 _mintAmountDAI, // Amount of DAI to mint\n uint256 _flashloanAmountWETH, // Amount of WETH to flashloan\n address _vaultStats,\n uint256 _daiUsdcRatio6\n ) external payable {\n require(msg.value == 2, \"!fee\");\n\n // Tries and get USDC from msg.sender to proxy\n require(\n IERC20(Constants.USDC).transferFrom(\n msg.sender,\n address(this),\n _initialMarginUSDC\n ),\n \"initial-margin-transferFrom-failed\"\n );\n\n uint256 cdpId = _cdpId;\n\n // Opens a new USDC vault for the user if unspecified\n if (cdpId == 0) {\n cdpId = _openUSDCACdp();\n }\n\n // Allows LSD contract to manage vault on behalf of user\n IDssCdpManager(Constants.CDP_MANAGER).cdpAllow(cdpId, _osd, 1);\n\n // Approve OpenShortDAI Contract to use USDC funds\n require(\n IERC20(Constants.USDC).approve(_osd, _initialMarginUSDC),\n \"initial-margin-approve-failed\"\n );\n // Flashloan and shorts DAI\n OpenShortDAI(_osd).flashloanAndOpen{value: msg.value}(\n msg.sender,\n _solo,\n _curvePool,\n cdpId,\n _initialMarginUSDC,\n _mintAmountDAI,\n _flashloanAmountWETH\n );\n\n // Forbids LSD contract to manage vault on behalf of user\n IDssCdpManager(Constants.CDP_MANAGER).cdpAllow(cdpId, _osd, 0);\n\n // Save stats\n VaultStats(_vaultStats).setDaiUsdcRatio6(cdpId, _daiUsdcRatio6);\n }\n\n function flashloanAndClose(\n address _csd,\n address _solo,\n address _curvePool,\n uint256 _cdpId,\n uint256 _ethUsdRatio18\n ) external payable {\n require(msg.value == 2, \"!fee\");\n\n IDssCdpManager(Constants.CDP_MANAGER).cdpAllow(_cdpId, _csd, 1);\n\n CloseShortDAI(_csd).flashloanAndClose{value: msg.value}(\n msg.sender,\n _solo,\n _curvePool,\n _cdpId,\n _ethUsdRatio18\n );\n\n IDssCdpManager(Constants.CDP_MANAGER).cdpAllow(_cdpId, _csd, 0);\n IDssCdpManager(Constants.CDP_MANAGER).give(_cdpId, address(1));\n }\n\n function cdpAllow(\n uint256 cdp,\n address usr,\n uint256 ok\n ) public {\n IDssCdpManager(Constants.CDP_MANAGER).cdpAllow(cdp, usr, ok);\n }\n}\n"
},
"contracts/VaultStats.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport \"./maker/IDssCdpManager.sol\";\nimport \"./maker/IDssProxyActions.sol\";\nimport \"./maker/DssActionsBase.sol\";\n\nimport \"./Constants.sol\";\n\ncontract VaultStats {\n uint256 constant RAY = 10**27;\n\n using SafeMath for uint256;\n\n // CDP ID => DAI/USDC Ratio in 6 decimals\n // i.e. What was DAI/USDC ratio when CDP was opened\n mapping(uint256 => uint256) public daiUsdcRatio6;\n\n //** View functions for stats ** //\n\n function _getCdpSuppliedAndBorrowed(\n address vat,\n address usr,\n address urn,\n bytes32 ilk\n ) internal view returns (uint256, uint256) {\n // Gets actual rate from the vat\n (, uint256 rate, , , ) = VatLike(vat).ilks(ilk);\n // Gets actual art value of the urn\n (uint256 supplied, uint256 art) = VatLike(vat).urns(ilk, urn);\n // Gets actual dai amount in the urn\n uint256 dai = VatLike(vat).dai(usr);\n\n uint256 rad = art.mul(rate).sub(dai);\n uint256 wad = rad / RAY;\n\n // If the rad precision has some dust, it will need to request for 1 extra wad wei\n uint256 borrowed = wad.mul(RAY) < rad ? wad + 1 : wad;\n\n // Note that supplied is in 18 decimals, so you'll need to convert it back\n // i.e. supplied = supplied / 10 ** (18 - decimals)\n\n return (supplied, borrowed);\n }\n\n // Get DAI borrow / supply stats\n function getCdpStats(uint256 cdp)\n public\n view\n returns (\n uint256,\n uint256,\n uint256\n )\n {\n address vat = IDssCdpManager(Constants.CDP_MANAGER).vat();\n address urn = IDssCdpManager(Constants.CDP_MANAGER).urns(cdp);\n bytes32 ilk = IDssCdpManager(Constants.CDP_MANAGER).ilks(cdp);\n address usr = IDssCdpManager(Constants.CDP_MANAGER).owns(cdp);\n\n (uint256 supplied, uint256 borrowed) = _getCdpSuppliedAndBorrowed(\n vat,\n usr,\n urn,\n ilk\n );\n\n uint256 ratio = daiUsdcRatio6[cdp];\n\n // Note that supplied and borrowed are in 18 decimals\n // while DAI USDC ratio is in 6 decimals\n return (supplied, borrowed, ratio);\n }\n\n function setDaiUsdcRatio6(uint256 _cdp, uint256 _daiUsdcRatio6) public {\n IDssCdpManager manager = IDssCdpManager(Constants.CDP_MANAGER);\n address owner = manager.owns(_cdp);\n\n require(\n owner == msg.sender || manager.cdpCan(owner, _cdp, msg.sender) == 1,\n \"cdp-not-allowed\"\n );\n\n daiUsdcRatio6[_cdp] = _daiUsdcRatio6;\n }\n}\n"
},
"contracts/uniswapv2/UniswapRouterV2.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.2;\n\ninterface UniswapRouterV2 {\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n\n function removeLiquidity(\n address tokenA,\n address tokenB,\n uint256 liquidity,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n ) external returns (uint256 amountA, uint256 amountB);\n\n function getAmountsOut(uint256 amountIn, address[] calldata path)\n external\n view\n returns (uint256[] memory amounts);\n\n function getAmountsIn(uint256 amountOut, address[] calldata path)\n external\n view\n returns (uint256[] memory amounts);\n\n function swapETHForExactTokens(\n uint256 amountOut,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external payable returns (uint256[] memory amounts);\n}\n\ninterface UniswapPair {\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestamp\n );\n}\n"
}
},
"settings": {
"metadata": {
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers"
],
"": [
"id",
"ast"
]
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment