Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x61014060 | 15049785 | 873 days ago | IN | 0 ETH | 0.19772409 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
RibbonThetaVaultWithSwap
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ISwap} from "../../interfaces/ISwap.sol"; import { RibbonThetaVaultStorage } from "../../storage/RibbonThetaVaultStorage.sol"; import {Vault} from "../../libraries/Vault.sol"; import { VaultLifecycleWithSwap } from "../../libraries/VaultLifecycleWithSwap.sol"; import {ShareMath} from "../../libraries/ShareMath.sol"; import {ILiquidityGauge} from "../../interfaces/ILiquidityGauge.sol"; import {RibbonVault} from "./base/RibbonVault.sol"; import {IVaultPauser} from "../../interfaces/IVaultPauser.sol"; /** * UPGRADEABILITY: Since we use the upgradeable proxy pattern, we must observe * the inheritance chain closely. * Any changes/appends in storage variable needs to happen in RibbonThetaVaultStorage. * RibbonThetaVault should not inherit from any other contract aside from RibbonVault, RibbonThetaVaultStorage */ contract RibbonThetaVaultWithSwap is RibbonVault, RibbonThetaVaultStorage { using SafeERC20 for IERC20; using SafeMath for uint256; using ShareMath for Vault.DepositReceipt; /************************************************ * IMMUTABLES & CONSTANTS ***********************************************/ /// @notice oTokenFactory is the factory contract used to spawn otokens. Used to lookup otokens. address public immutable OTOKEN_FACTORY; // The minimum duration for an option auction. uint256 private constant MIN_AUCTION_DURATION = 5 minutes; /************************************************ * EVENTS ***********************************************/ event OpenShort( address indexed options, uint256 depositAmount, address indexed manager ); event CloseShort( address indexed options, uint256 withdrawAmount, address indexed manager ); event NewOptionStrikeSelected(uint256 strikePrice, uint256 delta); event PremiumDiscountSet( uint256 premiumDiscount, uint256 newPremiumDiscount ); event AuctionDurationSet( uint256 auctionDuration, uint256 newAuctionDuration ); event InstantWithdraw( address indexed account, uint256 amount, uint256 round ); event NewOffer( uint256 swapId, address seller, address oToken, address biddingToken, uint256 minPrice, uint256 minBidSize, uint256 totalSize ); /************************************************ * STRUCTS ***********************************************/ /** * @notice Initialization parameters for the vault. * @param _owner is the owner of the vault with critical permissions * @param _feeRecipient is the address to recieve vault performance and management fees * @param _managementFee is the management fee pct. * @param _performanceFee is the perfomance fee pct. * @param _tokenName is the name of the token * @param _tokenSymbol is the symbol of the token * @param _optionsPremiumPricer is the address of the contract with the black-scholes premium calculation logic * @param _strikeSelection is the address of the contract with strike selection logic * @param _premiumDiscount is the vault's discount applied to the premium */ struct InitParams { address _owner; address _keeper; address _feeRecipient; uint256 _managementFee; uint256 _performanceFee; string _tokenName; string _tokenSymbol; address _optionsPremiumPricer; address _strikeSelection; uint32 _premiumDiscount; } /************************************************ * CONSTRUCTOR & INITIALIZATION ***********************************************/ /** * @notice Initializes the contract with immutable variables * @param _weth is the Wrapped Ether contract * @param _usdc is the USDC contract * @param _oTokenFactory is the contract address for minting new opyn option types (strikes, asset, expiry) * @param _gammaController is the contract address for opyn actions * @param _marginPool is the contract address for providing collateral to opyn * @param _swapContract is the contract address that facilitates bids settlement */ constructor( address _weth, address _usdc, address _oTokenFactory, address _gammaController, address _marginPool, address _swapContract ) RibbonVault(_weth, _usdc, _gammaController, _marginPool, _swapContract) { require(_oTokenFactory != address(0), "!_oTokenFactory"); OTOKEN_FACTORY = _oTokenFactory; } /** * @notice Initializes the OptionVault contract with storage variables. * @param _initParams is the struct with vault initialization parameters * @param _vaultParams is the struct with vault general data */ function initialize( InitParams calldata _initParams, Vault.VaultParams calldata _vaultParams ) external initializer { baseInitialize( _initParams._owner, _initParams._keeper, _initParams._feeRecipient, _initParams._managementFee, _initParams._performanceFee, _initParams._tokenName, _initParams._tokenSymbol, _vaultParams ); require( _initParams._optionsPremiumPricer != address(0), "!_optionsPremiumPricer" ); require( _initParams._strikeSelection != address(0), "!_strikeSelection" ); require( _initParams._premiumDiscount > 0 && _initParams._premiumDiscount < 100 * Vault.PREMIUM_DISCOUNT_MULTIPLIER, "!_premiumDiscount" ); optionsPremiumPricer = _initParams._optionsPremiumPricer; strikeSelection = _initParams._strikeSelection; premiumDiscount = _initParams._premiumDiscount; } /************************************************ * SETTERS ***********************************************/ /** * @notice Sets the new discount on premiums for options we are selling * @param newPremiumDiscount is the premium discount */ function setPremiumDiscount(uint256 newPremiumDiscount) external onlyKeeper { require( newPremiumDiscount > 0 && newPremiumDiscount <= 100 * Vault.PREMIUM_DISCOUNT_MULTIPLIER, "Invalid discount" ); emit PremiumDiscountSet(premiumDiscount, newPremiumDiscount); premiumDiscount = newPremiumDiscount; } /** * @notice Sets the new auction duration * @param newAuctionDuration is the auction duration */ function setAuctionDuration(uint256 newAuctionDuration) external onlyOwner { require( newAuctionDuration >= MIN_AUCTION_DURATION, "Invalid auction duration" ); emit AuctionDurationSet(auctionDuration, newAuctionDuration); auctionDuration = newAuctionDuration; } /** * @notice Sets the new strike selection contract * @param newStrikeSelection is the address of the new strike selection contract */ function setStrikeSelection(address newStrikeSelection) external onlyOwner { require(newStrikeSelection != address(0), "!newStrikeSelection"); strikeSelection = newStrikeSelection; } /** * @notice Sets the new options premium pricer contract * @param newOptionsPremiumPricer is the address of the new strike selection contract */ function setOptionsPremiumPricer(address newOptionsPremiumPricer) external onlyOwner { require( newOptionsPremiumPricer != address(0), "!newOptionsPremiumPricer" ); optionsPremiumPricer = newOptionsPremiumPricer; } /** * @notice Optionality to set strike price manually * Should be called after closeRound if we are setting current week's strike * @param strikePrice is the strike price of the new oTokens (decimals = 8) */ function setStrikePrice(uint128 strikePrice) external onlyOwner { require(strikePrice > 0, "!strikePrice"); overriddenStrikePrice = strikePrice; lastStrikeOverrideRound = vaultState.round; } /** * @notice Sets the new liquidityGauge contract for this vault * @param newLiquidityGauge is the address of the new liquidityGauge contract */ function setLiquidityGauge(address newLiquidityGauge) external onlyOwner { liquidityGauge = newLiquidityGauge; } /** * @notice Sets oToken Premium * @param minPrice is the new oToken Premium in the units of 10**18 */ function setMinPrice(uint256 minPrice) external onlyKeeper { require(minPrice > 0, "!minPrice"); currentOtokenPremium = minPrice; } /** * @notice Sets the new Vault Pauser contract for this vault * @param newVaultPauser is the address of the new vaultPauser contract */ function setVaultPauser(address newVaultPauser) external onlyOwner { vaultPauser = newVaultPauser; } /** * @notice Sets the new offerExecutor * @param newOfferExecutor is the address of the new offerExecutor */ function setNewOfferExecutor(address newOfferExecutor) external onlyOwner { require(newOfferExecutor != address(0), "!newOfferExecutor"); offerExecutor = newOfferExecutor; } /************************************************ * VAULT OPERATIONS ***********************************************/ /** * @notice Withdraws the assets on the vault using the outstanding `DepositReceipt.amount` * @param amount is the amount to withdraw */ function withdrawInstantly(uint256 amount) external nonReentrant { Vault.DepositReceipt storage depositReceipt = depositReceipts[msg.sender]; uint256 currentRound = vaultState.round; require(amount > 0, "!amount"); require(depositReceipt.round == currentRound, "Invalid round"); uint256 receiptAmount = depositReceipt.amount; require(receiptAmount >= amount, "Exceed amount"); // Subtraction underflow checks already ensure it is smaller than uint104 depositReceipt.amount = uint104(receiptAmount.sub(amount)); vaultState.totalPending = uint128( uint256(vaultState.totalPending).sub(amount) ); emit InstantWithdraw(msg.sender, amount, currentRound); transferAsset(msg.sender, amount); } /** * @notice Initiates a withdrawal that can be processed once the round completes * @param numShares is the number of shares to withdraw */ function initiateWithdraw(uint256 numShares) external nonReentrant { _initiateWithdraw(numShares); currentQueuedWithdrawShares = currentQueuedWithdrawShares.add( numShares ); } /** * @notice Completes a scheduled withdrawal from a past round. Uses finalized pps for the round */ function completeWithdraw() external nonReentrant { uint256 withdrawAmount = _completeWithdraw(); lastQueuedWithdrawAmount = uint128( uint256(lastQueuedWithdrawAmount).sub(withdrawAmount) ); } /** * @notice Stakes a users vault shares * @param numShares is the number of shares to stake */ function stake(uint256 numShares) external nonReentrant { address _liquidityGauge = liquidityGauge; require(_liquidityGauge != address(0)); // Removed revert msgs due to contract size limit require(numShares > 0); uint256 heldByAccount = balanceOf(msg.sender); if (heldByAccount < numShares) { _redeem(numShares.sub(heldByAccount), false); } _transfer(msg.sender, address(this), numShares); _approve(address(this), _liquidityGauge, numShares); ILiquidityGauge(_liquidityGauge).deposit(numShares, msg.sender, false); } /** * @notice Closes the existing short and calculate the shares to mint, new price per share & amount of funds to re-allocate as collateral for the new round * Since we are incrementing the round here, the options are sold in the beginning of a round * instead of at the end of the round. For example, at round 1, we don't sell any options. We * start selling options at the beginning of round 2. */ function closeRound() external nonReentrant { address oldOption = optionState.currentOption; require( oldOption != address(0) || vaultState.round == 1, "Round closed" ); _closeShort(optionState.currentOption); uint256 currQueuedWithdrawShares = currentQueuedWithdrawShares; (uint256 lockedBalance, uint256 queuedWithdrawAmount) = _closeRound( uint256(lastQueuedWithdrawAmount), currQueuedWithdrawShares ); lastQueuedWithdrawAmount = queuedWithdrawAmount; uint256 newQueuedWithdrawShares = uint256(vaultState.queuedWithdrawShares).add( currQueuedWithdrawShares ); ShareMath.assertUint128(newQueuedWithdrawShares); vaultState.queuedWithdrawShares = uint128(newQueuedWithdrawShares); currentQueuedWithdrawShares = 0; ShareMath.assertUint104(lockedBalance); vaultState.lockedAmount = uint104(lockedBalance); uint256 nextOptionReady = block.timestamp.add(DELAY); require( nextOptionReady <= type(uint32).max, "Overflow nextOptionReady" ); optionState.nextOptionReadyAt = uint32(nextOptionReady); } /** * @notice Closes the existing short position for the vault. */ function _closeShort(address oldOption) private { uint256 lockedAmount = vaultState.lockedAmount; if (oldOption != address(0)) { vaultState.lastLockedAmount = uint104(lockedAmount); } vaultState.lockedAmount = 0; optionState.currentOption = address(0); if (oldOption != address(0)) { uint256 withdrawAmount = VaultLifecycleWithSwap.settleShort(GAMMA_CONTROLLER); emit CloseShort(oldOption, withdrawAmount, msg.sender); } } /** * @notice Sets the next option the vault will be shorting */ function commitNextOption() external onlyKeeper nonReentrant { address currentOption = optionState.currentOption; require( currentOption == address(0) && vaultState.round != 1, "Round not closed" ); VaultLifecycleWithSwap.CommitParams memory commitParams = VaultLifecycleWithSwap.CommitParams({ OTOKEN_FACTORY: OTOKEN_FACTORY, USDC: USDC, currentOption: currentOption, delay: DELAY, lastStrikeOverrideRound: lastStrikeOverrideRound, overriddenStrikePrice: overriddenStrikePrice, strikeSelection: strikeSelection, optionsPremiumPricer: optionsPremiumPricer, premiumDiscount: premiumDiscount }); (address otokenAddress, uint256 strikePrice, uint256 delta) = VaultLifecycleWithSwap.commitNextOption( commitParams, vaultParams, vaultState ); emit NewOptionStrikeSelected(strikePrice, delta); optionState.nextOption = otokenAddress; } /** * @notice Rolls the vault's funds into a new short position and create a new offer. */ function rollToNextOption() external onlyKeeper nonReentrant { address newOption = optionState.nextOption; require(newOption != address(0), "!nextOption"); optionState.currentOption = newOption; optionState.nextOption = address(0); uint256 lockedBalance = vaultState.lockedAmount; emit OpenShort(newOption, lockedBalance, msg.sender); VaultLifecycleWithSwap.createShort( GAMMA_CONTROLLER, MARGIN_POOL, newOption, lockedBalance ); _createOffer(); } function _createOffer() private { address currentOtoken = optionState.currentOption; uint256 currOtokenPremium = currentOtokenPremium; optionAuctionID = VaultLifecycleWithSwap.createOffer( currentOtoken, currOtokenPremium, SWAP_CONTRACT, vaultParams ); } /** * @notice Settle current offer */ function settleOffer(ISwap.Bid[] calldata bids) external onlyOfferExecutor nonReentrant { ISwap(SWAP_CONTRACT).settleOffer(optionAuctionID, bids); } /** * @notice Burn the remaining oTokens left over */ function burnRemainingOTokens() external onlyKeeper nonReentrant { uint256 unlockedAssetAmount = VaultLifecycleWithSwap.burnOtokens( GAMMA_CONTROLLER, optionState.currentOption ); vaultState.lockedAmount = uint104( uint256(vaultState.lockedAmount).sub(unlockedAssetAmount) ); } /** * @notice pause a user's vault position */ function pausePosition() external { address _vaultPauserAddress = vaultPauser; require(_vaultPauserAddress != address(0)); // Removed revert msgs due to contract size limit _redeem(0, true); uint256 heldByAccount = balanceOf(msg.sender); _approve(msg.sender, _vaultPauserAddress, heldByAccount); IVaultPauser(_vaultPauserAddress).pausePosition( msg.sender, heldByAccount ); } /** * @dev Throws if called by any account other than the offerExecutor. */ modifier onlyOfferExecutor() { require(msg.sender == offerExecutor, "!offerExecutor"); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; interface ISwap { struct Offer { // 32 byte slot 1, partial fill // Seller wallet address address seller; // 32 byte slot 2 // Addess of oToken address oToken; // Price per oToken denominated in biddingToken uint96 minPrice; // 32 byte slot 3 // ERC20 Token to bid for oToken address biddingToken; // Minimum oToken amount acceptable for a single bid uint96 minBidSize; // 32 byte slot 4 // Total available oToken amount uint128 totalSize; // Remaining available oToken amount // This figure is updated after each successfull swap uint128 availableSize; // 32 byte slot 5 // Amount of biddingToken received // This figure is updated after each successfull swap uint256 totalSales; } struct Bid { // ID assigned to offers uint256 swapId; // Number only used once for each wallet uint256 nonce; // Signer wallet address address signerWallet; // Amount of biddingToken offered by signer uint256 sellAmount; // Amount of oToken requested by signer uint256 buyAmount; // Referrer wallet address address referrer; // Signature recovery id uint8 v; // r portion of the ECSDA signature bytes32 r; // s portion of the ECSDA signature bytes32 s; } struct OfferDetails { // Seller wallet address address seller; // Addess of oToken address oToken; // Price per oToken denominated in biddingToken uint256 minPrice; // ERC20 Token to bid for oToken address biddingToken; // Minimum oToken amount acceptable for a single bid uint256 minBidSize; } event Swap( uint256 indexed swapId, uint256 nonce, address indexed signerWallet, uint256 signerAmount, uint256 sellerAmount, address referrer, uint256 feeAmount ); event NewOffer( uint256 swapId, address seller, address oToken, address biddingToken, uint256 minPrice, uint256 minBidSize, uint256 totalSize ); event SetFee(address referrer, uint256 fee); event SettleOffer(uint256 swapId); event Cancel(uint256 indexed nonce, address indexed signerWallet); event Authorize(address indexed signer, address indexed signerWallet); event Revoke(address indexed signer, address indexed signerWallet); function createOffer( address oToken, address biddingToken, uint96 minPrice, uint96 minBidSize, uint128 totalSize ) external returns (uint256 swapId); function settleOffer(uint256 swapId, Bid[] calldata bids) external; function cancelNonce(uint256[] calldata nonces) external; function check(Bid calldata bid) external view returns (uint256, bytes32[] memory); function averagePriceForOffer(uint256 swapId) external view returns (uint256); function authorize(address sender) external; function revoke() external; function nonceUsed(address, uint256) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; abstract contract RibbonThetaVaultStorageV1 { // Logic contract used to price options address public optionsPremiumPricer; // Logic contract used to select strike prices address public strikeSelection; // Premium discount on options we are selling (thousandths place: 000 - 999) uint256 public premiumDiscount; // Current oToken premium uint256 public currentOtokenPremium; // Last round id at which the strike was manually overridden uint16 public lastStrikeOverrideRound; // Price last overridden strike set to uint256 public overriddenStrikePrice; // Auction duration uint256 public auctionDuration; // Auction id of current option uint256 public optionAuctionID; } abstract contract RibbonThetaVaultStorageV2 { // Amount locked for scheduled withdrawals last week; uint256 public lastQueuedWithdrawAmount; } abstract contract RibbonThetaVaultStorageV3 { // DEPRECATED: Auction will be denominated in USDC if true bool private _isUsdcAuction; // DEPRECATED: Path for swaps bytes private _swapPath; } abstract contract RibbonThetaVaultStorageV4 { // LiquidityGauge contract for the vault address public liquidityGauge; } abstract contract RibbonThetaVaultStorageV5 { // OptionsPurchaseQueue contract for selling options address public optionsPurchaseQueue; } abstract contract RibbonThetaVaultStorageV6 { // Queued withdraw shares for the current round uint256 public currentQueuedWithdrawShares; } abstract contract RibbonThetaVaultStorageV7 { // Vault Pauser Contract for the vault address public vaultPauser; } abstract contract RibbonThetaVaultStorageV8 { // Executor role for Swap offers address public offerExecutor; } // We are following Compound's method of upgrading new contract implementations // When we need to add new storage variables, we create a new version of RibbonThetaVaultStorage // e.g. RibbonThetaVaultStorage<versionNumber>, so finally it would look like // contract RibbonThetaVaultStorage is RibbonThetaVaultStorageV1, RibbonThetaVaultStorageV2 abstract contract RibbonThetaVaultStorage is RibbonThetaVaultStorageV1, RibbonThetaVaultStorageV2, RibbonThetaVaultStorageV3, RibbonThetaVaultStorageV4, RibbonThetaVaultStorageV5, RibbonThetaVaultStorageV6, RibbonThetaVaultStorageV7, RibbonThetaVaultStorageV8 { }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; library Vault { /************************************************ * IMMUTABLES & CONSTANTS ***********************************************/ // Fees are 6-decimal places. For example: 20 * 10**6 = 20% uint256 internal constant FEE_MULTIPLIER = 10**6; // Premium discount has 1-decimal place. For example: 80 * 10**1 = 80%. Which represents a 20% discount. uint256 internal constant PREMIUM_DISCOUNT_MULTIPLIER = 10; // Otokens have 8 decimal places. uint256 internal constant OTOKEN_DECIMALS = 8; // Percentage of funds allocated to options is 2 decimal places. 10 * 10**2 = 10% uint256 internal constant OPTION_ALLOCATION_MULTIPLIER = 10**2; // Placeholder uint value to prevent cold writes uint256 internal constant PLACEHOLDER_UINT = 1; struct VaultParams { // Option type the vault is selling bool isPut; // Token decimals for vault shares uint8 decimals; // Asset used in Theta / Delta Vault address asset; // Underlying asset of the options sold by vault address underlying; // Minimum supply of the vault shares issued, for ETH it's 10**10 uint56 minimumSupply; // Vault cap uint104 cap; } struct OptionState { // Option that the vault is shorting / longing in the next cycle address nextOption; // Option that the vault is currently shorting / longing address currentOption; // The timestamp when the `nextOption` can be used by the vault uint32 nextOptionReadyAt; } struct VaultState { // 32 byte slot 1 // Current round number. `round` represents the number of `period`s elapsed. uint16 round; // Amount that is currently locked for selling options uint104 lockedAmount; // Amount that was locked for selling options in the previous round // used for calculating performance fee deduction uint104 lastLockedAmount; // 32 byte slot 2 // Stores the total tally of how much of `asset` there is // to be used to mint rTHETA tokens uint128 totalPending; // Total amount of queued withdrawal shares from previous rounds (doesn't include the current round) uint128 queuedWithdrawShares; } struct DepositReceipt { // Maximum of 65535 rounds. Assuming 1 round is 7 days, maximum is 1256 years. uint16 round; // Deposit amount, max 20,282,409,603,651 or 20 trillion ETH deposit uint104 amount; // Unredeemed shares balance uint128 unredeemedShares; } struct Withdrawal { // Maximum of 65535 rounds. Assuming 1 round is 7 days, maximum is 1256 years. uint16 round; // Number of shares withdrawn uint128 shares; } struct AuctionSellOrder { // Amount of `asset` token offered in auction uint96 sellAmount; // Amount of oToken requested in auction uint96 buyAmount; // User Id of delta vault in latest gnosis auction uint64 userId; } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Vault} from "./Vault.sol"; import {ShareMath} from "./ShareMath.sol"; import {IStrikeSelection} from "../interfaces/IRibbon.sol"; import {GnosisAuction} from "./GnosisAuction.sol"; import { IOtokenFactory, IOtoken, IController, GammaTypes } from "../interfaces/GammaInterface.sol"; import {IERC20Detailed} from "../interfaces/IERC20Detailed.sol"; import {ISwap} from "../interfaces/ISwap.sol"; import {IOptionsPurchaseQueue} from "../interfaces/IOptionsPurchaseQueue.sol"; import {SupportsNonCompliantERC20} from "./SupportsNonCompliantERC20.sol"; import {IOptionsPremiumPricer} from "../interfaces/IRibbon.sol"; library VaultLifecycleWithSwap { using SafeMath for uint256; using SupportsNonCompliantERC20 for IERC20; using SafeERC20 for IERC20; struct CommitParams { address OTOKEN_FACTORY; address USDC; address currentOption; uint256 delay; uint16 lastStrikeOverrideRound; uint256 overriddenStrikePrice; address strikeSelection; address optionsPremiumPricer; uint256 premiumDiscount; } /** * @notice Sets the next option the vault will be shorting, and calculates its premium for the auction * @param commitParams is the struct with details on previous option and strike selection details * @param vaultParams is the struct with vault general data * @param vaultState is the struct with vault accounting state * @return otokenAddress is the address of the new option * @return strikePrice is the strike price of the new option * @return delta is the delta of the new option */ function commitNextOption( CommitParams calldata commitParams, Vault.VaultParams storage vaultParams, Vault.VaultState storage vaultState ) external returns ( address otokenAddress, uint256 strikePrice, uint256 delta ) { uint256 expiry = getNextExpiry(commitParams.currentOption); IStrikeSelection selection = IStrikeSelection(commitParams.strikeSelection); bool isPut = vaultParams.isPut; address underlying = vaultParams.underlying; address asset = vaultParams.asset; (strikePrice, delta) = commitParams.lastStrikeOverrideRound == vaultState.round ? (commitParams.overriddenStrikePrice, selection.delta()) : selection.getStrikePrice(expiry, isPut); require(strikePrice != 0, "!strikePrice"); // retrieve address if option already exists, or deploy it otokenAddress = getOrDeployOtoken( commitParams, vaultParams, underlying, asset, strikePrice, expiry, isPut ); return (otokenAddress, strikePrice, delta); } /** * @notice Verify the otoken has the correct parameters to prevent vulnerability to opyn contract changes * @param otokenAddress is the address of the otoken * @param vaultParams is the struct with vault general data * @param collateralAsset is the address of the collateral asset * @param USDC is the address of usdc * @param delay is the delay between commitAndClose and rollToNextOption */ function verifyOtoken( address otokenAddress, Vault.VaultParams storage vaultParams, address collateralAsset, address USDC, uint256 delay ) private view { require(otokenAddress != address(0), "!otokenAddress"); IOtoken otoken = IOtoken(otokenAddress); require(otoken.isPut() == vaultParams.isPut, "Type mismatch"); require( otoken.underlyingAsset() == vaultParams.underlying, "Wrong underlyingAsset" ); require( otoken.collateralAsset() == collateralAsset, "Wrong collateralAsset" ); // we just assume all options use USDC as the strike require(otoken.strikeAsset() == USDC, "strikeAsset != USDC"); uint256 readyAt = block.timestamp.add(delay); require(otoken.expiryTimestamp() >= readyAt, "Expiry before delay"); } /** * @param decimals is the decimals of the asset * @param totalBalance is the vault's total asset balance * @param currentShareSupply is the supply of the shares invoked with totalSupply() * @param lastQueuedWithdrawAmount is the amount queued for withdrawals from last round * @param performanceFee is the perf fee percent to charge on premiums * @param managementFee is the management fee percent to charge on the AUM */ struct CloseParams { uint256 decimals; uint256 totalBalance; uint256 currentShareSupply; uint256 lastQueuedWithdrawAmount; uint256 performanceFee; uint256 managementFee; uint256 currentQueuedWithdrawShares; } /** * @notice Calculate the shares to mint, new price per share, and amount of funds to re-allocate as collateral for the new round * @param vaultState is the storage variable vaultState passed from RibbonVault * @param params is the rollover parameters passed to compute the next state * @return newLockedAmount is the amount of funds to allocate for the new round * @return queuedWithdrawAmount is the amount of funds set aside for withdrawal * @return newPricePerShare is the price per share of the new round * @return mintShares is the amount of shares to mint from deposits * @return performanceFeeInAsset is the performance fee charged by vault * @return totalVaultFee is the total amount of fee charged by vault */ function closeRound( Vault.VaultState storage vaultState, CloseParams calldata params ) external view returns ( uint256 newLockedAmount, uint256 queuedWithdrawAmount, uint256 newPricePerShare, uint256 mintShares, uint256 performanceFeeInAsset, uint256 totalVaultFee ) { uint256 currentBalance = params.totalBalance; uint256 pendingAmount = vaultState.totalPending; // Total amount of queued withdrawal shares from previous rounds (doesn't include the current round) uint256 lastQueuedWithdrawShares = vaultState.queuedWithdrawShares; // Deduct older queued withdraws so we don't charge fees on them uint256 balanceForVaultFees = currentBalance.sub(params.lastQueuedWithdrawAmount); { (performanceFeeInAsset, , totalVaultFee) = getVaultFees( balanceForVaultFees, vaultState.lastLockedAmount, vaultState.totalPending, params.performanceFee, params.managementFee ); } // Take into account the fee // so we can calculate the newPricePerShare currentBalance = currentBalance.sub(totalVaultFee); { newPricePerShare = ShareMath.pricePerShare( params.currentShareSupply.sub(lastQueuedWithdrawShares), currentBalance.sub(params.lastQueuedWithdrawAmount), pendingAmount, params.decimals ); queuedWithdrawAmount = params.lastQueuedWithdrawAmount.add( ShareMath.sharesToAsset( params.currentQueuedWithdrawShares, newPricePerShare, params.decimals ) ); // After closing the short, if the options expire in-the-money // vault pricePerShare would go down because vault's asset balance decreased. // This ensures that the newly-minted shares do not take on the loss. mintShares = ShareMath.assetToShares( pendingAmount, newPricePerShare, params.decimals ); } return ( currentBalance.sub(queuedWithdrawAmount), // new locked balance subtracts the queued withdrawals queuedWithdrawAmount, newPricePerShare, mintShares, performanceFeeInAsset, totalVaultFee ); } /** * @notice Creates the actual Opyn short position by depositing collateral and minting otokens * @param gammaController is the address of the opyn controller contract * @param marginPool is the address of the opyn margin contract which holds the collateral * @param oTokenAddress is the address of the otoken to mint * @param depositAmount is the amount of collateral to deposit * @return the otoken mint amount */ function createShort( address gammaController, address marginPool, address oTokenAddress, uint256 depositAmount ) external returns (uint256) { IController controller = IController(gammaController); uint256 newVaultID = (controller.getAccountVaultCounter(address(this))).add(1); // An otoken's collateralAsset is the vault's `asset` // So in the context of performing Opyn short operations we call them collateralAsset IOtoken oToken = IOtoken(oTokenAddress); address collateralAsset = oToken.collateralAsset(); uint256 collateralDecimals = uint256(IERC20Detailed(collateralAsset).decimals()); uint256 mintAmount; if (oToken.isPut()) { // For minting puts, there will be instances where the full depositAmount will not be used for minting. // This is because of an issue with precision. // // For ETH put options, we are calculating the mintAmount (10**8 decimals) using // the depositAmount (10**18 decimals), which will result in truncation of decimals when scaling down. // As a result, there will be tiny amounts of dust left behind in the Opyn vault when minting put otokens. // // For simplicity's sake, we do not refund the dust back to the address(this) on minting otokens. // We retain the dust in the vault so the calling contract can withdraw the // actual locked amount + dust at settlement. // // To test this behavior, we can console.log // MarginCalculatorInterface(0x7A48d10f372b3D7c60f6c9770B91398e4ccfd3C7).getExcessCollateral(vault) // to see how much dust (or excess collateral) is left behind. mintAmount = depositAmount .mul(10**Vault.OTOKEN_DECIMALS) .mul(10**18) // we use 10**18 to give extra precision .div(oToken.strikePrice().mul(10**(10 + collateralDecimals))); } else { mintAmount = depositAmount; if (collateralDecimals > 8) { uint256 scaleBy = 10**(collateralDecimals.sub(8)); // oTokens have 8 decimals if (mintAmount > scaleBy) { mintAmount = depositAmount.div(scaleBy); // scale down from 10**18 to 10**8 } } } // double approve to fix non-compliant ERC20s IERC20 collateralToken = IERC20(collateralAsset); collateralToken.safeApproveNonCompliant(marginPool, depositAmount); IController.ActionArgs[] memory actions = new IController.ActionArgs[](3); actions[0] = IController.ActionArgs( IController.ActionType.OpenVault, address(this), // owner address(this), // receiver address(0), // asset, otoken newVaultID, // vaultId 0, // amount 0, //index "" //data ); actions[1] = IController.ActionArgs( IController.ActionType.DepositCollateral, address(this), // owner address(this), // address to transfer from collateralAsset, // deposited asset newVaultID, // vaultId depositAmount, // amount 0, //index "" //data ); actions[2] = IController.ActionArgs( IController.ActionType.MintShortOption, address(this), // owner address(this), // address to transfer to oTokenAddress, // option address newVaultID, // vaultId mintAmount, // amount 0, //index "" //data ); controller.operate(actions); return mintAmount; } /** * @notice Close the existing short otoken position. Currently this implementation is simple. * It closes the most recent vault opened by the contract. This assumes that the contract will * only have a single vault open at any given time. Since calling `_closeShort` deletes vaults by calling SettleVault action, this assumption should hold. * @param gammaController is the address of the opyn controller contract * @return amount of collateral redeemed from the vault */ function settleShort(address gammaController) external returns (uint256) { IController controller = IController(gammaController); // gets the currently active vault ID uint256 vaultID = controller.getAccountVaultCounter(address(this)); GammaTypes.Vault memory vault = controller.getVault(address(this), vaultID); require(vault.shortOtokens.length > 0, "No short"); // An otoken's collateralAsset is the vault's `asset` // So in the context of performing Opyn short operations we call them collateralAsset IERC20 collateralToken = IERC20(vault.collateralAssets[0]); // The short position has been previously closed, or all the otokens have been burned. // So we return early. if (address(collateralToken) == address(0)) { return 0; } // This is equivalent to doing IERC20(vault.asset).balanceOf(address(this)) uint256 startCollateralBalance = collateralToken.balanceOf(address(this)); // If it is after expiry, we need to settle the short position using the normal way // Delete the vault and withdraw all remaining collateral from the vault IController.ActionArgs[] memory actions = new IController.ActionArgs[](1); actions[0] = IController.ActionArgs( IController.ActionType.SettleVault, address(this), // owner address(this), // address to transfer to address(0), // not used vaultID, // vaultId 0, // not used 0, // not used "" // not used ); controller.operate(actions); uint256 endCollateralBalance = collateralToken.balanceOf(address(this)); return endCollateralBalance.sub(startCollateralBalance); } /** * @notice Exercises the ITM option using existing long otoken position. Currently this implementation is simple. * It calls the `Redeem` action to claim the payout. * @param gammaController is the address of the opyn controller contract * @param oldOption is the address of the old option * @param asset is the address of the vault's asset * @return amount of asset received by exercising the option */ function settleLong( address gammaController, address oldOption, address asset ) external returns (uint256) { IController controller = IController(gammaController); uint256 oldOptionBalance = IERC20(oldOption).balanceOf(address(this)); if (controller.getPayout(oldOption, oldOptionBalance) == 0) { return 0; } uint256 startAssetBalance = IERC20(asset).balanceOf(address(this)); // If it is after expiry, we need to redeem the profits IController.ActionArgs[] memory actions = new IController.ActionArgs[](1); actions[0] = IController.ActionArgs( IController.ActionType.Redeem, address(0), // not used address(this), // address to send profits to oldOption, // address of otoken 0, // not used oldOptionBalance, // otoken balance 0, // not used "" // not used ); controller.operate(actions); uint256 endAssetBalance = IERC20(asset).balanceOf(address(this)); return endAssetBalance.sub(startAssetBalance); } /** * @notice Burn the remaining oTokens left over from auction. Currently this implementation is simple. * It burns oTokens from the most recent vault opened by the contract. This assumes that the contract will * only have a single vault open at any given time. * @param gammaController is the address of the opyn controller contract * @param currentOption is the address of the current option * @return amount of collateral redeemed by burning otokens */ function burnOtokens(address gammaController, address currentOption) external returns (uint256) { uint256 numOTokensToBurn = IERC20(currentOption).balanceOf(address(this)); require(numOTokensToBurn > 0, "No oTokens to burn"); IController controller = IController(gammaController); // gets the currently active vault ID uint256 vaultID = controller.getAccountVaultCounter(address(this)); GammaTypes.Vault memory vault = controller.getVault(address(this), vaultID); require(vault.shortOtokens.length > 0, "No short"); IERC20 collateralToken = IERC20(vault.collateralAssets[0]); uint256 startCollateralBalance = collateralToken.balanceOf(address(this)); // Burning `amount` of oTokens from the ribbon vault, // then withdrawing the corresponding collateral amount from the vault IController.ActionArgs[] memory actions = new IController.ActionArgs[](2); actions[0] = IController.ActionArgs( IController.ActionType.BurnShortOption, address(this), // owner address(this), // address to transfer from address(vault.shortOtokens[0]), // otoken address vaultID, // vaultId numOTokensToBurn, // amount 0, //index "" //data ); actions[1] = IController.ActionArgs( IController.ActionType.WithdrawCollateral, address(this), // owner address(this), // address to transfer to address(collateralToken), // withdrawn asset vaultID, // vaultId vault.collateralAmounts[0].mul(numOTokensToBurn).div( vault.shortAmounts[0] ), // amount 0, //index "" //data ); controller.operate(actions); uint256 endCollateralBalance = collateralToken.balanceOf(address(this)); return endCollateralBalance.sub(startCollateralBalance); } /** * @notice Calculates the performance and management fee for this week's round * @param currentBalance is the balance of funds held on the vault after closing short * @param lastLockedAmount is the amount of funds locked from the previous round * @param pendingAmount is the pending deposit amount * @param performanceFeePercent is the performance fee pct. * @param managementFeePercent is the management fee pct. * @return performanceFeeInAsset is the performance fee * @return managementFeeInAsset is the management fee * @return vaultFee is the total fees */ function getVaultFees( uint256 currentBalance, uint256 lastLockedAmount, uint256 pendingAmount, uint256 performanceFeePercent, uint256 managementFeePercent ) internal pure returns ( uint256 performanceFeeInAsset, uint256 managementFeeInAsset, uint256 vaultFee ) { // At the first round, currentBalance=0, pendingAmount>0 // so we just do not charge anything on the first round uint256 lockedBalanceSansPending = currentBalance > pendingAmount ? currentBalance.sub(pendingAmount) : 0; uint256 _performanceFeeInAsset; uint256 _managementFeeInAsset; uint256 _vaultFee; // Take performance fee and management fee ONLY if difference between // last week and this week's vault deposits, taking into account pending // deposits and withdrawals, is positive. If it is negative, last week's // option expired ITM past breakeven, and the vault took a loss so we // do not collect performance fee for last week if (lockedBalanceSansPending > lastLockedAmount) { _performanceFeeInAsset = performanceFeePercent > 0 ? lockedBalanceSansPending .sub(lastLockedAmount) .mul(performanceFeePercent) .div(100 * Vault.FEE_MULTIPLIER) : 0; _managementFeeInAsset = managementFeePercent > 0 ? lockedBalanceSansPending.mul(managementFeePercent).div( 100 * Vault.FEE_MULTIPLIER ) : 0; _vaultFee = _performanceFeeInAsset.add(_managementFeeInAsset); } return (_performanceFeeInAsset, _managementFeeInAsset, _vaultFee); } /** * @notice Either retrieves the option token if it already exists, or deploy it * @param commitParams is the struct with details on previous option and strike selection details * @param vaultParams is the struct with vault general data * @param underlying is the address of the underlying asset of the option * @param collateralAsset is the address of the collateral asset of the option * @param strikePrice is the strike price of the option * @param expiry is the expiry timestamp of the option * @param isPut is whether the option is a put * @return the address of the option */ function getOrDeployOtoken( CommitParams calldata commitParams, Vault.VaultParams storage vaultParams, address underlying, address collateralAsset, uint256 strikePrice, uint256 expiry, bool isPut ) internal returns (address) { IOtokenFactory factory = IOtokenFactory(commitParams.OTOKEN_FACTORY); address otokenFromFactory = factory.getOtoken( underlying, commitParams.USDC, collateralAsset, strikePrice, expiry, isPut ); if (otokenFromFactory != address(0)) { return otokenFromFactory; } address otoken = factory.createOtoken( underlying, commitParams.USDC, collateralAsset, strikePrice, expiry, isPut ); verifyOtoken( otoken, vaultParams, collateralAsset, commitParams.USDC, commitParams.delay ); return otoken; } function getOTokenPremium( address oTokenAddress, address optionsPremiumPricer, uint256 premiumDiscount ) external view returns (uint256) { return _getOTokenPremium( oTokenAddress, optionsPremiumPricer, premiumDiscount ); } function _getOTokenPremium( address oTokenAddress, address optionsPremiumPricer, uint256 premiumDiscount ) internal view returns (uint256) { IOtoken newOToken = IOtoken(oTokenAddress); IOptionsPremiumPricer premiumPricer = IOptionsPremiumPricer(optionsPremiumPricer); // Apply black-scholes formula (from rvol library) to option given its features // and get price for 100 contracts denominated in the underlying asset for call option // and USDC for put option uint256 optionPremium = premiumPricer.getPremium( newOToken.strikePrice(), newOToken.expiryTimestamp(), newOToken.isPut() ); // Apply a discount to incentivize arbitraguers optionPremium = optionPremium.mul(premiumDiscount).div( 100 * Vault.PREMIUM_DISCOUNT_MULTIPLIER ); require( optionPremium <= type(uint96).max, "optionPremium > type(uint96) max value!" ); require(optionPremium > 0, "!optionPremium"); return optionPremium; } /** * @notice Creates an offer in the Swap Contract * @param currentOtoken is the current otoken address * @param currOtokenPremium is premium for each otoken * @param swapContract the address of the swap contract * @param vaultParams is the struct with vault general data * @return optionAuctionID auction id of the newly created offer */ function createOffer( address currentOtoken, uint256 currOtokenPremium, address swapContract, Vault.VaultParams storage vaultParams ) external returns (uint256 optionAuctionID) { require( currOtokenPremium <= type(uint96).max, "currentOtokenPremium > type(uint96) max value!" ); require(currOtokenPremium > 0, "!currentOtokenPremium"); uint256 oTokenBalance = IERC20(currentOtoken).balanceOf(address(this)); require( oTokenBalance <= type(uint128).max, "oTokenBalance > type(uint128) max value!" ); // Use safeIncrease instead of safeApproval because safeApproval is only used for initial // approval and cannot be called again. Using safeIncrease allow us to call _createOffer // even when we are approving the same oTokens we have used before. This might happen if // we accidentally burn the oTokens before settlement. uint256 allowance = IERC20(currentOtoken).allowance(address(this), swapContract); if (allowance < oTokenBalance) { IERC20(currentOtoken).safeIncreaseAllowance( swapContract, oTokenBalance.sub(allowance) ); } uint256 decimals = vaultParams.decimals; // If total size is larger than 1, set minimum bid as 1 // Otherwise, set minimum bid to one tenth the total size uint256 minBidSize = oTokenBalance > 10**decimals ? 10**decimals : oTokenBalance.div(10); require( minBidSize <= type(uint96).max, "minBidSize > type(uint96) max value!" ); currOtokenPremium = decimals > 18 ? currOtokenPremium.mul(10**(decimals.sub(18))) : currOtokenPremium.div(10**(uint256(18).sub(decimals))); optionAuctionID = ISwap(swapContract).createOffer( currentOtoken, vaultParams.asset, uint96(currOtokenPremium), uint96(minBidSize), uint128(oTokenBalance) ); } /** * @notice Allocates the vault's minted options to the OptionsPurchaseQueue contract * @dev Skipped if the optionsPurchaseQueue doesn't exist * @param optionsPurchaseQueue is the OptionsPurchaseQueue contract * @param option is the minted option * @param optionsAmount is the amount of options minted * @param optionAllocation is the maximum % of options to allocate towards the purchase queue (will only allocate * up to the amount that is on the queue) * @return allocatedOptions is the amount of options that ended up getting allocated to the OptionsPurchaseQueue */ function allocateOptions( address optionsPurchaseQueue, address option, uint256 optionsAmount, uint256 optionAllocation ) external returns (uint256 allocatedOptions) { // Skip if optionsPurchaseQueue is address(0) if (optionsPurchaseQueue != address(0)) { allocatedOptions = optionsAmount.mul(optionAllocation).div( 100 * Vault.OPTION_ALLOCATION_MULTIPLIER ); allocatedOptions = IOptionsPurchaseQueue(optionsPurchaseQueue) .getOptionsAllocation(address(this), allocatedOptions); if (allocatedOptions != 0) { IERC20(option).approve(optionsPurchaseQueue, allocatedOptions); IOptionsPurchaseQueue(optionsPurchaseQueue).allocateOptions( allocatedOptions ); } } return allocatedOptions; } /** * @notice Sell the allocated options to the purchase queue post auction settlement * @dev Reverts if the auction hasn't settled yet * @param optionsPurchaseQueue is the OptionsPurchaseQueue contract * @param swapContract The address of the swap settlement contract * @return totalPremiums Total premiums earnt by the vault */ function sellOptionsToQueue( address optionsPurchaseQueue, address swapContract, uint256 optionAuctionID ) external returns (uint256) { uint256 settlementPrice = getAuctionSettlementPrice(swapContract, optionAuctionID); require(settlementPrice != 0, "!settlementPrice"); return IOptionsPurchaseQueue(optionsPurchaseQueue).sellToBuyers( settlementPrice ); } /** * @notice Gets the settlement price of a settled auction * @param swapContract The address of the swap settlement contract * @param optionAuctionID is the offer ID * @return settlementPrice Auction settlement price */ function getAuctionSettlementPrice( address swapContract, uint256 optionAuctionID ) public view returns (uint256) { return ISwap(swapContract).averagePriceForOffer(optionAuctionID); } /** * @notice Verify the constructor params satisfy requirements * @param owner is the owner of the vault with critical permissions * @param feeRecipient is the address to recieve vault performance and management fees * @param performanceFee is the perfomance fee pct. * @param tokenName is the name of the token * @param tokenSymbol is the symbol of the token * @param _vaultParams is the struct with vault general data */ function verifyInitializerParams( address owner, address keeper, address feeRecipient, uint256 performanceFee, uint256 managementFee, string calldata tokenName, string calldata tokenSymbol, Vault.VaultParams calldata _vaultParams ) external pure { require(owner != address(0), "!owner"); require(keeper != address(0), "!keeper"); require(feeRecipient != address(0), "!feeRecipient"); require( performanceFee < 100 * Vault.FEE_MULTIPLIER, "performanceFee >= 100%" ); require( managementFee < 100 * Vault.FEE_MULTIPLIER, "managementFee >= 100%" ); require(bytes(tokenName).length > 0, "!tokenName"); require(bytes(tokenSymbol).length > 0, "!tokenSymbol"); require(_vaultParams.asset != address(0), "!asset"); require(_vaultParams.underlying != address(0), "!underlying"); require(_vaultParams.minimumSupply > 0, "!minimumSupply"); require(_vaultParams.cap > 0, "!cap"); require( _vaultParams.cap > _vaultParams.minimumSupply, "cap has to be higher than minimumSupply" ); } /** * @notice Gets the next option expiry timestamp * @param currentOption is the otoken address that the vault is currently writing */ function getNextExpiry(address currentOption) internal view returns (uint256) { // uninitialized state if (currentOption == address(0)) { return getNextFriday(block.timestamp); } uint256 currentExpiry = IOtoken(currentOption).expiryTimestamp(); // After options expiry if no options are written for >1 week // We need to give the ability continue writing options if (block.timestamp > currentExpiry + 7 days) { return getNextFriday(block.timestamp); } return getNextFriday(currentExpiry); } /** * @notice Gets the next options expiry timestamp * @param timestamp is the expiry timestamp of the current option * Reference: https://codereview.stackexchange.com/a/33532 * Examples: * getNextFriday(week 1 thursday) -> week 1 friday * getNextFriday(week 1 friday) -> week 2 friday * getNextFriday(week 1 saturday) -> week 2 friday */ function getNextFriday(uint256 timestamp) internal pure returns (uint256) { // dayOfWeek = 0 (sunday) - 6 (saturday) uint256 dayOfWeek = ((timestamp / 1 days) + 4) % 7; uint256 nextFriday = timestamp + ((7 + 5 - dayOfWeek) % 7) * 1 days; uint256 friday8am = nextFriday - (nextFriday % (24 hours)) + (8 hours); // If the passed timestamp is day=Friday hour>8am, we simply increment it by a week to next Friday if (timestamp >= friday8am) { friday8am += 7 days; } return friday8am; } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {Vault} from "./Vault.sol"; library ShareMath { using SafeMath for uint256; uint256 internal constant PLACEHOLDER_UINT = 1; function assetToShares( uint256 assetAmount, uint256 assetPerShare, uint256 decimals ) internal pure returns (uint256) { // If this throws, it means that vault's roundPricePerShare[currentRound] has not been set yet // which should never happen. // Has to be larger than 1 because `1` is used in `initRoundPricePerShares` to prevent cold writes. require(assetPerShare > PLACEHOLDER_UINT, "Invalid assetPerShare"); return assetAmount.mul(10**decimals).div(assetPerShare); } function sharesToAsset( uint256 shares, uint256 assetPerShare, uint256 decimals ) internal pure returns (uint256) { // If this throws, it means that vault's roundPricePerShare[currentRound] has not been set yet // which should never happen. // Has to be larger than 1 because `1` is used in `initRoundPricePerShares` to prevent cold writes. require(assetPerShare > PLACEHOLDER_UINT, "Invalid assetPerShare"); return shares.mul(assetPerShare).div(10**decimals); } /** * @notice Returns the shares unredeemed by the user given their DepositReceipt * @param depositReceipt is the user's deposit receipt * @param currentRound is the `round` stored on the vault * @param assetPerShare is the price in asset per share * @param decimals is the number of decimals the asset/shares use * @return unredeemedShares is the user's virtual balance of shares that are owed */ function getSharesFromReceipt( Vault.DepositReceipt memory depositReceipt, uint256 currentRound, uint256 assetPerShare, uint256 decimals ) internal pure returns (uint256 unredeemedShares) { if (depositReceipt.round > 0 && depositReceipt.round < currentRound) { uint256 sharesFromRound = assetToShares(depositReceipt.amount, assetPerShare, decimals); return uint256(depositReceipt.unredeemedShares).add(sharesFromRound); } return depositReceipt.unredeemedShares; } function pricePerShare( uint256 totalSupply, uint256 totalBalance, uint256 pendingAmount, uint256 decimals ) internal pure returns (uint256) { uint256 singleShare = 10**decimals; return totalSupply > 0 ? singleShare.mul(totalBalance.sub(pendingAmount)).div( totalSupply ) : singleShare; } /************************************************ * HELPERS ***********************************************/ function assertUint104(uint256 num) internal pure { require(num <= type(uint104).max, "Overflow uint104"); } function assertUint128(uint256 num) internal pure { require(num <= type(uint128).max, "Overflow uint128"); } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; interface ILiquidityGauge { function balanceOf(address) external view returns (uint256); function deposit( uint256 _value, address _addr, bool _claim_rewards ) external; function withdraw(uint256 _value) external; }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import {Vault} from "../../../libraries/Vault.sol"; import { VaultLifecycleWithSwap } from "../../../libraries/VaultLifecycleWithSwap.sol"; import {ShareMath} from "../../../libraries/ShareMath.sol"; import {IWETH} from "../../../interfaces/IWETH.sol"; contract RibbonVault is ReentrancyGuardUpgradeable, OwnableUpgradeable, ERC20Upgradeable { using SafeERC20 for IERC20; using SafeMath for uint256; using ShareMath for Vault.DepositReceipt; /************************************************ * NON UPGRADEABLE STORAGE ***********************************************/ /// @notice Stores the user's pending deposit for the round mapping(address => Vault.DepositReceipt) public depositReceipts; /// @notice On every round's close, the pricePerShare value of an rTHETA token is stored /// This is used to determine the number of shares to be returned /// to a user with their DepositReceipt.depositAmount mapping(uint256 => uint256) public roundPricePerShare; /// @notice Stores pending user withdrawals mapping(address => Vault.Withdrawal) public withdrawals; /// @notice Vault's parameters like cap, decimals Vault.VaultParams public vaultParams; /// @notice Vault's lifecycle state like round and locked amounts Vault.VaultState public vaultState; /// @notice Vault's state of the options sold and the timelocked option Vault.OptionState public optionState; /// @notice Fee recipient for the performance and management fees address public feeRecipient; /// @notice role in charge of weekly vault operations such as rollToNextOption and burnRemainingOTokens // no access to critical vault changes address public keeper; /// @notice Performance fee charged on premiums earned in rollToNextOption. Only charged when there is no loss. uint256 public performanceFee; /// @notice Management fee charged on entire AUM in rollToNextOption. Only charged when there is no loss. uint256 public managementFee; // Gap is left to avoid storage collisions. Though RibbonVault is not upgradeable, we add this as a safety measure. uint256[30] private ____gap; // *IMPORTANT* NO NEW STORAGE VARIABLES SHOULD BE ADDED HERE // This is to prevent storage collisions. All storage variables should be appended to RibbonThetaVaultStorage // or RibbonDeltaVaultStorage instead. Read this documentation to learn more: // https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#modifying-your-contracts /************************************************ * IMMUTABLES & CONSTANTS ***********************************************/ /// @notice WETH9 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 address public immutable WETH; /// @notice USDC 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 address public immutable USDC; /// @notice Deprecated: 15 minute timelock between commitAndClose and rollToNexOption. uint256 public constant DELAY = 0; /// @notice 7 day period between each options sale. uint256 public constant PERIOD = 7 days; // Number of weeks per year = 52.142857 weeks * FEE_MULTIPLIER = 52142857 // Dividing by weeks per year requires doing num.mul(FEE_MULTIPLIER).div(WEEKS_PER_YEAR) uint256 private constant WEEKS_PER_YEAR = 52142857; // GAMMA_CONTROLLER is the top-level contract in Gamma protocol // which allows users to perform multiple actions on their vaults // and positions https://github.com/opynfinance/GammaProtocol/blob/master/contracts/core/Controller.sol address public immutable GAMMA_CONTROLLER; // MARGIN_POOL is Gamma protocol's collateral pool. // Needed to approve collateral.safeTransferFrom for minting otokens. // https://github.com/opynfinance/GammaProtocol/blob/master/contracts/core/MarginPool.sol address public immutable MARGIN_POOL; // SWAP_CONTRACT is a contract for settling bids via signed messages // https://github.com/ribbon-finance/ribbon-v2/blob/master/contracts/utils/Swap.sol address public immutable SWAP_CONTRACT; /************************************************ * EVENTS ***********************************************/ event Deposit(address indexed account, uint256 amount, uint256 round); event InitiateWithdraw( address indexed account, uint256 shares, uint256 round ); event Redeem(address indexed account, uint256 share, uint256 round); event ManagementFeeSet(uint256 managementFee, uint256 newManagementFee); event PerformanceFeeSet(uint256 performanceFee, uint256 newPerformanceFee); event CapSet(uint256 oldCap, uint256 newCap); event Withdraw(address indexed account, uint256 amount, uint256 shares); event CollectVaultFees( uint256 performanceFee, uint256 vaultFee, uint256 round, address indexed feeRecipient ); /************************************************ * CONSTRUCTOR & INITIALIZATION ***********************************************/ /** * @notice Initializes the contract with immutable variables * @param _weth is the Wrapped Ether contract * @param _usdc is the USDC contract * @param _gammaController is the contract address for opyn actions * @param _marginPool is the contract address for providing collateral to opyn * @param _swapContract is the contract address that facilitates bids settlement */ constructor( address _weth, address _usdc, address _gammaController, address _marginPool, address _swapContract ) { require(_weth != address(0), "!_weth"); require(_usdc != address(0), "!_usdc"); require(_swapContract != address(0), "!_swapContract"); require(_gammaController != address(0), "!_gammaController"); require(_marginPool != address(0), "!_marginPool"); WETH = _weth; USDC = _usdc; GAMMA_CONTROLLER = _gammaController; MARGIN_POOL = _marginPool; SWAP_CONTRACT = _swapContract; } /** * @notice Initializes the OptionVault contract with storage variables. */ function baseInitialize( address _owner, address _keeper, address _feeRecipient, uint256 _managementFee, uint256 _performanceFee, string memory _tokenName, string memory _tokenSymbol, Vault.VaultParams calldata _vaultParams ) internal initializer { VaultLifecycleWithSwap.verifyInitializerParams( _owner, _keeper, _feeRecipient, _performanceFee, _managementFee, _tokenName, _tokenSymbol, _vaultParams ); __ReentrancyGuard_init(); __ERC20_init(_tokenName, _tokenSymbol); __Ownable_init(); transferOwnership(_owner); keeper = _keeper; feeRecipient = _feeRecipient; performanceFee = _performanceFee; managementFee = _managementFee.mul(Vault.FEE_MULTIPLIER).div( WEEKS_PER_YEAR ); vaultParams = _vaultParams; uint256 assetBalance = IERC20(vaultParams.asset).balanceOf(address(this)); ShareMath.assertUint104(assetBalance); vaultState.lastLockedAmount = uint104(assetBalance); vaultState.round = 1; } /** * @dev Throws if called by any account other than the keeper. */ modifier onlyKeeper() { require(msg.sender == keeper, "!keeper"); _; } /************************************************ * SETTERS ***********************************************/ /** * @notice Sets the new keeper * @param newKeeper is the address of the new keeper */ function setNewKeeper(address newKeeper) external onlyOwner { require(newKeeper != address(0), "!newKeeper"); keeper = newKeeper; } /** * @notice Sets the new fee recipient * @param newFeeRecipient is the address of the new fee recipient */ function setFeeRecipient(address newFeeRecipient) external onlyOwner { require(newFeeRecipient != address(0), "!newFeeRecipient"); require(newFeeRecipient != feeRecipient, "Must be new feeRecipient"); feeRecipient = newFeeRecipient; } /** * @notice Sets the management fee for the vault * @param newManagementFee is the management fee (6 decimals). ex: 2 * 10 ** 6 = 2% */ function setManagementFee(uint256 newManagementFee) external onlyOwner { require( newManagementFee < 100 * Vault.FEE_MULTIPLIER, "Invalid management fee" ); // We are dividing annualized management fee by num weeks in a year uint256 tmpManagementFee = newManagementFee.mul(Vault.FEE_MULTIPLIER).div(WEEKS_PER_YEAR); emit ManagementFeeSet(managementFee, newManagementFee); managementFee = tmpManagementFee; } /** * @notice Sets the performance fee for the vault * @param newPerformanceFee is the performance fee (6 decimals). ex: 20 * 10 ** 6 = 20% */ function setPerformanceFee(uint256 newPerformanceFee) external onlyOwner { require( newPerformanceFee < 100 * Vault.FEE_MULTIPLIER, "Invalid performance fee" ); emit PerformanceFeeSet(performanceFee, newPerformanceFee); performanceFee = newPerformanceFee; } /** * @notice Sets a new cap for deposits * @param newCap is the new cap for deposits */ function setCap(uint256 newCap) external onlyOwner { require(newCap > 0, "!newCap"); ShareMath.assertUint104(newCap); emit CapSet(vaultParams.cap, newCap); vaultParams.cap = uint104(newCap); } /************************************************ * DEPOSIT & WITHDRAWALS ***********************************************/ /** * @notice Deposits ETH into the contract and mint vault shares. Reverts if the asset is not WETH. */ function depositETH() external payable nonReentrant { require(vaultParams.asset == WETH, "!WETH"); require(msg.value > 0, "!value"); _depositFor(msg.value, msg.sender); IWETH(WETH).deposit{value: msg.value}(); } /** * @notice Deposits the `asset` from msg.sender. * @param amount is the amount of `asset` to deposit */ function deposit(uint256 amount) external nonReentrant { require(amount > 0, "!amount"); _depositFor(amount, msg.sender); // An approve() by the msg.sender is required beforehand IERC20(vaultParams.asset).safeTransferFrom( msg.sender, address(this), amount ); } /** * @notice Deposits the `asset` from msg.sender added to `creditor`'s deposit. * @notice Used for vault -> vault deposits on the user's behalf * @param amount is the amount of `asset` to deposit * @param creditor is the address that can claim/withdraw deposited amount */ function depositFor(uint256 amount, address creditor) external nonReentrant { require(amount > 0, "!amount"); require(creditor != address(0)); _depositFor(amount, creditor); // An approve() by the msg.sender is required beforehand IERC20(vaultParams.asset).safeTransferFrom( msg.sender, address(this), amount ); } /** * @notice Mints the vault shares to the creditor * @param amount is the amount of `asset` deposited * @param creditor is the address to receieve the deposit */ function _depositFor(uint256 amount, address creditor) private { uint256 currentRound = vaultState.round; uint256 totalWithDepositedAmount = totalBalance().add(amount); require(totalWithDepositedAmount <= vaultParams.cap, "Exceed cap"); require( totalWithDepositedAmount >= vaultParams.minimumSupply, "Insufficient balance" ); emit Deposit(creditor, amount, currentRound); Vault.DepositReceipt memory depositReceipt = depositReceipts[creditor]; // If we have an unprocessed pending deposit from the previous rounds, we have to process it. uint256 unredeemedShares = depositReceipt.getSharesFromReceipt( currentRound, roundPricePerShare[depositReceipt.round], vaultParams.decimals ); uint256 depositAmount = amount; // If we have a pending deposit in the current round, we add on to the pending deposit if (currentRound == depositReceipt.round) { uint256 newAmount = uint256(depositReceipt.amount).add(amount); depositAmount = newAmount; } ShareMath.assertUint104(depositAmount); depositReceipts[creditor] = Vault.DepositReceipt({ round: uint16(currentRound), amount: uint104(depositAmount), unredeemedShares: uint128(unredeemedShares) }); uint256 newTotalPending = uint256(vaultState.totalPending).add(amount); ShareMath.assertUint128(newTotalPending); vaultState.totalPending = uint128(newTotalPending); } /** * @notice Initiates a withdrawal that can be processed once the round completes * @param numShares is the number of shares to withdraw */ function _initiateWithdraw(uint256 numShares) internal { require(numShares > 0, "!numShares"); // We do a max redeem before initiating a withdrawal // But we check if they must first have unredeemed shares if ( depositReceipts[msg.sender].amount > 0 || depositReceipts[msg.sender].unredeemedShares > 0 ) { _redeem(0, true); } // This caches the `round` variable used in shareBalances uint256 currentRound = vaultState.round; Vault.Withdrawal storage withdrawal = withdrawals[msg.sender]; bool withdrawalIsSameRound = withdrawal.round == currentRound; emit InitiateWithdraw(msg.sender, numShares, currentRound); uint256 existingShares = uint256(withdrawal.shares); uint256 withdrawalShares; if (withdrawalIsSameRound) { withdrawalShares = existingShares.add(numShares); } else { require(existingShares == 0, "Existing withdraw"); withdrawalShares = numShares; withdrawals[msg.sender].round = uint16(currentRound); } ShareMath.assertUint128(withdrawalShares); withdrawals[msg.sender].shares = uint128(withdrawalShares); _transfer(msg.sender, address(this), numShares); } /** * @notice Completes a scheduled withdrawal from a past round. Uses finalized pps for the round * @return withdrawAmount the current withdrawal amount */ function _completeWithdraw() internal returns (uint256) { Vault.Withdrawal storage withdrawal = withdrawals[msg.sender]; uint256 withdrawalShares = withdrawal.shares; uint256 withdrawalRound = withdrawal.round; // This checks if there is a withdrawal require(withdrawalShares > 0, "Not initiated"); require(withdrawalRound < vaultState.round, "Round not closed"); // We leave the round number as non-zero to save on gas for subsequent writes withdrawals[msg.sender].shares = 0; vaultState.queuedWithdrawShares = uint128( uint256(vaultState.queuedWithdrawShares).sub(withdrawalShares) ); uint256 withdrawAmount = ShareMath.sharesToAsset( withdrawalShares, roundPricePerShare[withdrawalRound], vaultParams.decimals ); emit Withdraw(msg.sender, withdrawAmount, withdrawalShares); _burn(address(this), withdrawalShares); require(withdrawAmount > 0, "!withdrawAmount"); transferAsset(msg.sender, withdrawAmount); return withdrawAmount; } /** * @notice Redeems shares that are owed to the account * @param numShares is the number of shares to redeem */ function redeem(uint256 numShares) external nonReentrant { require(numShares > 0, "!numShares"); _redeem(numShares, false); } /** * @notice Redeems the entire unredeemedShares balance that is owed to the account */ function maxRedeem() external nonReentrant { _redeem(0, true); } /** * @notice Redeems shares that are owed to the account * @param numShares is the number of shares to redeem, could be 0 when isMax=true * @param isMax is flag for when callers do a max redemption */ function _redeem(uint256 numShares, bool isMax) internal { Vault.DepositReceipt memory depositReceipt = depositReceipts[msg.sender]; // This handles the null case when depositReceipt.round = 0 // Because we start with round = 1 at `initialize` uint256 currentRound = vaultState.round; uint256 unredeemedShares = depositReceipt.getSharesFromReceipt( currentRound, roundPricePerShare[depositReceipt.round], vaultParams.decimals ); numShares = isMax ? unredeemedShares : numShares; if (numShares == 0) { return; } require(numShares <= unredeemedShares, "Exceeds available"); // If we have a depositReceipt on the same round, BUT we have some unredeemed shares // we debit from the unredeemedShares, but leave the amount field intact // If the round has past, with no new deposits, we just zero it out for new deposits. if (depositReceipt.round < currentRound) { depositReceipts[msg.sender].amount = 0; } ShareMath.assertUint128(numShares); depositReceipts[msg.sender].unredeemedShares = uint128( unredeemedShares.sub(numShares) ); emit Redeem(msg.sender, numShares, depositReceipt.round); _transfer(address(this), msg.sender, numShares); } /************************************************ * VAULT OPERATIONS ***********************************************/ /** * @notice Helper function that helps to save gas for writing values into the roundPricePerShare map. * Writing `1` into the map makes subsequent writes warm, reducing the gas from 20k to 5k. * Having 1 initialized beforehand will not be an issue as long as we round down share calculations to 0. * @param numRounds is the number of rounds to initialize in the map */ function initRounds(uint256 numRounds) external nonReentrant { require(numRounds > 0, "!numRounds"); uint256 _round = vaultState.round; for (uint256 i = 0; i < numRounds; i++) { uint256 index = _round + i; require(roundPricePerShare[index] == 0, "Initialized"); // AVOID OVERWRITING ACTUAL VALUES roundPricePerShare[index] = ShareMath.PLACEHOLDER_UINT; } } /** * @notice Helper function that performs most administrative tasks * such as minting new shares, getting vault fees, etc. * @param lastQueuedWithdrawAmount is old queued withdraw amount * @param currentQueuedWithdrawShares is the queued withdraw shares for the current round * @return lockedBalance is the new balance used to calculate next option purchase size or collateral size * @return queuedWithdrawAmount is the new queued withdraw amount for this round */ function _closeRound( uint256 lastQueuedWithdrawAmount, uint256 currentQueuedWithdrawShares ) internal returns (uint256 lockedBalance, uint256 queuedWithdrawAmount) { address recipient = feeRecipient; uint256 mintShares; uint256 performanceFeeInAsset; uint256 totalVaultFee; { uint256 newPricePerShare; ( lockedBalance, queuedWithdrawAmount, newPricePerShare, mintShares, performanceFeeInAsset, totalVaultFee ) = VaultLifecycleWithSwap.closeRound( vaultState, VaultLifecycleWithSwap.CloseParams( vaultParams.decimals, IERC20(vaultParams.asset).balanceOf(address(this)), totalSupply(), lastQueuedWithdrawAmount, performanceFee, managementFee, currentQueuedWithdrawShares ) ); // Finalize the pricePerShare at the end of the round uint256 currentRound = vaultState.round; roundPricePerShare[currentRound] = newPricePerShare; emit CollectVaultFees( performanceFeeInAsset, totalVaultFee, currentRound, recipient ); vaultState.totalPending = 0; vaultState.round = uint16(currentRound + 1); } _mint(address(this), mintShares); if (totalVaultFee > 0) { transferAsset(payable(recipient), totalVaultFee); } return (lockedBalance, queuedWithdrawAmount); } /** * @notice Helper function to make either an ETH transfer or ERC20 transfer * @param recipient is the receiving address * @param amount is the transfer amount */ function transferAsset(address recipient, uint256 amount) internal { address asset = vaultParams.asset; if (asset == WETH) { IWETH(WETH).withdraw(amount); (bool success, ) = recipient.call{value: amount}(""); require(success, "Transfer failed"); return; } IERC20(asset).safeTransfer(recipient, amount); } /************************************************ * GETTERS ***********************************************/ /** * @notice Returns the asset balance held on the vault for the account * @param account is the address to lookup balance for * @return the amount of `asset` custodied by the vault for the user */ function accountVaultBalance(address account) external view returns (uint256) { uint256 _decimals = vaultParams.decimals; uint256 assetPerShare = ShareMath.pricePerShare( totalSupply(), totalBalance(), vaultState.totalPending, _decimals ); return ShareMath.sharesToAsset(shares(account), assetPerShare, _decimals); } /** * @notice Getter for returning the account's share balance including unredeemed shares * @param account is the account to lookup share balance for * @return the share balance */ function shares(address account) public view returns (uint256) { (uint256 heldByAccount, uint256 heldByVault) = shareBalances(account); return heldByAccount.add(heldByVault); } /** * @notice Getter for returning the account's share balance split between account and vault holdings * @param account is the account to lookup share balance for * @return heldByAccount is the shares held by account * @return heldByVault is the shares held on the vault (unredeemedShares) */ function shareBalances(address account) public view returns (uint256 heldByAccount, uint256 heldByVault) { Vault.DepositReceipt memory depositReceipt = depositReceipts[account]; if (depositReceipt.round < ShareMath.PLACEHOLDER_UINT) { return (balanceOf(account), 0); } uint256 unredeemedShares = depositReceipt.getSharesFromReceipt( vaultState.round, roundPricePerShare[depositReceipt.round], vaultParams.decimals ); return (balanceOf(account), unredeemedShares); } /** * @notice The price of a unit of share denominated in the `asset` */ function pricePerShare() external view returns (uint256) { return ShareMath.pricePerShare( totalSupply(), totalBalance(), vaultState.totalPending, vaultParams.decimals ); } /** * @notice Returns the vault's total balance, including the amounts locked into a short position * @return total balance of the vault, including the amounts locked in third party protocols */ function totalBalance() public view returns (uint256) { // After calling closeRound, current option is set to none // We also commit the lockedAmount but do not deposit into Opyn // which results in double counting of asset balance and lockedAmount return optionState.currentOption != address(0) ? uint256(vaultState.lockedAmount).add( IERC20(vaultParams.asset).balanceOf(address(this)) ) : IERC20(vaultParams.asset).balanceOf(address(this)); } /** * @notice Returns the token decimals */ function decimals() public view override returns (uint8) { return vaultParams.decimals; } function cap() external view returns (uint256) { return vaultParams.cap; } function nextOptionReadyAt() external view returns (uint256) { return optionState.nextOptionReadyAt; } function currentOption() external view returns (address) { return optionState.currentOption; } function nextOption() external view returns (address) { return optionState.nextOption; } function totalPending() external view returns (uint256) { return vaultState.totalPending; } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; interface IVaultPauser { /// @notice pause vault position of an account with max amount /// @param _account the address of user /// @param _amount amount of shares function pausePosition(address _account, uint256 _amount) external; /// @notice resume vault position of an account with max amount /// @param _vaultAddress the address of vault function resumePosition(address _vaultAddress) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {Vault} from "../libraries/Vault.sol"; interface IRibbonVault { function deposit(uint256 amount) external; function depositETH() external payable; function cap() external view returns (uint256); function depositFor(uint256 amount, address creditor) external; function vaultParams() external view returns (Vault.VaultParams memory); } interface IStrikeSelection { function getStrikePrice(uint256 expiryTimestamp, bool isPut) external view returns (uint256, uint256); function delta() external view returns (uint256); } interface IOptionsPremiumPricer { function getPremium( uint256 strikePrice, uint256 timeToExpiry, bool isPut ) external view returns (uint256); function getPremiumInStables( uint256 strikePrice, uint256 timeToExpiry, bool isPut ) external view returns (uint256); function getOptionDelta( uint256 spotPrice, uint256 strikePrice, uint256 volatility, uint256 expiryTimestamp ) external view returns (uint256 delta); function getUnderlyingPrice() external view returns (uint256); function priceOracle() external view returns (address); function volatilityOracle() external view returns (address); function optionId() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {DSMath} from "../vendor/DSMath.sol"; import {IGnosisAuction} from "../interfaces/IGnosisAuction.sol"; import {IOtoken} from "../interfaces/GammaInterface.sol"; import {IOptionsPremiumPricer} from "../interfaces/IRibbon.sol"; import {Vault} from "./Vault.sol"; import {IRibbonThetaVault} from "../interfaces/IRibbonThetaVault.sol"; library GnosisAuction { using SafeMath for uint256; using SafeERC20 for IERC20; event InitiateGnosisAuction( address indexed auctioningToken, address indexed biddingToken, uint256 auctionCounter, address indexed manager ); event PlaceAuctionBid( uint256 auctionId, address indexed auctioningToken, uint256 sellAmount, uint256 buyAmount, address indexed bidder ); struct AuctionDetails { address oTokenAddress; address gnosisEasyAuction; address asset; uint256 assetDecimals; uint256 oTokenPremium; uint256 duration; } struct BidDetails { address oTokenAddress; address gnosisEasyAuction; address asset; uint256 assetDecimals; uint256 auctionId; uint256 lockedBalance; uint256 optionAllocation; uint256 optionPremium; address bidder; } function startAuction(AuctionDetails calldata auctionDetails) internal returns (uint256 auctionID) { uint256 oTokenSellAmount = getOTokenSellAmount(auctionDetails.oTokenAddress); require(oTokenSellAmount > 0, "No otokens to sell"); IERC20(auctionDetails.oTokenAddress).safeApprove( auctionDetails.gnosisEasyAuction, IERC20(auctionDetails.oTokenAddress).balanceOf(address(this)) ); // minBidAmount is total oTokens to sell * premium per oToken // shift decimals to correspond to decimals of USDC for puts // and underlying for calls uint256 minBidAmount = DSMath.wmul( oTokenSellAmount.mul(10**10), auctionDetails.oTokenPremium ); minBidAmount = auctionDetails.assetDecimals > 18 ? minBidAmount.mul(10**(auctionDetails.assetDecimals.sub(18))) : minBidAmount.div( 10**(uint256(18).sub(auctionDetails.assetDecimals)) ); require( minBidAmount <= type(uint96).max, "optionPremium * oTokenSellAmount > type(uint96) max value!" ); uint256 auctionEnd = block.timestamp.add(auctionDetails.duration); auctionID = IGnosisAuction(auctionDetails.gnosisEasyAuction) .initiateAuction( // address of oToken we minted and are selling auctionDetails.oTokenAddress, // address of asset we want in exchange for oTokens. Should match vault `asset` auctionDetails.asset, // orders can be cancelled at any time during the auction auctionEnd, // order will last for `duration` auctionEnd, // we are selling all of the otokens minus a fee taken by gnosis uint96(oTokenSellAmount), // the minimum we are willing to sell all the oTokens for. A discount is applied on black-scholes price uint96(minBidAmount), // the minimum bidding amount must be 1 * 10 ** -assetDecimals 1, // the min funding threshold 0, // no atomic closure false, // access manager contract address(0), // bytes for storing info like a whitelist for who can bid bytes("") ); emit InitiateGnosisAuction( auctionDetails.oTokenAddress, auctionDetails.asset, auctionID, msg.sender ); } function placeBid(BidDetails calldata bidDetails) internal returns ( uint256 sellAmount, uint256 buyAmount, uint64 userId ) { // calculate how much to allocate sellAmount = bidDetails .lockedBalance .mul(bidDetails.optionAllocation) .div(100 * Vault.OPTION_ALLOCATION_MULTIPLIER); // divide the `asset` sellAmount by the target premium per oToken to // get the number of oTokens to buy (8 decimals) buyAmount = sellAmount .mul(10**(bidDetails.assetDecimals.add(Vault.OTOKEN_DECIMALS))) .div(bidDetails.optionPremium) .div(10**bidDetails.assetDecimals); require( sellAmount <= type(uint96).max, "sellAmount > type(uint96) max value!" ); require( buyAmount <= type(uint96).max, "buyAmount > type(uint96) max value!" ); // approve that amount IERC20(bidDetails.asset).safeApprove( bidDetails.gnosisEasyAuction, sellAmount ); uint96[] memory _minBuyAmounts = new uint96[](1); uint96[] memory _sellAmounts = new uint96[](1); bytes32[] memory _prevSellOrders = new bytes32[](1); _minBuyAmounts[0] = uint96(buyAmount); _sellAmounts[0] = uint96(sellAmount); _prevSellOrders[ 0 ] = 0x0000000000000000000000000000000000000000000000000000000000000001; // place sell order with that amount userId = IGnosisAuction(bidDetails.gnosisEasyAuction).placeSellOrders( bidDetails.auctionId, _minBuyAmounts, _sellAmounts, _prevSellOrders, "0x" ); emit PlaceAuctionBid( bidDetails.auctionId, bidDetails.oTokenAddress, sellAmount, buyAmount, bidDetails.bidder ); return (sellAmount, buyAmount, userId); } function claimAuctionOtokens( Vault.AuctionSellOrder calldata auctionSellOrder, address gnosisEasyAuction, address counterpartyThetaVault ) internal { bytes32 order = encodeOrder( auctionSellOrder.userId, auctionSellOrder.buyAmount, auctionSellOrder.sellAmount ); bytes32[] memory orders = new bytes32[](1); orders[0] = order; IGnosisAuction(gnosisEasyAuction).claimFromParticipantOrder( IRibbonThetaVault(counterpartyThetaVault).optionAuctionID(), orders ); } function getOTokenSellAmount(address oTokenAddress) internal view returns (uint256) { // We take our current oToken balance. That will be our sell amount // but otokens will be transferred to gnosis. uint256 oTokenSellAmount = IERC20(oTokenAddress).balanceOf(address(this)); require( oTokenSellAmount <= type(uint96).max, "oTokenSellAmount > type(uint96) max value!" ); return oTokenSellAmount; } function getOTokenPremiumInStables( address oTokenAddress, address optionsPremiumPricer, uint256 premiumDiscount ) internal view returns (uint256) { IOtoken newOToken = IOtoken(oTokenAddress); IOptionsPremiumPricer premiumPricer = IOptionsPremiumPricer(optionsPremiumPricer); // Apply black-scholes formula (from rvol library) to option given its features // and get price for 100 contracts denominated USDC for both call and put options uint256 optionPremium = premiumPricer.getPremiumInStables( newOToken.strikePrice(), newOToken.expiryTimestamp(), newOToken.isPut() ); // Apply a discount to incentivize arbitraguers optionPremium = optionPremium.mul(premiumDiscount).div( 100 * Vault.PREMIUM_DISCOUNT_MULTIPLIER ); require( optionPremium <= type(uint96).max, "optionPremium > type(uint96) max value!" ); return optionPremium; } function encodeOrder( uint64 userId, uint96 buyAmount, uint96 sellAmount ) internal pure returns (bytes32) { return bytes32( (uint256(userId) << 192) + (uint256(buyAmount) << 96) + uint256(sellAmount) ); } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; library GammaTypes { // vault is a struct of 6 arrays that describe a position a user has, a user can have multiple vaults. struct Vault { // addresses of oTokens a user has shorted (i.e. written) against this vault address[] shortOtokens; // addresses of oTokens a user has bought and deposited in this vault // user can be long oTokens without opening a vault (e.g. by buying on a DEX) // generally, long oTokens will be 'deposited' in vaults to act as collateral // in order to write oTokens against (i.e. in spreads) address[] longOtokens; // addresses of other ERC-20s a user has deposited as collateral in this vault address[] collateralAssets; // quantity of oTokens minted/written for each oToken address in shortOtokens uint256[] shortAmounts; // quantity of oTokens owned and held in the vault for each oToken address in longOtokens uint256[] longAmounts; // quantity of ERC-20 deposited as collateral in the vault for each ERC-20 address in collateralAssets uint256[] collateralAmounts; } } interface IOtoken { function underlyingAsset() external view returns (address); function strikeAsset() external view returns (address); function collateralAsset() external view returns (address); function strikePrice() external view returns (uint256); function expiryTimestamp() external view returns (uint256); function isPut() external view returns (bool); } interface IOtokenFactory { function getOtoken( address _underlyingAsset, address _strikeAsset, address _collateralAsset, uint256 _strikePrice, uint256 _expiry, bool _isPut ) external view returns (address); function createOtoken( address _underlyingAsset, address _strikeAsset, address _collateralAsset, uint256 _strikePrice, uint256 _expiry, bool _isPut ) external returns (address); function getTargetOtokenAddress( address _underlyingAsset, address _strikeAsset, address _collateralAsset, uint256 _strikePrice, uint256 _expiry, bool _isPut ) external view returns (address); event OtokenCreated( address tokenAddress, address creator, address indexed underlying, address indexed strike, address indexed collateral, uint256 strikePrice, uint256 expiry, bool isPut ); } interface IController { // possible actions that can be performed enum ActionType { OpenVault, MintShortOption, BurnShortOption, DepositLongOption, WithdrawLongOption, DepositCollateral, WithdrawCollateral, SettleVault, Redeem, Call, Liquidate } struct ActionArgs { // type of action that is being performed on the system ActionType actionType; // address of the account owner address owner; // address which we move assets from or to (depending on the action type) address secondAddress; // asset that is to be transfered address asset; // index of the vault that is to be modified (if any) uint256 vaultId; // amount of asset that is to be transfered uint256 amount; // each vault can hold multiple short / long / collateral assets // but we are restricting the scope to only 1 of each in this version // in future versions this would be the index of the short / long / collateral asset that needs to be modified uint256 index; // any other data that needs to be passed in for arbitrary function calls bytes data; } struct RedeemArgs { // address to which we pay out the oToken proceeds address receiver; // oToken that is to be redeemed address otoken; // amount of oTokens that is to be redeemed uint256 amount; } function getPayout(address _otoken, uint256 _amount) external view returns (uint256); function operate(ActionArgs[] calldata _actions) external; function getAccountVaultCounter(address owner) external view returns (uint256); function oracle() external view returns (address); function getVault(address _owner, uint256 _vaultId) external view returns (GammaTypes.Vault memory); function getProceed(address _owner, uint256 _vaultId) external view returns (uint256); function isSettlementAllowed( address _underlying, address _strike, address _collateral, uint256 _expiry ) external view returns (bool); } interface IOracle { function setAssetPricer(address _asset, address _pricer) external; function updateAssetPricer(address _asset, address _pricer) external; function getPrice(address _asset) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IERC20Detailed is IERC20 { function decimals() external view returns (uint8); function symbol() external view returns (string calldata); function name() external view returns (string calldata); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IOptionsPurchaseQueue { /** * @dev Contains purchase request info * @param optionsAmount Amount of options to purchase * @param premiums Total premiums the buyer is spending to purchase the options (optionsAmount * ceilingPrice) * We need to track the premiums here since the ceilingPrice could change between the time the purchase was * requested and when the options are sold * @param buyer The buyer requesting this purchase */ struct Purchase { uint128 optionsAmount; // Slot 0 uint128 premiums; address buyer; // Slot 1 } function purchases(address, uint256) external view returns ( uint128, uint128, address ); function totalOptionsAmount(address) external view returns (uint256); function vaultAllocatedOptions(address) external view returns (uint256); function whitelistedBuyer(address) external view returns (bool); function minPurchaseAmount(address) external view returns (uint256); function ceilingPrice(address) external view returns (uint256); function getPurchases(address vault) external view returns (Purchase[] memory); function getPremiums(address vault, uint256 optionsAmount) external view returns (uint256); function getOptionsAllocation(address vault, uint256 allocatedOptions) external view returns (uint256); function requestPurchase(address vault, uint256 optionsAmount) external returns (uint256); function allocateOptions(uint256 allocatedOptions) external returns (uint256); function sellToBuyers(uint256 settlementPrice) external returns (uint256); function cancelAllPurchases(address vault) external; function addWhitelist(address buyer) external; function removeWhitelist(address buyer) external; function setCeilingPrice(address vault, uint256 price) external; function setMinPurchaseAmount(address vault, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /** * This library supports ERC20s that have quirks in their behavior. * One such ERC20 is USDT, which requires allowance to be 0 before calling approve. * We plan to update this library with ERC20s that display such idiosyncratic behavior. */ library SupportsNonCompliantERC20 { address private constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; function safeApproveNonCompliant( IERC20 token, address spender, uint256 amount ) internal { if (address(token) == USDT) { SafeERC20.safeApprove(token, spender, 0); } SafeERC20.safeApprove(token, spender, amount); } }
// SPDX-License-Identifier: MIT /// math.sol -- mixin for inline numerical wizardry // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >0.4.13; library DSMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x <= y ? x : y; } function max(uint256 x, uint256 y) internal pure returns (uint256 z) { return x >= y ? x : y; } function imin(int256 x, int256 y) internal pure returns (int256 z) { return x <= y ? x : y; } function imax(int256 x, int256 y) internal pure returns (int256 z) { return x >= y ? x : y; } uint256 constant WAD = 10**18; uint256 constant RAY = 10**27; //rounds to zero if x*y < WAD / 2 function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, y), WAD / 2) / WAD; } //rounds to zero if x*y < WAD / 2 function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, y), RAY / 2) / RAY; } //rounds to zero if x*y < WAD / 2 function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, WAD), y / 2) / y; } //rounds to zero if x*y < RAY / 2 function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, RAY), y / 2) / y; } // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. // function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; library AuctionType { struct AuctionData { IERC20 auctioningToken; IERC20 biddingToken; uint256 orderCancellationEndDate; uint256 auctionEndDate; bytes32 initialAuctionOrder; uint256 minimumBiddingAmountPerOrder; uint256 interimSumBidAmount; bytes32 interimOrder; bytes32 clearingPriceOrder; uint96 volumeClearingPriceOrder; bool minFundingThresholdNotReached; bool isAtomicClosureAllowed; uint256 feeNumerator; uint256 minFundingThreshold; } } interface IGnosisAuction { function initiateAuction( address _auctioningToken, address _biddingToken, uint256 orderCancellationEndDate, uint256 auctionEndDate, uint96 _auctionedSellAmount, uint96 _minBuyAmount, uint256 minimumBiddingAmountPerOrder, uint256 minFundingThreshold, bool isAtomicClosureAllowed, address accessManagerContract, bytes memory accessManagerContractData ) external returns (uint256); function auctionCounter() external view returns (uint256); function auctionData(uint256 auctionId) external view returns (AuctionType.AuctionData memory); function auctionAccessManager(uint256 auctionId) external view returns (address); function auctionAccessData(uint256 auctionId) external view returns (bytes memory); function FEE_DENOMINATOR() external view returns (uint256); function feeNumerator() external view returns (uint256); function settleAuction(uint256 auctionId) external returns (bytes32); function placeSellOrders( uint256 auctionId, uint96[] memory _minBuyAmounts, uint96[] memory _sellAmounts, bytes32[] memory _prevSellOrders, bytes calldata allowListCallData ) external returns (uint64); function claimFromParticipantOrder( uint256 auctionId, bytes32[] memory orders ) external returns (uint256, uint256); }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; import {Vault} from "../libraries/Vault.sol"; interface IRibbonThetaVault { function currentOption() external view returns (address); function nextOption() external view returns (address); function vaultParams() external view returns (Vault.VaultParams memory); function vaultState() external view returns (Vault.VaultState memory); function optionState() external view returns (Vault.OptionState memory); function optionAuctionID() external view returns (uint256); function pricePerShare() external view returns (uint256); function roundPricePerShare(uint256) external view returns (uint256); function depositFor(uint256 amount, address creditor) external; function initiateWithdraw(uint256 numShares) external; function completeWithdraw() external; function maxRedeem() external; function depositYieldTokenFor(uint256 amount, address creditor) external; function symbol() external view returns (string calldata); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal initializer { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal initializer { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} uint256[45] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity =0.8.4; interface IWETH { function deposit() external payable; function withdraw(uint256) external; function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); function decimals() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": { "contracts/libraries/VaultLifecycleWithSwap.sol": { "VaultLifecycleWithSwap": "0x63b9712f3acf31597595a1d43f7ee0ad2c83357f" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_oTokenFactory","type":"address"},{"internalType":"address","name":"_gammaController","type":"address"},{"internalType":"address","name":"_marginPool","type":"address"},{"internalType":"address","name":"_swapContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAuctionDuration","type":"uint256"}],"name":"AuctionDurationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"CapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"options","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"CloseShort","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"performanceFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vaultFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"},{"indexed":true,"internalType":"address","name":"feeRecipient","type":"address"}],"name":"CollectVaultFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"InitiateWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"InstantWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"managementFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newManagementFee","type":"uint256"}],"name":"ManagementFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"swapId","type":"uint256"},{"indexed":false,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"address","name":"oToken","type":"address"},{"indexed":false,"internalType":"address","name":"biddingToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"minPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minBidSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSize","type":"uint256"}],"name":"NewOffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strikePrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"delta","type":"uint256"}],"name":"NewOptionStrikeSelected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"options","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"OpenShort","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"performanceFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPerformanceFee","type":"uint256"}],"name":"PerformanceFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"premiumDiscount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPremiumDiscount","type":"uint256"}],"name":"PremiumDiscountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"share","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GAMMA_CONTROLLER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MARGIN_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OTOKEN_FACTORY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAP_CONTRACT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accountVaultBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"auctionDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnRemainingOTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"closeRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"commitNextOption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"completeWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentOption","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentOtokenPremium","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentQueuedWithdrawShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"creditor","type":"address"}],"name":"depositFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"depositReceipts","outputs":[{"internalType":"uint16","name":"round","type":"uint16"},{"internalType":"uint104","name":"amount","type":"uint104"},{"internalType":"uint128","name":"unredeemedShares","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numRounds","type":"uint256"}],"name":"initRounds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"uint256","name":"_managementFee","type":"uint256"},{"internalType":"uint256","name":"_performanceFee","type":"uint256"},{"internalType":"string","name":"_tokenName","type":"string"},{"internalType":"string","name":"_tokenSymbol","type":"string"},{"internalType":"address","name":"_optionsPremiumPricer","type":"address"},{"internalType":"address","name":"_strikeSelection","type":"address"},{"internalType":"uint32","name":"_premiumDiscount","type":"uint32"}],"internalType":"struct RibbonThetaVaultWithSwap.InitParams","name":"_initParams","type":"tuple"},{"components":[{"internalType":"bool","name":"isPut","type":"bool"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint56","name":"minimumSupply","type":"uint56"},{"internalType":"uint104","name":"cap","type":"uint104"}],"internalType":"struct Vault.VaultParams","name":"_vaultParams","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numShares","type":"uint256"}],"name":"initiateWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastQueuedWithdrawAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastStrikeOverrideRound","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityGauge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managementFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextOption","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextOptionReadyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"offerExecutor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optionAuctionID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optionState","outputs":[{"internalType":"address","name":"nextOption","type":"address"},{"internalType":"address","name":"currentOption","type":"address"},{"internalType":"uint32","name":"nextOptionReadyAt","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optionsPremiumPricer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optionsPurchaseQueue","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"overriddenStrikePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pausePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"performanceFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"premiumDiscount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numShares","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollToNextOption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAuctionDuration","type":"uint256"}],"name":"setAuctionDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newLiquidityGauge","type":"address"}],"name":"setLiquidityGauge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newManagementFee","type":"uint256"}],"name":"setManagementFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minPrice","type":"uint256"}],"name":"setMinPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newKeeper","type":"address"}],"name":"setNewKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOfferExecutor","type":"address"}],"name":"setNewOfferExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOptionsPremiumPricer","type":"address"}],"name":"setOptionsPremiumPricer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPerformanceFee","type":"uint256"}],"name":"setPerformanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPremiumDiscount","type":"uint256"}],"name":"setPremiumDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"strikePrice","type":"uint128"}],"name":"setStrikePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newStrikeSelection","type":"address"}],"name":"setStrikeSelection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newVaultPauser","type":"address"}],"name":"setVaultPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"swapId","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"signerWallet","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ISwap.Bid[]","name":"bids","type":"tuple[]"}],"name":"settleOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"shareBalances","outputs":[{"internalType":"uint256","name":"heldByAccount","type":"uint256"},{"internalType":"uint256","name":"heldByVault","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"shares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numShares","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strikeSelection","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPending","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultParams","outputs":[{"internalType":"bool","name":"isPut","type":"bool"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint56","name":"minimumSupply","type":"uint56"},{"internalType":"uint104","name":"cap","type":"uint104"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultPauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultState","outputs":[{"internalType":"uint16","name":"round","type":"uint16"},{"internalType":"uint104","name":"lockedAmount","type":"uint104"},{"internalType":"uint104","name":"lastLockedAmount","type":"uint104"},{"internalType":"uint128","name":"totalPending","type":"uint128"},{"internalType":"uint128","name":"queuedWithdrawShares","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawInstantly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawals","outputs":[{"internalType":"uint16","name":"round","type":"uint16"},{"internalType":"uint128","name":"shares","type":"uint128"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101406040523480156200001257600080fd5b506040516200602c3803806200602c833981016040819052620000359162000252565b85858484846001600160a01b0385166200007f5760405162461bcd60e51b8152602060048201526006602482015265042beeecae8d60d31b60448201526064015b60405180910390fd5b6001600160a01b038416620000c05760405162461bcd60e51b8152602060048201526006602482015265215f7573646360d01b604482015260640162000076565b6001600160a01b038116620001095760405162461bcd60e51b815260206004820152600e60248201526d0857dcddd85c10dbdb9d1c9858dd60921b604482015260640162000076565b6001600160a01b038316620001555760405162461bcd60e51b815260206004820152601160248201527010afb3b0b6b6b0a1b7b73a3937b63632b960791b604482015260640162000076565b6001600160a01b0382166200019c5760405162461bcd60e51b815260206004820152600c60248201526b0857db585c99da5b941bdbdb60a21b604482015260640162000076565b6001600160601b0319606095861b811660805293851b841660a05291841b831660c052831b821660e05290911b16610100526001600160a01b038416620002185760405162461bcd60e51b815260206004820152600f60248201526e215f6f546f6b656e466163746f727960881b604482015260640162000076565b50505060601b6001600160601b0319166101205250620002d29050565b80516001600160a01b03811681146200024d57600080fd5b919050565b60008060008060008060c087890312156200026b578182fd5b620002768762000235565b9550620002866020880162000235565b9450620002966040880162000235565b9350620002a66060880162000235565b9250620002b66080880162000235565b9150620002c660a0880162000235565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c615ca46200038860003960008181610ff70152613149015260008181610f4d01528181611e6101526142410152600081816108f8015261277e01526000818161058d01528181611ce4015281816127560152614379015260008181610b42015261316e015260008181610e6301528181612e2601528181612ed20152818161390c01526139490152615ca46000f3fe6080604052600436106104c05760003560e01c80638da5cb5b11610276578063b9f8092b1161014f578063e73c63d5116100c1578063f756fa2111610085578063f756fa2114611107578063f87c7d931461111c578063f957a06714611131578063f9a0be6814611151578063fba7dc6114611172578063fe56e2321461119357600080fd5b8063e73c63d514611074578063e74b981b1461108a578063f2fde38b146110aa578063f6326fb3146110ca578063f656ba51146110d257600080fd5b8063d164cc1511610113578063d164cc1514610f8f578063d5f2638214610faf578063db006a7514610fc5578063db43e86214610fe5578063dd62ed3e14611019578063e278fe6f1461105f57600080fd5b8063b9f8092b14610ef1578063ca59409414610f06578063ce7c2ac214610f1b578063cf3afa5114610f3b578063d13f1b3e14610f6f57600080fd5b8063a497e674116101e8578063aced1661116101ac578063aced166114610e31578063ad5c464814610e51578063ad7a672f14610e85578063afa6626414610e9a578063b4d1d79514610eba578063b6b55f2514610ed157600080fd5b8063a497e67414610d9a578063a6095d6e14610dba578063a694fc3a14610ddb578063a6f7f5d614610dfb578063a9059cbb14610e1157600080fd5b80639fcc2d751161023a5780639fcc2d7514610c0b578063a083ff1714610cb7578063a24e3c7e14610d1a578063a285c9e814610d3a578063a2db9d8314610d5c578063a457c2d714610d7a57600080fd5b80638da5cb5b14610b82578063947061b514610ba057806395d89b4114610bc157806399530b0614610bd65780639be43daa14610beb57600080fd5b806347786d37116103a85780636f31ab341161031a5780637e108d52116102de5780637e108d5214610ab757806383536ff314610ad757806387153eb114610aed5780638778878214610b1a57806389a3027114610b305780638b10cc7c14610b6457600080fd5b80636f31ab34146109d357806370897b23146109e857806370a0823114610a08578063715018a614610a3e5780637a9262a214610a5357600080fd5b80635ea8cd121161036c5780635ea8cd12146108b1578063600a2cfb146108d1578063650cce8a146108e65780636719b2ee1461091a578063692308681461099e57806369b41170146109be57600080fd5b806347786d37146108245780634b2431d914610844578063503c70aa1461085b57806355489bb214610871578063573f0d6e1461089157600080fd5b806330630da4116104415780633ec143d3116104055780633ec143d3146107625780633f23bb73146107905780633f90916a146107b0578063432833a6146107ce5780634603c0aa146107e4578063469048401461080457600080fd5b806330630da4146106ba578063313ce567146106da578063355274ea1461070457806336efd16f14610722578063395093511461074257600080fd5b80631a92f6c2116104885780631a92f6c21461057b5780631cacf9b9146105c757806323b872dd146105e75780632728f333146106075780632775d01c1461069a57600080fd5b8063048bf085146104c557806306fdde03146104e7578063095ea7b3146105125780630cbf54c81461054257806318160ddd14610566575b600080fd5b3480156104d157600080fd5b506104e56104e0366004615200565b6111b3565b005b3480156104f357600080fd5b506104fc611209565b6040516105099190615608565b60405180910390f35b34801561051e57600080fd5b5061053261052d366004615294565b61129b565b6040519015158152602001610509565b34801561054e57600080fd5b5061055860fb5481565b604051908152602001610509565b34801561057257600080fd5b50609954610558565b34801561058757600080fd5b506105af7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610509565b3480156105d357600080fd5b506104e56105e2366004615382565b6112b2565b3480156105f357600080fd5b50610532610602366004615254565b6115ad565b34801561061357600080fd5b5060cf5460d0546106559161ffff8116916001600160681b03620100008304811692600160781b900416906001600160801b0380821691600160801b90041685565b6040805161ffff90961686526001600160681b03948516602087015293909216928401929092526001600160801b03918216606084015216608082015260a001610509565b3480156106a657600080fd5b506104e56106b5366004615405565b611659565b3480156106c657600080fd5b506104e56106d5366004615200565b6117fc565b3480156106e657600080fd5b5060cc54610100900460ff1660405160ff9091168152602001610509565b34801561071057600080fd5b5060ce546001600160681b0316610558565b34801561072e57600080fd5b506104e561073d366004615435565b611894565b34801561074e57600080fd5b5061053261075d366004615294565b61191c565b34801561076e57600080fd5b5060f95461077d9061ffff1681565b60405161ffff9091168152602001610509565b34801561079c57600080fd5b506105586107ab366004615200565b611958565b3480156107bc57600080fd5b5060d0546001600160801b0316610558565b3480156107da57600080fd5b5061055860fc5481565b3480156107f057600080fd5b506104e56107ff366004615200565b6119ab565b34801561081057600080fd5b5060d3546105af906001600160a01b031681565b34801561083057600080fd5b506104e561083f366004615405565b611a4d565b34801561085057600080fd5b506105586101025481565b34801561086757600080fd5b5061055860fd5481565b34801561087d57600080fd5b506104e561088c3660046153de565b611b28565b34801561089d57600080fd5b506104e56108ac366004615200565b611bc0565b3480156108bd57600080fd5b506104e56108cc366004615405565b611c0d565b3480156108dd57600080fd5b506104e5611c78565b3480156108f257600080fd5b506105af7f000000000000000000000000000000000000000000000000000000000000000081565b34801561092657600080fd5b5061096d610935366004615200565b60c96020526000908152604090205461ffff8116906201000081046001600160681b031690600160781b90046001600160801b031683565b6040805161ffff90941684526001600160681b0390921660208401526001600160801b031690820152606001610509565b3480156109aa57600080fd5b506104e56109b93660046152f5565b611dd3565b3480156109ca57600080fd5b50610558600081565b3480156109df57600080fd5b506104e5611ed3565b3480156109f457600080fd5b506104e5610a03366004615405565b611f10565b348015610a1457600080fd5b50610558610a23366004615200565b6001600160a01b031660009081526097602052604090205490565b348015610a4a57600080fd5b506104e5611fd7565b348015610a5f57600080fd5b50610a95610a6e366004615200565b60cb6020526000908152604090205461ffff8116906201000090046001600160801b031682565b6040805161ffff90931683526001600160801b03909116602083015201610509565b348015610ac357600080fd5b506104e5610ad2366004615405565b61200d565b348015610ae357600080fd5b5061055860f75481565b348015610af957600080fd5b50610558610b08366004615405565b60ca6020526000908152604090205481565b348015610b2657600080fd5b5061055860d55481565b348015610b3c57600080fd5b506105af7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b7057600080fd5b5060d2546001600160a01b03166105af565b348015610b8e57600080fd5b506065546001600160a01b03166105af565b348015610bac57600080fd5b50610103546105af906001600160a01b031681565b348015610bcd57600080fd5b506104fc612057565b348015610be257600080fd5b50610558612066565b348015610bf757600080fd5b506104e5610c06366004615405565b6120a0565b348015610c1757600080fd5b5060cc5460cd5460ce54610c679260ff808216936101008304909116926001600160a01b036201000090930483169282169166ffffffffffffff600160a01b90910416906001600160681b031686565b60408051961515875260ff90951660208701526001600160a01b03938416948601949094529116606084015266ffffffffffffff1660808301526001600160681b031660a082015260c001610509565b348015610cc357600080fd5b5060d15460d254610cee916001600160a01b039081169190811690600160a01b900463ffffffff1683565b604080516001600160a01b03948516815293909216602084015263ffffffff1690820152606001610509565b348015610d2657600080fd5b506104e5610d35366004615200565b61219a565b348015610d4657600080fd5b5060d254600160a01b900463ffffffff16610558565b348015610d6857600080fd5b5060d1546001600160a01b03166105af565b348015610d8657600080fd5b50610532610d95366004615294565b612231565b348015610da657600080fd5b506104e5610db5366004615405565b6122ca565b348015610dc657600080fd5b50610104546105af906001600160a01b031681565b348015610de757600080fd5b506104e5610df6366004615405565b612387565b348015610e0757600080fd5b5061055860d65481565b348015610e1d57600080fd5b50610532610e2c366004615294565b612485565b348015610e3d57600080fd5b5060d4546105af906001600160a01b031681565b348015610e5d57600080fd5b506105af7f000000000000000000000000000000000000000000000000000000000000000081565b348015610e9157600080fd5b50610558612492565b348015610ea657600080fd5b5060f5546105af906001600160a01b031681565b348015610ec657600080fd5b5061055862093a8081565b348015610edd57600080fd5b506104e5610eec366004615405565b6125c0565b348015610efd57600080fd5b506104e5612634565b348015610f1257600080fd5b506104e561282a565b348015610f2757600080fd5b50610558610f36366004615200565b6128cd565b348015610f4757600080fd5b506105af7f000000000000000000000000000000000000000000000000000000000000000081565b348015610f7b57600080fd5b506104e5610f8a366004615405565b6128ea565b348015610f9b57600080fd5b506104e5610faa366004615200565b6129af565b348015610fbb57600080fd5b5061055860f85481565b348015610fd157600080fd5b506104e5610fe0366004615405565b612a3e565b348015610ff157600080fd5b506105af7f000000000000000000000000000000000000000000000000000000000000000081565b34801561102557600080fd5b5061055861103436600461521c565b6001600160a01b03918216600090815260986020908152604080832093909416825291909152205490565b34801561106b57600080fd5b506104e5612aab565b34801561108057600080fd5b5061055860fa5481565b34801561109657600080fd5b506104e56110a5366004615200565b612c6b565b3480156110b657600080fd5b506104e56110c5366004615200565b612d5e565b6104e5612df9565b3480156110de57600080fd5b506110f26110ed366004615200565b612f4a565b60408051928352602083019190915201610509565b34801561111357600080fd5b506104e561302d565b34801561112857600080fd5b506104e5613082565b34801561113d57600080fd5b5060f6546105af906001600160a01b031681565b34801561115d57600080fd5b50610100546105af906001600160a01b031681565b34801561117e57600080fd5b50610101546105af906001600160a01b031681565b34801561119f57600080fd5b506104e56111ae366004615405565b6132d4565b6065546001600160a01b031633146111e65760405162461bcd60e51b81526004016111dd9061568a565b60405180910390fd5b61010080546001600160a01b0319166001600160a01b0392909216919091179055565b6060609a805461121890615a6e565b80601f016020809104026020016040519081016040528092919081815260200182805461124490615a6e565b80156112915780601f1061126657610100808354040283529160200191611291565b820191906000526020600020905b81548152906001019060200180831161127457829003601f168201915b5050505050905090565b60006112a83384846133b5565b5060015b92915050565b600054610100900460ff16806112cb575060005460ff16155b6112e75760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015611309576000805461ffff19166101011790555b6113ce6113196020850185615200565b6113296040860160208701615200565b6113396060870160408801615200565b6060870135608088013561135060a08a018a6158a4565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113929250505060c08b018b6158a4565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92506134da915050565b60006113e1610100850160e08601615200565b6001600160a01b031614156114315760405162461bcd60e51b815260206004820152601660248201527510afb7b83a34b7b739a83932b6b4bab6a83934b1b2b960511b60448201526064016111dd565b600061144561012085016101008601615200565b6001600160a01b031614156114905760405162461bcd60e51b815260206004820152601160248201527010afb9ba3934b5b2a9b2b632b1ba34b7b760791b60448201526064016111dd565b60006114a4610140850161012086016154a2565b63ffffffff161180156114d857506114be600a6064615a0c565b6114d0610140850161012086016154a2565b63ffffffff16105b6115185760405162461bcd60e51b81526020600482015260116024820152700857dc1c995b5a5d5b511a5cd8dbdd5b9d607a1b60448201526064016111dd565b611529610100840160e08501615200565b60f580546001600160a01b0319166001600160a01b039290921691909117905561155b61012084016101008501615200565b60f680546001600160a01b0319166001600160a01b039290921691909117905561158d610140840161012085016154a2565b63ffffffff1660f75580156115a8576000805461ff00191690555b505050565b60006115ba848484613719565b6001600160a01b03841660009081526098602090815260408083203384529091529020548281101561163f5760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b60648201526084016111dd565b61164c85338584036133b5565b60019150505b9392505050565b6002600154141561167c5760405162461bcd60e51b81526004016111dd906156e0565b600260015533600090815260c96020526040902060cf5461ffff16826116b45760405162461bcd60e51b81526004016111dd906156bf565b815461ffff1681146116f85760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081c9bdd5b99609a1b60448201526064016111dd565b81546201000090046001600160681b0316838110156117495760405162461bcd60e51b815260206004820152600d60248201526c115e18d9595908185b5bdd5b9d609a1b60448201526064016111dd565b61175381856138e9565b83546001600160681b0391909116620100000262010000600160781b031990911617835560d05461178d906001600160801b0316856138e9565b60d080546001600160801b0319166001600160801b0392909216919091179055604080518581526020810184905233917fab2daf3c146ca6416cbccd2a86ed2ba995e171ef6319df14a38aef01403a9c96910160405180910390a26117f233856138f5565b5050600180555050565b6065546001600160a01b031633146118265760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b0381166118725760405162461bcd60e51b815260206004820152601360248201527210b732bba9ba3934b5b2a9b2b632b1ba34b7b760691b60448201526064016111dd565b60f680546001600160a01b0319166001600160a01b0392909216919091179055565b600260015414156118b75760405162461bcd60e51b81526004016111dd906156e0565b6002600155816118d95760405162461bcd60e51b81526004016111dd906156bf565b6001600160a01b0381166118ec57600080fd5b6118f68282613a56565b60cc54611914906201000090046001600160a01b0316333085613ce8565b505060018055565b3360008181526098602090815260408083206001600160a01b038716845290915281205490916112a89185906119539086906158e9565b6133b5565b60cc5460009060ff610100909104168161198e61197460995490565b61197c612492565b60d0546001600160801b031685613d53565b90506119a361199c856128cd565b8284613d93565b949350505050565b6065546001600160a01b031633146119d55760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b038116611a2b5760405162461bcd60e51b815260206004820152601860248201527f216e65774f7074696f6e735072656d69756d507269636572000000000000000060448201526064016111dd565b60f580546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b03163314611a775760405162461bcd60e51b81526004016111dd9061568a565b60008111611ab15760405162461bcd60e51b81526020600482015260076024820152660216e65774361760cc1b60448201526064016111dd565b611aba81613df5565b60ce54604080516001600160681b039092168252602082018390527f5f86edbb9d92228a9edc3f0ebc0f001bda1ea345ac7335e0eeef3504b31d1a1c910160405180910390a160ce80546cffffffffffffffffffffffffff19166001600160681b0392909216919091179055565b6065546001600160a01b03163314611b525760405162461bcd60e51b81526004016111dd9061568a565b6000816001600160801b031611611b9a5760405162461bcd60e51b815260206004820152600c60248201526b21737472696b65507269636560a01b60448201526064016111dd565b6001600160801b031660fa5560cf5460f9805461ffff191661ffff909216919091179055565b6065546001600160a01b03163314611bea5760405162461bcd60e51b81526004016111dd9061568a565b61010380546001600160a01b0319166001600160a01b0392909216919091179055565b60d4546001600160a01b03163314611c375760405162461bcd60e51b81526004016111dd9061561b565b60008111611c735760405162461bcd60e51b8152602060048201526009602482015268216d696e507269636560b81b60448201526064016111dd565b60f855565b60d4546001600160a01b03163314611ca25760405162461bcd60e51b81526004016111dd9061561b565b60026001541415611cc55760405162461bcd60e51b81526004016111dd906156e0565b600260015560d2546040516358ffbb3d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015290911660248201526000907363b9712f3acf31597595a1d43f7ee0ad2c83357f906358ffbb3d9060440160206040518083038186803b158015611d4c57600080fd5b505af4158015611d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d84919061541d565b60cf54909150611da3906201000090046001600160681b0316826138e9565b60cf80546001600160681b0392909216620100000262010000600160781b03199092169190911790555060018055565b610104546001600160a01b03163314611e1f5760405162461bcd60e51b815260206004820152600e60248201526d10b7b33332b922bc32b1baba37b960911b60448201526064016111dd565b60026001541415611e425760405162461bcd60e51b81526004016111dd906156e0565b600260015560fc54604051633545cbf360e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163d5172fcc91611e999190869086906004016157e1565b600060405180830381600087803b158015611eb357600080fd5b505af1158015611ec7573d6000803e3d6000fd5b50506001805550505050565b60026001541415611ef65760405162461bcd60e51b81526004016111dd906156e0565b6002600181905550611f0a60006001613e3f565b60018055565b6065546001600160a01b03163314611f3a5760405162461bcd60e51b81526004016111dd9061568a565b611f48620f42406064615a0c565b8110611f965760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420706572666f726d616e63652066656500000000000000000060448201526064016111dd565b60d55460408051918252602082018390527f24867dfb6fcb9970a07be21024956524abe7a1837faa903ff0e99aaa40cf893e910160405180910390a160d555565b6065546001600160a01b031633146120015760405162461bcd60e51b81526004016111dd9061568a565b61200b6000613fee565b565b600260015414156120305760405162461bcd60e51b81526004016111dd906156e0565b600260015561203e81614040565b6101025461204c9082614207565b610102555060018055565b6060609b805461121890615a6e565b600061209b61207460995490565b61207c612492565b60d05460cc546001600160801b0390911690610100900460ff16613d53565b905090565b600260015414156120c35760405162461bcd60e51b81526004016111dd906156e0565b6002600155806121025760405162461bcd60e51b815260206004820152600a602482015269216e756d526f756e647360b01b60448201526064016111dd565b60cf5461ffff1660005b8281101561219157600061212082846158e9565b600081815260ca60205260409020549091501561216d5760405162461bcd60e51b815260206004820152600b60248201526a125b9a5d1a585b1a5e995960aa1b60448201526064016111dd565b600090815260ca60205260409020600190558061218981615aa9565b91505061210c565b50506001805550565b6065546001600160a01b031633146121c45760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b03811661220e5760405162461bcd60e51b815260206004820152601160248201527010b732bba7b33332b922bc32b1baba37b960791b60448201526064016111dd565b61010480546001600160a01b0319166001600160a01b0392909216919091179055565b3360009081526098602090815260408083206001600160a01b0386168452909152812054828110156122b35760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016111dd565b6122c033858584036133b5565b5060019392505050565b6065546001600160a01b031633146122f45760405162461bcd60e51b81526004016111dd9061568a565b61012c8110156123465760405162461bcd60e51b815260206004820152601860248201527f496e76616c69642061756374696f6e206475726174696f6e000000000000000060448201526064016111dd565b60fb5460408051918252602082018390527f5acd982e2240ed224a69aa03dab039d3797c108e4b5f288cd7dd6ca181b275f3910160405180910390a160fb55565b600260015414156123aa5760405162461bcd60e51b81526004016111dd906156e0565b6002600155610100546001600160a01b0316806123c657600080fd5b600082116123d357600080fd5b33600090815260976020526040902054828110156123ff576123ff6123f884836138e9565b6000613e3f565b61240a333085613719565b6124153083856133b5565b6040516383df674760e01b815260048101849052336024820152600060448201526001600160a01b038316906383df674790606401600060405180830381600087803b15801561246457600080fd5b505af1158015612478573d6000803e3d6000fd5b5050600180555050505050565b60006112a8338484613719565b60d2546000906001600160a01b03166125255760cc546040516370a0823160e01b8152306004820152620100009091046001600160a01b0316906370a082319060240160206040518083038186803b1580156124ed57600080fd5b505afa158015612501573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209b919061541d565b60cc546040516370a0823160e01b815230600482015261209b916201000090046001600160a01b0316906370a082319060240160206040518083038186803b15801561257057600080fd5b505afa158015612584573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a8919061541d565b60cf546201000090046001600160681b031690614207565b600260015414156125e35760405162461bcd60e51b81526004016111dd906156e0565b6002600155806126055760405162461bcd60e51b81526004016111dd906156bf565b61260f8133613a56565b60cc5461262d906201000090046001600160a01b0316333084613ce8565b5060018055565b60d4546001600160a01b0316331461265e5760405162461bcd60e51b81526004016111dd9061561b565b600260015414156126815760405162461bcd60e51b81526004016111dd906156e0565b600260015560d1546001600160a01b0316806126cd5760405162461bcd60e51b815260206004820152600b60248201526a10b732bc3a27b83a34b7b760a91b60448201526064016111dd565b60d280546001600160a01b03199081166001600160a01b03841690811790925560d18054909116905560cf54604051620100009091046001600160681b03168082529133917f045c558fdce4714c5816d53820d27420f4cd860892df203fe636384d8d19aa019060200160405180910390a3604051632904c23960e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f00000000000000000000000000000000000000000000000000000000000000008116602483015283166044820152606481018290527363b9712f3acf31597595a1d43f7ee0ad2c83357f90632904c2399060840160206040518083038186803b1580156127e957600080fd5b505af41580156127fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612821919061541d565b50611914614213565b610103546001600160a01b03168061284157600080fd5b61284d60006001613e3f565b33600081815260976020526040902054906128699083836133b5565b60405163c9c2d4f560e01b8152336004820152602481018290526001600160a01b0383169063c9c2d4f590604401600060405180830381600087803b1580156128b157600080fd5b505af11580156128c5573d6000803e3d6000fd5b505050505050565b60008060006128db84612f4a565b90925090506119a38282614207565b60d4546001600160a01b031633146129145760405162461bcd60e51b81526004016111dd9061561b565b60008111801561292f575061292b600a6064615a0c565b8111155b61296e5760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a5908191a5cd8dbdd5b9d60821b60448201526064016111dd565b60f75460408051918252602082018390527f4cd657fde404967d63a338fb06c5c98751a9df57dfae6dc333a432faf8a5f656910160405180910390a160f755565b6065546001600160a01b031633146129d95760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b038116612a1c5760405162461bcd60e51b815260206004820152600a60248201526910b732bba5b2b2b832b960b11b60448201526064016111dd565b60d480546001600160a01b0319166001600160a01b0392909216919091179055565b60026001541415612a615760405162461bcd60e51b81526004016111dd906156e0565b600260015580612aa05760405162461bcd60e51b815260206004820152600a602482015269216e756d53686172657360b01b60448201526064016111dd565b61262d816000613e3f565b60026001541415612ace5760405162461bcd60e51b81526004016111dd906156e0565b600260015560d2546001600160a01b031680151580612af3575060cf5461ffff166001145b612b2e5760405162461bcd60e51b815260206004820152600c60248201526b149bdd5b990818db1bdcd95960a21b60448201526064016111dd565b60d254612b43906001600160a01b03166142e5565b6000610102549050600080612b5a60fd548461445b565b60fd81905560d0549193509150600090612b8490600160801b90046001600160801b031685614207565b9050612b8f816146e2565b60d080546001600160801b03808416600160801b029116179055600061010255612bb883613df5565b60cf805462010000600160781b031916620100006001600160681b038616021790556000612be64282614207565b905063ffffffff811115612c3c5760405162461bcd60e51b815260206004820152601860248201527f4f766572666c6f77206e6578744f7074696f6e5265616479000000000000000060448201526064016111dd565b60d2805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055505060018055505050565b6065546001600160a01b03163314612c955760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b038116612cde5760405162461bcd60e51b815260206004820152601060248201526f085b995dd19959549958da5c1a595b9d60821b60448201526064016111dd565b60d3546001600160a01b0382811691161415612d3c5760405162461bcd60e51b815260206004820152601860248201527f4d757374206265206e657720666565526563697069656e74000000000000000060448201526064016111dd565b60d380546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b03163314612d885760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b038116612ded5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016111dd565b612df681613fee565b50565b60026001541415612e1c5760405162461bcd60e51b81526004016111dd906156e0565b600260015560cc547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116620100009092041614612e8d5760405162461bcd60e51b8152602060048201526005602482015264042ae8aa8960db1b60448201526064016111dd565b60003411612ec65760405162461bcd60e51b81526020600482015260066024820152652176616c756560d01b60448201526064016111dd565b612ed03433613a56565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f2b57600080fd5b505af1158015612f3f573d6000803e3d6000fd5b505060018055505050565b6001600160a01b038116600090815260c9602090815260408083208151606081018352905461ffff81168083526201000082046001600160681b031694830194909452600160781b90046001600160801b031691810191909152829160011115612fcc575050506001600160a01b031660009081526097602052604081205491565b60cf54815161ffff908116600090815260ca602052604081205460cc54919361300293869391169190610100900460ff1661472c565b9050613023856001600160a01b031660009081526097602052604090205490565b9590945092505050565b600260015414156130505760405162461bcd60e51b81526004016111dd906156e0565b6002600155600061305f61479d565b60fd5490915061306f90826138e9565b6001600160801b031660fd555060018055565b60d4546001600160a01b031633146130ac5760405162461bcd60e51b81526004016111dd9061561b565b600260015414156130cf5760405162461bcd60e51b81526004016111dd906156e0565b600260015560d2546001600160a01b0316801580156130f5575060cf5461ffff16600114155b6131345760405162461bcd60e51b815260206004820152601060248201526f149bdd5b99081b9bdd0818db1bdcd95960821b60448201526064016111dd565b60408051610120810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f0000000000000000000000000000000000000000000000000000000000000000811660208301528381168284015260006060830181905260f95461ffff16608084015260fa5460a084015260f654821660c084015260f55490911660e083015260f75461010083015291516377e3ce0d60e11b8152909190819081907363b9712f3acf31597595a1d43f7ee0ad2c83357f9063efc79c1a9061321990879060cc9060cf90600401615717565b60606040518083038186803b15801561323157600080fd5b505af4158015613245573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326991906152bf565b604080518381526020810183905293965091945092507fa217999b1c125c2a996f712c5f26a28addad7167bd8a67d5bd5b2a751148abb0910160405180910390a1505060d180546001600160a01b0319166001600160a01b0392909216919091179055505060018055565b6065546001600160a01b031633146132fe5760405162461bcd60e51b81526004016111dd9061568a565b61330c620f42406064615a0c565b81106133535760405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206d616e6167656d656e742066656560501b60448201526064016111dd565b600061337063031ba30961336a84620f424061495a565b90614966565b60d65460408051918252602082018590529192507f4e874b007ab14f7e263baefd44951834c8266f4f224d1092e49e9c254354cc54910160405180910390a160d65550565b6001600160a01b0383166134175760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016111dd565b6001600160a01b0382166134785760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016111dd565b6001600160a01b0383811660008181526098602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600054610100900460ff16806134f3575060005460ff16155b61350f5760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015613531576000805461ffff19166101011790555b60405163c72733f760e01b81527363b9712f3acf31597595a1d43f7ee0ad2c83357f9063c72733f790613576908c908c908c908b908d908c908c908c9060040161550e565b60006040518083038186803b15801561358e57600080fd5b505af41580156135a2573d6000803e3d6000fd5b505050506135ae614972565b6135b884846149e5565b6135c0614a64565b6135c989612d5e565b60d480546001600160a01b03808b166001600160a01b03199283161790925560d38054928a169290911691909117905560d585905561361363031ba30961336a88620f424061495a565b60d6558160cc6136238282615b01565b505060cc546040516370a0823160e01b81523060048201526000916201000090046001600160a01b0316906370a082319060240160206040518083038186803b15801561366f57600080fd5b505afa158015613683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a7919061541d565b90506136b281613df5565b60cf805461ffff196001600160681b03909316600160781b02929092167fffffffff00000000000000000000000000ffffffffffffffffffffffffff0000909216919091176001179055801561370e576000805461ff00191690555b505050505050505050565b6001600160a01b03831661377d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016111dd565b6001600160a01b0382166137df5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016111dd565b6001600160a01b038316600090815260976020526040902054818110156138575760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016111dd565b6001600160a01b0380851660009081526097602052604080822085850390559185168152908120805484929061388e9084906158e9565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516138da91815260200190565b60405180910390a35b50505050565b60006116528284615a2b565b60cc546001600160a01b03620100009091048116907f000000000000000000000000000000000000000000000000000000000000000016811415613a4257604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561399557600080fd5b505af11580156139a9573d6000803e3d6000fd5b505050506000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146139fa576040519150601f19603f3d011682016040523d82523d6000602084013e6139ff565b606091505b50509050806138e35760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b60448201526064016111dd565b6115a86001600160a01b0382168484614acb565b60cf5461ffff166000613a7184613a6b612492565b90614207565b60ce549091506001600160681b0316811115613abc5760405162461bcd60e51b815260206004820152600a6024820152690457863656564206361760b41b60448201526064016111dd565b60cd54600160a01b900466ffffffffffffff16811015613b155760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b60448201526064016111dd565b60408051858152602081018490526001600160a01b038516917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a26001600160a01b038316600090815260c9602090815260408083208151606081018352905461ffff81168083526201000082046001600160681b031683860152600160781b9091046001600160801b031682840152845260ca90925282205460cc54919291613bd4918491879190610100900460ff1661472c565b8251909150869061ffff16851415613c05576020830151600090613c01906001600160681b031689614207565b9150505b613c0e81613df5565b6040805160608101825261ffff80881682526001600160681b0380851660208085019182526001600160801b038089168688019081526001600160a01b038e16600090815260c990935296822095518654935197518216600160781b02600160781b600160f81b03199890951662010000026effffffffffffffffffffffffffffff1990941695169490941791909117949094161790915560d054613cb4911689614207565b9050613cbf816146e2565b60d080546001600160801b0319166001600160801b039290921691909117905550505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526138e39085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614afb565b600080613d6183600a615964565b905060008611613d715780613d89565b613d898661336a613d8288886138e9565b849061495a565b9695505050505050565b600060018311613ddd5760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b60448201526064016111dd565b6119a3613deb83600a615964565b61336a868661495a565b6001600160681b03811115612df65760405162461bcd60e51b815260206004820152601060248201526f13dd995c999b1bddc81d5a5b9d0c4c0d60821b60448201526064016111dd565b33600090815260c9602090815260408083208151606081018352905461ffff8082168084526201000083046001600160681b031684870152600160781b9092046001600160801b03168385015260cf5491865260ca9094529184205460cc5491949290931692613eba9185918591610100900460ff1661472c565b905083613ec75784613ec9565b805b945084613ed7575050505050565b80851115613f1b5760405162461bcd60e51b81526020600482015260116024820152704578636565647320617661696c61626c6560781b60448201526064016111dd565b825161ffff16821115613f485733600090815260c960205260409020805462010000600160781b03191690555b613f51856146e2565b613f5b81866138e9565b33600081815260c960205260409081902080546001600160801b0394909416600160781b02600160781b600160f81b0319909416939093179092558451915190917fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92991613fd49189825261ffff16602082015260400190565b60405180910390a2613fe7303387613719565b5050505050565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000811161407d5760405162461bcd60e51b815260206004820152600a602482015269216e756d53686172657360b01b60448201526064016111dd565b33600090815260c960205260409020546201000090046001600160681b03161515806140c7575033600090815260c96020526040902054600160781b90046001600160801b031615155b156140d8576140d860006001613e3f565b60cf5433600081815260cb60209081526040918290208054835187815261ffff96871693810184905292959194911685149290917f0c53c82ad07e2d592d88ece3b066777dd60f1118e2a081b380efc4358f0d9e2a910160405180910390a281546201000090046001600160801b0316600082156141615761415a8287614207565b90506141c4565b81156141a35760405162461bcd60e51b81526020600482015260116024820152704578697374696e6720776974686472617760781b60448201526064016111dd565b5033600090815260cb60205260409020805461ffff191661ffff8616179055845b6141cd816146e2565b33600081815260cb60205260409020805462010000600160901b031916620100006001600160801b038516021790556128c5903088613719565b600061165282846158e9565b60d25460f8546040516301c6654960e21b81526001600160a01b0392831660048201819052602482018390527f0000000000000000000000000000000000000000000000000000000000000000909316604482015260cc60648201527363b9712f3acf31597595a1d43f7ee0ad2c83357f9063071995249060840160206040518083038186803b1580156142a657600080fd5b505af41580156142ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142de919061541d565b60fc555050565b60cf546201000090046001600160681b03166001600160a01b038216156143315760cf80546cffffffffffffffffffffffffff60781b1916600160781b6001600160681b038416021790555b60cf805462010000600160781b031916905560d280546001600160a01b03191690556001600160a01b0382161561445757604051636c6fe87f60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660048201526000907363b9712f3acf31597595a1d43f7ee0ad2c83357f9063d8dfd0fe9060240160206040518083038186803b1580156143d857600080fd5b505af41580156143ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614410919061541d565b9050336001600160a01b0316836001600160a01b03167f7e830f7c1771deb1bdb35c4a7e6051bbac32b376f7f4e4976b8618b0b11997f7836040516134cd91815260200190565b5050565b60d3546040805160e08101825260cc54610100810460ff16825291516370a0823160e01b815230600482015260009384936001600160a01b039182169385938493849384937363b9712f3acf31597595a1d43f7ee0ad2c83357f9363d9b874389360cf93602084019262010000909104909116906370a082319060240160206040518083038186803b1580156144f057600080fd5b505afa158015614504573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614528919061541d565b815260200161453660995490565b81526020018d815260200160d554815260200160d65481526020018c8152506040518363ffffffff1660e01b81526004016145c392919060006101008201905083825282516020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e08301529392505050565b60c06040518083038186803b1580156145db57600080fd5b505af41580156145ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146139190615459565b60cf5461ffff16600081815260ca60209081526040918290208790558151858152908101849052908101829052969d50949b50919850965094509250906001600160a01b038716907f0a242f7ecaf711036ca770774ceffae28e60ef042ac113ddd187f2631db0c0069060600160405180910390a260d080546001600160801b03191690556146a38160016158e9565b60cf805461ffff191661ffff92909216919091179055506146c690503084614bcd565b80156146d6576146d684826138f5565b505050505b9250929050565b6001600160801b03811115612df65760405162461bcd60e51b815260206004820152601060248201526f09eeccae4ccd8deee40ead2dce86264760831b60448201526064016111dd565b835160009061ffff16158015906147475750845161ffff1684115b1561478957600061476686602001516001600160681b03168585614cac565b6040870151909150614781906001600160801b031682614207565b9150506119a3565b50505050604001516001600160801b031690565b33600090815260cb6020526040812080546001600160801b03620100008204169061ffff16816147ff5760405162461bcd60e51b815260206004820152600d60248201526c139bdd081a5b9a5d1a585d1959609a1b60448201526064016111dd565b60cf5461ffff1681106148475760405162461bcd60e51b815260206004820152601060248201526f149bdd5b99081b9bdd0818db1bdcd95960821b60448201526064016111dd565b33600090815260cb60205260409020805462010000600160901b031916905560d05461488390600160801b90046001600160801b0316836138e9565b60d080546001600160801b03928316600160801b029216919091179055600081815260ca602052604081205460cc546148c691859160ff61010090910416613d93565b604080518281526020810186905291925033917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a261490e3084614d0f565b600081116149505760405162461bcd60e51b815260206004820152600f60248201526e085dda5d1a191c985dd05b5bdd5b9d608a1b60448201526064016111dd565b6119a333826138f5565b60006116528284615a0c565b60006116528284615901565b600054610100900460ff168061498b575060005460ff16155b6149a75760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff161580156149c9576000805461ffff19166101011790555b6149d1614e5d565b8015612df6576000805461ff001916905550565b600054610100900460ff16806149fe575060005460ff16155b614a1a5760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015614a3c576000805461ffff19166101011790555b614a44614ecc565b614a4e8383614f36565b80156115a8576000805461ff0019169055505050565b600054610100900460ff1680614a7d575060005460ff16155b614a995760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015614abb576000805461ffff19166101011790555b614ac3614ecc565b6149d1614fcb565b6040516001600160a01b0383166024820152604481018290526115a890849063a9059cbb60e01b90606401613d1c565b6000614b50826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661502b9092919063ffffffff16565b8051909150156115a85780806020019051810190614b6e9190615366565b6115a85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016111dd565b6001600160a01b038216614c235760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016111dd565b8060996000828254614c3591906158e9565b90915550506001600160a01b03821660009081526097602052604081208054839290614c629084906158e9565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b600060018311614cf65760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b60448201526064016111dd565b6119a38361336a614d0885600a615964565b879061495a565b6001600160a01b038216614d6f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016111dd565b6001600160a01b03821660009081526097602052604090205481811015614de35760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016111dd565b6001600160a01b0383166000908152609760205260408120838303905560998054849290614e12908490615a2b565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b600054610100900460ff1680614e76575060005460ff16155b614e925760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015614eb4576000805461ffff19166101011790555b600180558015612df6576000805461ff001916905550565b600054610100900460ff1680614ee5575060005460ff16155b614f015760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff161580156149d1576000805461ffff19166101011790558015612df6576000805461ff001916905550565b600054610100900460ff1680614f4f575060005460ff16155b614f6b5760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015614f8d576000805461ffff19166101011790555b8251614fa090609a906020860190615136565b508151614fb490609b906020850190615136565b5080156115a8576000805461ff0019169055505050565b600054610100900460ff1680614fe4575060005460ff16155b6150005760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015615022576000805461ffff19166101011790555b6149d133613fee565b60606119a3848460008585843b6150845760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016111dd565b600080866001600160a01b031685876040516150a091906154f2565b60006040518083038185875af1925050503d80600081146150dd576040519150601f19603f3d011682016040523d82523d6000602084013e6150e2565b606091505b50915091506150f28282866150fd565b979650505050505050565b6060831561510c575081611652565b82511561511c5782518084602001fd5b8160405162461bcd60e51b81526004016111dd9190615608565b82805461514290615a6e565b90600052602060002090601f01602090048101928261516457600085556151aa565b82601f1061517d57805160ff19168380011785556151aa565b828001600101855582156151aa579182015b828111156151aa57825182559160200191906001019061518f565b506151b69291506151ba565b5090565b5b808211156151b657600081556001016151bb565b80356151da81615c12565b919050565b80356151da81615c35565b80356151da81615c4a565b80356151da81615c5f565b600060208284031215615211578081fd5b813561165281615c12565b6000806040838503121561522e578081fd5b823561523981615c12565b9150602083013561524981615c12565b809150509250929050565b600080600060608486031215615268578081fd5b833561527381615c12565b9250602084013561528381615c12565b929592945050506040919091013590565b600080604083850312156152a6578182fd5b82356152b181615c12565b946020939093013593505050565b6000806000606084860312156152d3578283fd5b83516152de81615c12565b602085015160409095015190969495509392505050565b60008060208385031215615307578182fd5b823567ffffffffffffffff8082111561531e578384fd5b818501915085601f830112615331578384fd5b81358181111561533f578485fd5b86602061012083028501011115615354578485fd5b60209290920196919550909350505050565b600060208284031215615377578081fd5b815161165281615c27565b60008082840360e0811215615395578283fd5b833567ffffffffffffffff8111156153ab578384fd5b840161014081870312156153bd578384fd5b925060c0601f19820112156153d0578182fd5b506020830190509250929050565b6000602082840312156153ef578081fd5b81356001600160801b0381168114611652578182fd5b600060208284031215615416578081fd5b5035919050565b60006020828403121561542e578081fd5b5051919050565b60008060408385031215615447578182fd5b82359150602083013561524981615c12565b60008060008060008060c08789031215615471578384fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b6000602082840312156154b3578081fd5b813563ffffffff81168114611652578182fd5b600081518084526154de816020860160208601615a42565b601f01601f19169290920160200192915050565b60008251615504818460208701615a42565b9190910192915050565b60006101a060018060a01b03808c168452808b166020850152808a1660408501528860608501528760808501528160a085015261554d828501886154c6565b915083820360c085015261556182876154c6565b92508435915061557082615c27565b90151560e084015260208401359061558782615c5f565b60ff8216610100850152604085013591506155a182615c12565b166101208301526155b4606084016151cf565b6001600160a01b03166101408301526155cf608084016151ea565b66ffffffffffffff166101608301526155ea60a084016151df565b6001600160681b038116610180840152509998505050505050505050565b60208152600061165260208301846154c6565b60208082526007908201526610b5b2b2b832b960c91b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526007908201526608585b5bdd5b9d60ca1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b83516001600160a01b03168152602080850151610160830191615744908401826001600160a01b03169052565b50604085015161575f60408401826001600160a01b03169052565b5060608501516060830152608085015161577f608084018261ffff169052565b5060a085015160a083015260c08501516157a460c08401826001600160a01b03169052565b5060e08501516157bf60e08401826001600160a01b03169052565b5061010094850151948201949094526101208101929092526101409091015290565b838152604060208083018290528282018490526000919060609081850187855b88811015615895578135835283820135848401526158208683016151cf565b6001600160a01b03168684015284820135858401526080808301359084015260a061584c8184016151cf565b6001600160a01b03169084015260c06158668382016151f5565b60ff169084015260e0828101359084015261010080830135908401526101209283019290910190600101615801565b50909998505050505050505050565b6000808335601e198436030181126158ba578283fd5b83018035915067ffffffffffffffff8211156158d4578283fd5b6020019150368190038213156146db57600080fd5b600082198211156158fc576158fc615ac4565b500190565b60008261591c57634e487b7160e01b81526012600452602481fd5b500490565b600181815b8085111561595c57816000190482111561594257615942615ac4565b8085161561594f57918102915b93841c9390800290615926565b509250929050565b6000611652838360008261597a575060016112ac565b81615987575060006112ac565b816001811461599d57600281146159a7576159c3565b60019150506112ac565b60ff8411156159b8576159b8615ac4565b50506001821b6112ac565b5060208310610133831016604e8410600b84101617156159e6575081810a6112ac565b6159f08383615921565b8060001904821115615a0457615a04615ac4565b029392505050565b6000816000190483118215151615615a2657615a26615ac4565b500290565b600082821015615a3d57615a3d615ac4565b500390565b60005b83811015615a5d578181015183820152602001615a45565b838111156138e35750506000910152565b600181811c90821680615a8257607f821691505b60208210811415615aa357634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415615abd57615abd615ac4565b5060010190565b634e487b7160e01b600052601160045260246000fd5b600081356112ac81615c12565b600081356112ac81615c35565b600081356112ac81615c4a565b8135615b0c81615c27565b815460ff19811691151560ff1691821783556020840135615b2c81615c5f565b61ff008160081b169050808361ffff198416171784556040850135615b5081615c12565b6001600160b01b0319929092169092179190911760109190911b62010000600160b01b031617815560018101615ba8615b8b60608501615ada565b82546001600160a01b0319166001600160a01b0391909116178255565b615be1615bb760808501615af4565b82805466ffffffffffffff60a01b191660a09290921b66ffffffffffffff60a01b16919091179055565b50614457615bf160a08401615ae7565b600283016001600160681b0382166001600160681b03198254161781555050565b6001600160a01b0381168114612df657600080fd5b8015158114612df657600080fd5b6001600160681b0381168114612df657600080fd5b66ffffffffffffff81168114612df657600080fd5b60ff81168114612df657600080fdfea2646970667358221220220ea42baa538ad6df1a5280f14eee73d27e2877dc7cbe3ea9702e1fb9e4f82164736f6c63430008040033000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000007c06792af1632e77cb27a558dc0885338f4bdf8e0000000000000000000000004ccc2339f87f6c59c6893e1a678c2266ca58dc720000000000000000000000005934807cc0654d46755ebd2848840b616256c6ef000000000000000000000000f0e5c92cedd66c7985c354c35e2bc37e685b99da
Deployed Bytecode
0x6080604052600436106104c05760003560e01c80638da5cb5b11610276578063b9f8092b1161014f578063e73c63d5116100c1578063f756fa2111610085578063f756fa2114611107578063f87c7d931461111c578063f957a06714611131578063f9a0be6814611151578063fba7dc6114611172578063fe56e2321461119357600080fd5b8063e73c63d514611074578063e74b981b1461108a578063f2fde38b146110aa578063f6326fb3146110ca578063f656ba51146110d257600080fd5b8063d164cc1511610113578063d164cc1514610f8f578063d5f2638214610faf578063db006a7514610fc5578063db43e86214610fe5578063dd62ed3e14611019578063e278fe6f1461105f57600080fd5b8063b9f8092b14610ef1578063ca59409414610f06578063ce7c2ac214610f1b578063cf3afa5114610f3b578063d13f1b3e14610f6f57600080fd5b8063a497e674116101e8578063aced1661116101ac578063aced166114610e31578063ad5c464814610e51578063ad7a672f14610e85578063afa6626414610e9a578063b4d1d79514610eba578063b6b55f2514610ed157600080fd5b8063a497e67414610d9a578063a6095d6e14610dba578063a694fc3a14610ddb578063a6f7f5d614610dfb578063a9059cbb14610e1157600080fd5b80639fcc2d751161023a5780639fcc2d7514610c0b578063a083ff1714610cb7578063a24e3c7e14610d1a578063a285c9e814610d3a578063a2db9d8314610d5c578063a457c2d714610d7a57600080fd5b80638da5cb5b14610b82578063947061b514610ba057806395d89b4114610bc157806399530b0614610bd65780639be43daa14610beb57600080fd5b806347786d37116103a85780636f31ab341161031a5780637e108d52116102de5780637e108d5214610ab757806383536ff314610ad757806387153eb114610aed5780638778878214610b1a57806389a3027114610b305780638b10cc7c14610b6457600080fd5b80636f31ab34146109d357806370897b23146109e857806370a0823114610a08578063715018a614610a3e5780637a9262a214610a5357600080fd5b80635ea8cd121161036c5780635ea8cd12146108b1578063600a2cfb146108d1578063650cce8a146108e65780636719b2ee1461091a578063692308681461099e57806369b41170146109be57600080fd5b806347786d37146108245780634b2431d914610844578063503c70aa1461085b57806355489bb214610871578063573f0d6e1461089157600080fd5b806330630da4116104415780633ec143d3116104055780633ec143d3146107625780633f23bb73146107905780633f90916a146107b0578063432833a6146107ce5780634603c0aa146107e4578063469048401461080457600080fd5b806330630da4146106ba578063313ce567146106da578063355274ea1461070457806336efd16f14610722578063395093511461074257600080fd5b80631a92f6c2116104885780631a92f6c21461057b5780631cacf9b9146105c757806323b872dd146105e75780632728f333146106075780632775d01c1461069a57600080fd5b8063048bf085146104c557806306fdde03146104e7578063095ea7b3146105125780630cbf54c81461054257806318160ddd14610566575b600080fd5b3480156104d157600080fd5b506104e56104e0366004615200565b6111b3565b005b3480156104f357600080fd5b506104fc611209565b6040516105099190615608565b60405180910390f35b34801561051e57600080fd5b5061053261052d366004615294565b61129b565b6040519015158152602001610509565b34801561054e57600080fd5b5061055860fb5481565b604051908152602001610509565b34801561057257600080fd5b50609954610558565b34801561058757600080fd5b506105af7f0000000000000000000000004ccc2339f87f6c59c6893e1a678c2266ca58dc7281565b6040516001600160a01b039091168152602001610509565b3480156105d357600080fd5b506104e56105e2366004615382565b6112b2565b3480156105f357600080fd5b50610532610602366004615254565b6115ad565b34801561061357600080fd5b5060cf5460d0546106559161ffff8116916001600160681b03620100008304811692600160781b900416906001600160801b0380821691600160801b90041685565b6040805161ffff90961686526001600160681b03948516602087015293909216928401929092526001600160801b03918216606084015216608082015260a001610509565b3480156106a657600080fd5b506104e56106b5366004615405565b611659565b3480156106c657600080fd5b506104e56106d5366004615200565b6117fc565b3480156106e657600080fd5b5060cc54610100900460ff1660405160ff9091168152602001610509565b34801561071057600080fd5b5060ce546001600160681b0316610558565b34801561072e57600080fd5b506104e561073d366004615435565b611894565b34801561074e57600080fd5b5061053261075d366004615294565b61191c565b34801561076e57600080fd5b5060f95461077d9061ffff1681565b60405161ffff9091168152602001610509565b34801561079c57600080fd5b506105586107ab366004615200565b611958565b3480156107bc57600080fd5b5060d0546001600160801b0316610558565b3480156107da57600080fd5b5061055860fc5481565b3480156107f057600080fd5b506104e56107ff366004615200565b6119ab565b34801561081057600080fd5b5060d3546105af906001600160a01b031681565b34801561083057600080fd5b506104e561083f366004615405565b611a4d565b34801561085057600080fd5b506105586101025481565b34801561086757600080fd5b5061055860fd5481565b34801561087d57600080fd5b506104e561088c3660046153de565b611b28565b34801561089d57600080fd5b506104e56108ac366004615200565b611bc0565b3480156108bd57600080fd5b506104e56108cc366004615405565b611c0d565b3480156108dd57600080fd5b506104e5611c78565b3480156108f257600080fd5b506105af7f0000000000000000000000005934807cc0654d46755ebd2848840b616256c6ef81565b34801561092657600080fd5b5061096d610935366004615200565b60c96020526000908152604090205461ffff8116906201000081046001600160681b031690600160781b90046001600160801b031683565b6040805161ffff90941684526001600160681b0390921660208401526001600160801b031690820152606001610509565b3480156109aa57600080fd5b506104e56109b93660046152f5565b611dd3565b3480156109ca57600080fd5b50610558600081565b3480156109df57600080fd5b506104e5611ed3565b3480156109f457600080fd5b506104e5610a03366004615405565b611f10565b348015610a1457600080fd5b50610558610a23366004615200565b6001600160a01b031660009081526097602052604090205490565b348015610a4a57600080fd5b506104e5611fd7565b348015610a5f57600080fd5b50610a95610a6e366004615200565b60cb6020526000908152604090205461ffff8116906201000090046001600160801b031682565b6040805161ffff90931683526001600160801b03909116602083015201610509565b348015610ac357600080fd5b506104e5610ad2366004615405565b61200d565b348015610ae357600080fd5b5061055860f75481565b348015610af957600080fd5b50610558610b08366004615405565b60ca6020526000908152604090205481565b348015610b2657600080fd5b5061055860d55481565b348015610b3c57600080fd5b506105af7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b348015610b7057600080fd5b5060d2546001600160a01b03166105af565b348015610b8e57600080fd5b506065546001600160a01b03166105af565b348015610bac57600080fd5b50610103546105af906001600160a01b031681565b348015610bcd57600080fd5b506104fc612057565b348015610be257600080fd5b50610558612066565b348015610bf757600080fd5b506104e5610c06366004615405565b6120a0565b348015610c1757600080fd5b5060cc5460cd5460ce54610c679260ff808216936101008304909116926001600160a01b036201000090930483169282169166ffffffffffffff600160a01b90910416906001600160681b031686565b60408051961515875260ff90951660208701526001600160a01b03938416948601949094529116606084015266ffffffffffffff1660808301526001600160681b031660a082015260c001610509565b348015610cc357600080fd5b5060d15460d254610cee916001600160a01b039081169190811690600160a01b900463ffffffff1683565b604080516001600160a01b03948516815293909216602084015263ffffffff1690820152606001610509565b348015610d2657600080fd5b506104e5610d35366004615200565b61219a565b348015610d4657600080fd5b5060d254600160a01b900463ffffffff16610558565b348015610d6857600080fd5b5060d1546001600160a01b03166105af565b348015610d8657600080fd5b50610532610d95366004615294565b612231565b348015610da657600080fd5b506104e5610db5366004615405565b6122ca565b348015610dc657600080fd5b50610104546105af906001600160a01b031681565b348015610de757600080fd5b506104e5610df6366004615405565b612387565b348015610e0757600080fd5b5061055860d65481565b348015610e1d57600080fd5b50610532610e2c366004615294565b612485565b348015610e3d57600080fd5b5060d4546105af906001600160a01b031681565b348015610e5d57600080fd5b506105af7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b348015610e9157600080fd5b50610558612492565b348015610ea657600080fd5b5060f5546105af906001600160a01b031681565b348015610ec657600080fd5b5061055862093a8081565b348015610edd57600080fd5b506104e5610eec366004615405565b6125c0565b348015610efd57600080fd5b506104e5612634565b348015610f1257600080fd5b506104e561282a565b348015610f2757600080fd5b50610558610f36366004615200565b6128cd565b348015610f4757600080fd5b506105af7f000000000000000000000000f0e5c92cedd66c7985c354c35e2bc37e685b99da81565b348015610f7b57600080fd5b506104e5610f8a366004615405565b6128ea565b348015610f9b57600080fd5b506104e5610faa366004615200565b6129af565b348015610fbb57600080fd5b5061055860f85481565b348015610fd157600080fd5b506104e5610fe0366004615405565b612a3e565b348015610ff157600080fd5b506105af7f0000000000000000000000007c06792af1632e77cb27a558dc0885338f4bdf8e81565b34801561102557600080fd5b5061055861103436600461521c565b6001600160a01b03918216600090815260986020908152604080832093909416825291909152205490565b34801561106b57600080fd5b506104e5612aab565b34801561108057600080fd5b5061055860fa5481565b34801561109657600080fd5b506104e56110a5366004615200565b612c6b565b3480156110b657600080fd5b506104e56110c5366004615200565b612d5e565b6104e5612df9565b3480156110de57600080fd5b506110f26110ed366004615200565b612f4a565b60408051928352602083019190915201610509565b34801561111357600080fd5b506104e561302d565b34801561112857600080fd5b506104e5613082565b34801561113d57600080fd5b5060f6546105af906001600160a01b031681565b34801561115d57600080fd5b50610100546105af906001600160a01b031681565b34801561117e57600080fd5b50610101546105af906001600160a01b031681565b34801561119f57600080fd5b506104e56111ae366004615405565b6132d4565b6065546001600160a01b031633146111e65760405162461bcd60e51b81526004016111dd9061568a565b60405180910390fd5b61010080546001600160a01b0319166001600160a01b0392909216919091179055565b6060609a805461121890615a6e565b80601f016020809104026020016040519081016040528092919081815260200182805461124490615a6e565b80156112915780601f1061126657610100808354040283529160200191611291565b820191906000526020600020905b81548152906001019060200180831161127457829003601f168201915b5050505050905090565b60006112a83384846133b5565b5060015b92915050565b600054610100900460ff16806112cb575060005460ff16155b6112e75760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015611309576000805461ffff19166101011790555b6113ce6113196020850185615200565b6113296040860160208701615200565b6113396060870160408801615200565b6060870135608088013561135060a08a018a6158a4565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113929250505060c08b018b6158a4565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92506134da915050565b60006113e1610100850160e08601615200565b6001600160a01b031614156114315760405162461bcd60e51b815260206004820152601660248201527510afb7b83a34b7b739a83932b6b4bab6a83934b1b2b960511b60448201526064016111dd565b600061144561012085016101008601615200565b6001600160a01b031614156114905760405162461bcd60e51b815260206004820152601160248201527010afb9ba3934b5b2a9b2b632b1ba34b7b760791b60448201526064016111dd565b60006114a4610140850161012086016154a2565b63ffffffff161180156114d857506114be600a6064615a0c565b6114d0610140850161012086016154a2565b63ffffffff16105b6115185760405162461bcd60e51b81526020600482015260116024820152700857dc1c995b5a5d5b511a5cd8dbdd5b9d607a1b60448201526064016111dd565b611529610100840160e08501615200565b60f580546001600160a01b0319166001600160a01b039290921691909117905561155b61012084016101008501615200565b60f680546001600160a01b0319166001600160a01b039290921691909117905561158d610140840161012085016154a2565b63ffffffff1660f75580156115a8576000805461ff00191690555b505050565b60006115ba848484613719565b6001600160a01b03841660009081526098602090815260408083203384529091529020548281101561163f5760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b60648201526084016111dd565b61164c85338584036133b5565b60019150505b9392505050565b6002600154141561167c5760405162461bcd60e51b81526004016111dd906156e0565b600260015533600090815260c96020526040902060cf5461ffff16826116b45760405162461bcd60e51b81526004016111dd906156bf565b815461ffff1681146116f85760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081c9bdd5b99609a1b60448201526064016111dd565b81546201000090046001600160681b0316838110156117495760405162461bcd60e51b815260206004820152600d60248201526c115e18d9595908185b5bdd5b9d609a1b60448201526064016111dd565b61175381856138e9565b83546001600160681b0391909116620100000262010000600160781b031990911617835560d05461178d906001600160801b0316856138e9565b60d080546001600160801b0319166001600160801b0392909216919091179055604080518581526020810184905233917fab2daf3c146ca6416cbccd2a86ed2ba995e171ef6319df14a38aef01403a9c96910160405180910390a26117f233856138f5565b5050600180555050565b6065546001600160a01b031633146118265760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b0381166118725760405162461bcd60e51b815260206004820152601360248201527210b732bba9ba3934b5b2a9b2b632b1ba34b7b760691b60448201526064016111dd565b60f680546001600160a01b0319166001600160a01b0392909216919091179055565b600260015414156118b75760405162461bcd60e51b81526004016111dd906156e0565b6002600155816118d95760405162461bcd60e51b81526004016111dd906156bf565b6001600160a01b0381166118ec57600080fd5b6118f68282613a56565b60cc54611914906201000090046001600160a01b0316333085613ce8565b505060018055565b3360008181526098602090815260408083206001600160a01b038716845290915281205490916112a89185906119539086906158e9565b6133b5565b60cc5460009060ff610100909104168161198e61197460995490565b61197c612492565b60d0546001600160801b031685613d53565b90506119a361199c856128cd565b8284613d93565b949350505050565b6065546001600160a01b031633146119d55760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b038116611a2b5760405162461bcd60e51b815260206004820152601860248201527f216e65774f7074696f6e735072656d69756d507269636572000000000000000060448201526064016111dd565b60f580546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b03163314611a775760405162461bcd60e51b81526004016111dd9061568a565b60008111611ab15760405162461bcd60e51b81526020600482015260076024820152660216e65774361760cc1b60448201526064016111dd565b611aba81613df5565b60ce54604080516001600160681b039092168252602082018390527f5f86edbb9d92228a9edc3f0ebc0f001bda1ea345ac7335e0eeef3504b31d1a1c910160405180910390a160ce80546cffffffffffffffffffffffffff19166001600160681b0392909216919091179055565b6065546001600160a01b03163314611b525760405162461bcd60e51b81526004016111dd9061568a565b6000816001600160801b031611611b9a5760405162461bcd60e51b815260206004820152600c60248201526b21737472696b65507269636560a01b60448201526064016111dd565b6001600160801b031660fa5560cf5460f9805461ffff191661ffff909216919091179055565b6065546001600160a01b03163314611bea5760405162461bcd60e51b81526004016111dd9061568a565b61010380546001600160a01b0319166001600160a01b0392909216919091179055565b60d4546001600160a01b03163314611c375760405162461bcd60e51b81526004016111dd9061561b565b60008111611c735760405162461bcd60e51b8152602060048201526009602482015268216d696e507269636560b81b60448201526064016111dd565b60f855565b60d4546001600160a01b03163314611ca25760405162461bcd60e51b81526004016111dd9061561b565b60026001541415611cc55760405162461bcd60e51b81526004016111dd906156e0565b600260015560d2546040516358ffbb3d60e01b81526001600160a01b037f0000000000000000000000004ccc2339f87f6c59c6893e1a678c2266ca58dc728116600483015290911660248201526000907363b9712f3acf31597595a1d43f7ee0ad2c83357f906358ffbb3d9060440160206040518083038186803b158015611d4c57600080fd5b505af4158015611d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d84919061541d565b60cf54909150611da3906201000090046001600160681b0316826138e9565b60cf80546001600160681b0392909216620100000262010000600160781b03199092169190911790555060018055565b610104546001600160a01b03163314611e1f5760405162461bcd60e51b815260206004820152600e60248201526d10b7b33332b922bc32b1baba37b960911b60448201526064016111dd565b60026001541415611e425760405162461bcd60e51b81526004016111dd906156e0565b600260015560fc54604051633545cbf360e21b81526001600160a01b037f000000000000000000000000f0e5c92cedd66c7985c354c35e2bc37e685b99da169163d5172fcc91611e999190869086906004016157e1565b600060405180830381600087803b158015611eb357600080fd5b505af1158015611ec7573d6000803e3d6000fd5b50506001805550505050565b60026001541415611ef65760405162461bcd60e51b81526004016111dd906156e0565b6002600181905550611f0a60006001613e3f565b60018055565b6065546001600160a01b03163314611f3a5760405162461bcd60e51b81526004016111dd9061568a565b611f48620f42406064615a0c565b8110611f965760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420706572666f726d616e63652066656500000000000000000060448201526064016111dd565b60d55460408051918252602082018390527f24867dfb6fcb9970a07be21024956524abe7a1837faa903ff0e99aaa40cf893e910160405180910390a160d555565b6065546001600160a01b031633146120015760405162461bcd60e51b81526004016111dd9061568a565b61200b6000613fee565b565b600260015414156120305760405162461bcd60e51b81526004016111dd906156e0565b600260015561203e81614040565b6101025461204c9082614207565b610102555060018055565b6060609b805461121890615a6e565b600061209b61207460995490565b61207c612492565b60d05460cc546001600160801b0390911690610100900460ff16613d53565b905090565b600260015414156120c35760405162461bcd60e51b81526004016111dd906156e0565b6002600155806121025760405162461bcd60e51b815260206004820152600a602482015269216e756d526f756e647360b01b60448201526064016111dd565b60cf5461ffff1660005b8281101561219157600061212082846158e9565b600081815260ca60205260409020549091501561216d5760405162461bcd60e51b815260206004820152600b60248201526a125b9a5d1a585b1a5e995960aa1b60448201526064016111dd565b600090815260ca60205260409020600190558061218981615aa9565b91505061210c565b50506001805550565b6065546001600160a01b031633146121c45760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b03811661220e5760405162461bcd60e51b815260206004820152601160248201527010b732bba7b33332b922bc32b1baba37b960791b60448201526064016111dd565b61010480546001600160a01b0319166001600160a01b0392909216919091179055565b3360009081526098602090815260408083206001600160a01b0386168452909152812054828110156122b35760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016111dd565b6122c033858584036133b5565b5060019392505050565b6065546001600160a01b031633146122f45760405162461bcd60e51b81526004016111dd9061568a565b61012c8110156123465760405162461bcd60e51b815260206004820152601860248201527f496e76616c69642061756374696f6e206475726174696f6e000000000000000060448201526064016111dd565b60fb5460408051918252602082018390527f5acd982e2240ed224a69aa03dab039d3797c108e4b5f288cd7dd6ca181b275f3910160405180910390a160fb55565b600260015414156123aa5760405162461bcd60e51b81526004016111dd906156e0565b6002600155610100546001600160a01b0316806123c657600080fd5b600082116123d357600080fd5b33600090815260976020526040902054828110156123ff576123ff6123f884836138e9565b6000613e3f565b61240a333085613719565b6124153083856133b5565b6040516383df674760e01b815260048101849052336024820152600060448201526001600160a01b038316906383df674790606401600060405180830381600087803b15801561246457600080fd5b505af1158015612478573d6000803e3d6000fd5b5050600180555050505050565b60006112a8338484613719565b60d2546000906001600160a01b03166125255760cc546040516370a0823160e01b8152306004820152620100009091046001600160a01b0316906370a082319060240160206040518083038186803b1580156124ed57600080fd5b505afa158015612501573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209b919061541d565b60cc546040516370a0823160e01b815230600482015261209b916201000090046001600160a01b0316906370a082319060240160206040518083038186803b15801561257057600080fd5b505afa158015612584573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a8919061541d565b60cf546201000090046001600160681b031690614207565b600260015414156125e35760405162461bcd60e51b81526004016111dd906156e0565b6002600155806126055760405162461bcd60e51b81526004016111dd906156bf565b61260f8133613a56565b60cc5461262d906201000090046001600160a01b0316333084613ce8565b5060018055565b60d4546001600160a01b0316331461265e5760405162461bcd60e51b81526004016111dd9061561b565b600260015414156126815760405162461bcd60e51b81526004016111dd906156e0565b600260015560d1546001600160a01b0316806126cd5760405162461bcd60e51b815260206004820152600b60248201526a10b732bc3a27b83a34b7b760a91b60448201526064016111dd565b60d280546001600160a01b03199081166001600160a01b03841690811790925560d18054909116905560cf54604051620100009091046001600160681b03168082529133917f045c558fdce4714c5816d53820d27420f4cd860892df203fe636384d8d19aa019060200160405180910390a3604051632904c23960e01b81526001600160a01b037f0000000000000000000000004ccc2339f87f6c59c6893e1a678c2266ca58dc72811660048301527f0000000000000000000000005934807cc0654d46755ebd2848840b616256c6ef8116602483015283166044820152606481018290527363b9712f3acf31597595a1d43f7ee0ad2c83357f90632904c2399060840160206040518083038186803b1580156127e957600080fd5b505af41580156127fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612821919061541d565b50611914614213565b610103546001600160a01b03168061284157600080fd5b61284d60006001613e3f565b33600081815260976020526040902054906128699083836133b5565b60405163c9c2d4f560e01b8152336004820152602481018290526001600160a01b0383169063c9c2d4f590604401600060405180830381600087803b1580156128b157600080fd5b505af11580156128c5573d6000803e3d6000fd5b505050505050565b60008060006128db84612f4a565b90925090506119a38282614207565b60d4546001600160a01b031633146129145760405162461bcd60e51b81526004016111dd9061561b565b60008111801561292f575061292b600a6064615a0c565b8111155b61296e5760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a5908191a5cd8dbdd5b9d60821b60448201526064016111dd565b60f75460408051918252602082018390527f4cd657fde404967d63a338fb06c5c98751a9df57dfae6dc333a432faf8a5f656910160405180910390a160f755565b6065546001600160a01b031633146129d95760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b038116612a1c5760405162461bcd60e51b815260206004820152600a60248201526910b732bba5b2b2b832b960b11b60448201526064016111dd565b60d480546001600160a01b0319166001600160a01b0392909216919091179055565b60026001541415612a615760405162461bcd60e51b81526004016111dd906156e0565b600260015580612aa05760405162461bcd60e51b815260206004820152600a602482015269216e756d53686172657360b01b60448201526064016111dd565b61262d816000613e3f565b60026001541415612ace5760405162461bcd60e51b81526004016111dd906156e0565b600260015560d2546001600160a01b031680151580612af3575060cf5461ffff166001145b612b2e5760405162461bcd60e51b815260206004820152600c60248201526b149bdd5b990818db1bdcd95960a21b60448201526064016111dd565b60d254612b43906001600160a01b03166142e5565b6000610102549050600080612b5a60fd548461445b565b60fd81905560d0549193509150600090612b8490600160801b90046001600160801b031685614207565b9050612b8f816146e2565b60d080546001600160801b03808416600160801b029116179055600061010255612bb883613df5565b60cf805462010000600160781b031916620100006001600160681b038616021790556000612be64282614207565b905063ffffffff811115612c3c5760405162461bcd60e51b815260206004820152601860248201527f4f766572666c6f77206e6578744f7074696f6e5265616479000000000000000060448201526064016111dd565b60d2805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055505060018055505050565b6065546001600160a01b03163314612c955760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b038116612cde5760405162461bcd60e51b815260206004820152601060248201526f085b995dd19959549958da5c1a595b9d60821b60448201526064016111dd565b60d3546001600160a01b0382811691161415612d3c5760405162461bcd60e51b815260206004820152601860248201527f4d757374206265206e657720666565526563697069656e74000000000000000060448201526064016111dd565b60d380546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b03163314612d885760405162461bcd60e51b81526004016111dd9061568a565b6001600160a01b038116612ded5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016111dd565b612df681613fee565b50565b60026001541415612e1c5760405162461bcd60e51b81526004016111dd906156e0565b600260015560cc547f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03908116620100009092041614612e8d5760405162461bcd60e51b8152602060048201526005602482015264042ae8aa8960db1b60448201526064016111dd565b60003411612ec65760405162461bcd60e51b81526020600482015260066024820152652176616c756560d01b60448201526064016111dd565b612ed03433613a56565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f2b57600080fd5b505af1158015612f3f573d6000803e3d6000fd5b505060018055505050565b6001600160a01b038116600090815260c9602090815260408083208151606081018352905461ffff81168083526201000082046001600160681b031694830194909452600160781b90046001600160801b031691810191909152829160011115612fcc575050506001600160a01b031660009081526097602052604081205491565b60cf54815161ffff908116600090815260ca602052604081205460cc54919361300293869391169190610100900460ff1661472c565b9050613023856001600160a01b031660009081526097602052604090205490565b9590945092505050565b600260015414156130505760405162461bcd60e51b81526004016111dd906156e0565b6002600155600061305f61479d565b60fd5490915061306f90826138e9565b6001600160801b031660fd555060018055565b60d4546001600160a01b031633146130ac5760405162461bcd60e51b81526004016111dd9061561b565b600260015414156130cf5760405162461bcd60e51b81526004016111dd906156e0565b600260015560d2546001600160a01b0316801580156130f5575060cf5461ffff16600114155b6131345760405162461bcd60e51b815260206004820152601060248201526f149bdd5b99081b9bdd0818db1bdcd95960821b60448201526064016111dd565b60408051610120810182526001600160a01b037f0000000000000000000000007c06792af1632e77cb27a558dc0885338f4bdf8e811682527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660208301528381168284015260006060830181905260f95461ffff16608084015260fa5460a084015260f654821660c084015260f55490911660e083015260f75461010083015291516377e3ce0d60e11b8152909190819081907363b9712f3acf31597595a1d43f7ee0ad2c83357f9063efc79c1a9061321990879060cc9060cf90600401615717565b60606040518083038186803b15801561323157600080fd5b505af4158015613245573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326991906152bf565b604080518381526020810183905293965091945092507fa217999b1c125c2a996f712c5f26a28addad7167bd8a67d5bd5b2a751148abb0910160405180910390a1505060d180546001600160a01b0319166001600160a01b0392909216919091179055505060018055565b6065546001600160a01b031633146132fe5760405162461bcd60e51b81526004016111dd9061568a565b61330c620f42406064615a0c565b81106133535760405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206d616e6167656d656e742066656560501b60448201526064016111dd565b600061337063031ba30961336a84620f424061495a565b90614966565b60d65460408051918252602082018590529192507f4e874b007ab14f7e263baefd44951834c8266f4f224d1092e49e9c254354cc54910160405180910390a160d65550565b6001600160a01b0383166134175760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016111dd565b6001600160a01b0382166134785760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016111dd565b6001600160a01b0383811660008181526098602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600054610100900460ff16806134f3575060005460ff16155b61350f5760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015613531576000805461ffff19166101011790555b60405163c72733f760e01b81527363b9712f3acf31597595a1d43f7ee0ad2c83357f9063c72733f790613576908c908c908c908b908d908c908c908c9060040161550e565b60006040518083038186803b15801561358e57600080fd5b505af41580156135a2573d6000803e3d6000fd5b505050506135ae614972565b6135b884846149e5565b6135c0614a64565b6135c989612d5e565b60d480546001600160a01b03808b166001600160a01b03199283161790925560d38054928a169290911691909117905560d585905561361363031ba30961336a88620f424061495a565b60d6558160cc6136238282615b01565b505060cc546040516370a0823160e01b81523060048201526000916201000090046001600160a01b0316906370a082319060240160206040518083038186803b15801561366f57600080fd5b505afa158015613683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a7919061541d565b90506136b281613df5565b60cf805461ffff196001600160681b03909316600160781b02929092167fffffffff00000000000000000000000000ffffffffffffffffffffffffff0000909216919091176001179055801561370e576000805461ff00191690555b505050505050505050565b6001600160a01b03831661377d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016111dd565b6001600160a01b0382166137df5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016111dd565b6001600160a01b038316600090815260976020526040902054818110156138575760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016111dd565b6001600160a01b0380851660009081526097602052604080822085850390559185168152908120805484929061388e9084906158e9565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516138da91815260200190565b60405180910390a35b50505050565b60006116528284615a2b565b60cc546001600160a01b03620100009091048116907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216811415613a4257604051632e1a7d4d60e01b8152600481018390527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561399557600080fd5b505af11580156139a9573d6000803e3d6000fd5b505050506000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146139fa576040519150601f19603f3d011682016040523d82523d6000602084013e6139ff565b606091505b50509050806138e35760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b60448201526064016111dd565b6115a86001600160a01b0382168484614acb565b60cf5461ffff166000613a7184613a6b612492565b90614207565b60ce549091506001600160681b0316811115613abc5760405162461bcd60e51b815260206004820152600a6024820152690457863656564206361760b41b60448201526064016111dd565b60cd54600160a01b900466ffffffffffffff16811015613b155760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b60448201526064016111dd565b60408051858152602081018490526001600160a01b038516917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a26001600160a01b038316600090815260c9602090815260408083208151606081018352905461ffff81168083526201000082046001600160681b031683860152600160781b9091046001600160801b031682840152845260ca90925282205460cc54919291613bd4918491879190610100900460ff1661472c565b8251909150869061ffff16851415613c05576020830151600090613c01906001600160681b031689614207565b9150505b613c0e81613df5565b6040805160608101825261ffff80881682526001600160681b0380851660208085019182526001600160801b038089168688019081526001600160a01b038e16600090815260c990935296822095518654935197518216600160781b02600160781b600160f81b03199890951662010000026effffffffffffffffffffffffffffff1990941695169490941791909117949094161790915560d054613cb4911689614207565b9050613cbf816146e2565b60d080546001600160801b0319166001600160801b039290921691909117905550505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526138e39085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614afb565b600080613d6183600a615964565b905060008611613d715780613d89565b613d898661336a613d8288886138e9565b849061495a565b9695505050505050565b600060018311613ddd5760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b60448201526064016111dd565b6119a3613deb83600a615964565b61336a868661495a565b6001600160681b03811115612df65760405162461bcd60e51b815260206004820152601060248201526f13dd995c999b1bddc81d5a5b9d0c4c0d60821b60448201526064016111dd565b33600090815260c9602090815260408083208151606081018352905461ffff8082168084526201000083046001600160681b031684870152600160781b9092046001600160801b03168385015260cf5491865260ca9094529184205460cc5491949290931692613eba9185918591610100900460ff1661472c565b905083613ec75784613ec9565b805b945084613ed7575050505050565b80851115613f1b5760405162461bcd60e51b81526020600482015260116024820152704578636565647320617661696c61626c6560781b60448201526064016111dd565b825161ffff16821115613f485733600090815260c960205260409020805462010000600160781b03191690555b613f51856146e2565b613f5b81866138e9565b33600081815260c960205260409081902080546001600160801b0394909416600160781b02600160781b600160f81b0319909416939093179092558451915190917fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92991613fd49189825261ffff16602082015260400190565b60405180910390a2613fe7303387613719565b5050505050565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000811161407d5760405162461bcd60e51b815260206004820152600a602482015269216e756d53686172657360b01b60448201526064016111dd565b33600090815260c960205260409020546201000090046001600160681b03161515806140c7575033600090815260c96020526040902054600160781b90046001600160801b031615155b156140d8576140d860006001613e3f565b60cf5433600081815260cb60209081526040918290208054835187815261ffff96871693810184905292959194911685149290917f0c53c82ad07e2d592d88ece3b066777dd60f1118e2a081b380efc4358f0d9e2a910160405180910390a281546201000090046001600160801b0316600082156141615761415a8287614207565b90506141c4565b81156141a35760405162461bcd60e51b81526020600482015260116024820152704578697374696e6720776974686472617760781b60448201526064016111dd565b5033600090815260cb60205260409020805461ffff191661ffff8616179055845b6141cd816146e2565b33600081815260cb60205260409020805462010000600160901b031916620100006001600160801b038516021790556128c5903088613719565b600061165282846158e9565b60d25460f8546040516301c6654960e21b81526001600160a01b0392831660048201819052602482018390527f000000000000000000000000f0e5c92cedd66c7985c354c35e2bc37e685b99da909316604482015260cc60648201527363b9712f3acf31597595a1d43f7ee0ad2c83357f9063071995249060840160206040518083038186803b1580156142a657600080fd5b505af41580156142ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142de919061541d565b60fc555050565b60cf546201000090046001600160681b03166001600160a01b038216156143315760cf80546cffffffffffffffffffffffffff60781b1916600160781b6001600160681b038416021790555b60cf805462010000600160781b031916905560d280546001600160a01b03191690556001600160a01b0382161561445757604051636c6fe87f60e11b81526001600160a01b037f0000000000000000000000004ccc2339f87f6c59c6893e1a678c2266ca58dc721660048201526000907363b9712f3acf31597595a1d43f7ee0ad2c83357f9063d8dfd0fe9060240160206040518083038186803b1580156143d857600080fd5b505af41580156143ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614410919061541d565b9050336001600160a01b0316836001600160a01b03167f7e830f7c1771deb1bdb35c4a7e6051bbac32b376f7f4e4976b8618b0b11997f7836040516134cd91815260200190565b5050565b60d3546040805160e08101825260cc54610100810460ff16825291516370a0823160e01b815230600482015260009384936001600160a01b039182169385938493849384937363b9712f3acf31597595a1d43f7ee0ad2c83357f9363d9b874389360cf93602084019262010000909104909116906370a082319060240160206040518083038186803b1580156144f057600080fd5b505afa158015614504573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614528919061541d565b815260200161453660995490565b81526020018d815260200160d554815260200160d65481526020018c8152506040518363ffffffff1660e01b81526004016145c392919060006101008201905083825282516020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e08301529392505050565b60c06040518083038186803b1580156145db57600080fd5b505af41580156145ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146139190615459565b60cf5461ffff16600081815260ca60209081526040918290208790558151858152908101849052908101829052969d50949b50919850965094509250906001600160a01b038716907f0a242f7ecaf711036ca770774ceffae28e60ef042ac113ddd187f2631db0c0069060600160405180910390a260d080546001600160801b03191690556146a38160016158e9565b60cf805461ffff191661ffff92909216919091179055506146c690503084614bcd565b80156146d6576146d684826138f5565b505050505b9250929050565b6001600160801b03811115612df65760405162461bcd60e51b815260206004820152601060248201526f09eeccae4ccd8deee40ead2dce86264760831b60448201526064016111dd565b835160009061ffff16158015906147475750845161ffff1684115b1561478957600061476686602001516001600160681b03168585614cac565b6040870151909150614781906001600160801b031682614207565b9150506119a3565b50505050604001516001600160801b031690565b33600090815260cb6020526040812080546001600160801b03620100008204169061ffff16816147ff5760405162461bcd60e51b815260206004820152600d60248201526c139bdd081a5b9a5d1a585d1959609a1b60448201526064016111dd565b60cf5461ffff1681106148475760405162461bcd60e51b815260206004820152601060248201526f149bdd5b99081b9bdd0818db1bdcd95960821b60448201526064016111dd565b33600090815260cb60205260409020805462010000600160901b031916905560d05461488390600160801b90046001600160801b0316836138e9565b60d080546001600160801b03928316600160801b029216919091179055600081815260ca602052604081205460cc546148c691859160ff61010090910416613d93565b604080518281526020810186905291925033917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a261490e3084614d0f565b600081116149505760405162461bcd60e51b815260206004820152600f60248201526e085dda5d1a191c985dd05b5bdd5b9d608a1b60448201526064016111dd565b6119a333826138f5565b60006116528284615a0c565b60006116528284615901565b600054610100900460ff168061498b575060005460ff16155b6149a75760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff161580156149c9576000805461ffff19166101011790555b6149d1614e5d565b8015612df6576000805461ff001916905550565b600054610100900460ff16806149fe575060005460ff16155b614a1a5760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015614a3c576000805461ffff19166101011790555b614a44614ecc565b614a4e8383614f36565b80156115a8576000805461ff0019169055505050565b600054610100900460ff1680614a7d575060005460ff16155b614a995760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015614abb576000805461ffff19166101011790555b614ac3614ecc565b6149d1614fcb565b6040516001600160a01b0383166024820152604481018290526115a890849063a9059cbb60e01b90606401613d1c565b6000614b50826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661502b9092919063ffffffff16565b8051909150156115a85780806020019051810190614b6e9190615366565b6115a85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016111dd565b6001600160a01b038216614c235760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016111dd565b8060996000828254614c3591906158e9565b90915550506001600160a01b03821660009081526097602052604081208054839290614c629084906158e9565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b600060018311614cf65760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b60448201526064016111dd565b6119a38361336a614d0885600a615964565b879061495a565b6001600160a01b038216614d6f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016111dd565b6001600160a01b03821660009081526097602052604090205481811015614de35760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016111dd565b6001600160a01b0383166000908152609760205260408120838303905560998054849290614e12908490615a2b565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b600054610100900460ff1680614e76575060005460ff16155b614e925760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015614eb4576000805461ffff19166101011790555b600180558015612df6576000805461ff001916905550565b600054610100900460ff1680614ee5575060005460ff16155b614f015760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff161580156149d1576000805461ffff19166101011790558015612df6576000805461ff001916905550565b600054610100900460ff1680614f4f575060005460ff16155b614f6b5760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015614f8d576000805461ffff19166101011790555b8251614fa090609a906020860190615136565b508151614fb490609b906020850190615136565b5080156115a8576000805461ff0019169055505050565b600054610100900460ff1680614fe4575060005460ff16155b6150005760405162461bcd60e51b81526004016111dd9061563c565b600054610100900460ff16158015615022576000805461ffff19166101011790555b6149d133613fee565b60606119a3848460008585843b6150845760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016111dd565b600080866001600160a01b031685876040516150a091906154f2565b60006040518083038185875af1925050503d80600081146150dd576040519150601f19603f3d011682016040523d82523d6000602084013e6150e2565b606091505b50915091506150f28282866150fd565b979650505050505050565b6060831561510c575081611652565b82511561511c5782518084602001fd5b8160405162461bcd60e51b81526004016111dd9190615608565b82805461514290615a6e565b90600052602060002090601f01602090048101928261516457600085556151aa565b82601f1061517d57805160ff19168380011785556151aa565b828001600101855582156151aa579182015b828111156151aa57825182559160200191906001019061518f565b506151b69291506151ba565b5090565b5b808211156151b657600081556001016151bb565b80356151da81615c12565b919050565b80356151da81615c35565b80356151da81615c4a565b80356151da81615c5f565b600060208284031215615211578081fd5b813561165281615c12565b6000806040838503121561522e578081fd5b823561523981615c12565b9150602083013561524981615c12565b809150509250929050565b600080600060608486031215615268578081fd5b833561527381615c12565b9250602084013561528381615c12565b929592945050506040919091013590565b600080604083850312156152a6578182fd5b82356152b181615c12565b946020939093013593505050565b6000806000606084860312156152d3578283fd5b83516152de81615c12565b602085015160409095015190969495509392505050565b60008060208385031215615307578182fd5b823567ffffffffffffffff8082111561531e578384fd5b818501915085601f830112615331578384fd5b81358181111561533f578485fd5b86602061012083028501011115615354578485fd5b60209290920196919550909350505050565b600060208284031215615377578081fd5b815161165281615c27565b60008082840360e0811215615395578283fd5b833567ffffffffffffffff8111156153ab578384fd5b840161014081870312156153bd578384fd5b925060c0601f19820112156153d0578182fd5b506020830190509250929050565b6000602082840312156153ef578081fd5b81356001600160801b0381168114611652578182fd5b600060208284031215615416578081fd5b5035919050565b60006020828403121561542e578081fd5b5051919050565b60008060408385031215615447578182fd5b82359150602083013561524981615c12565b60008060008060008060c08789031215615471578384fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b6000602082840312156154b3578081fd5b813563ffffffff81168114611652578182fd5b600081518084526154de816020860160208601615a42565b601f01601f19169290920160200192915050565b60008251615504818460208701615a42565b9190910192915050565b60006101a060018060a01b03808c168452808b166020850152808a1660408501528860608501528760808501528160a085015261554d828501886154c6565b915083820360c085015261556182876154c6565b92508435915061557082615c27565b90151560e084015260208401359061558782615c5f565b60ff8216610100850152604085013591506155a182615c12565b166101208301526155b4606084016151cf565b6001600160a01b03166101408301526155cf608084016151ea565b66ffffffffffffff166101608301526155ea60a084016151df565b6001600160681b038116610180840152509998505050505050505050565b60208152600061165260208301846154c6565b60208082526007908201526610b5b2b2b832b960c91b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526007908201526608585b5bdd5b9d60ca1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b83516001600160a01b03168152602080850151610160830191615744908401826001600160a01b03169052565b50604085015161575f60408401826001600160a01b03169052565b5060608501516060830152608085015161577f608084018261ffff169052565b5060a085015160a083015260c08501516157a460c08401826001600160a01b03169052565b5060e08501516157bf60e08401826001600160a01b03169052565b5061010094850151948201949094526101208101929092526101409091015290565b838152604060208083018290528282018490526000919060609081850187855b88811015615895578135835283820135848401526158208683016151cf565b6001600160a01b03168684015284820135858401526080808301359084015260a061584c8184016151cf565b6001600160a01b03169084015260c06158668382016151f5565b60ff169084015260e0828101359084015261010080830135908401526101209283019290910190600101615801565b50909998505050505050505050565b6000808335601e198436030181126158ba578283fd5b83018035915067ffffffffffffffff8211156158d4578283fd5b6020019150368190038213156146db57600080fd5b600082198211156158fc576158fc615ac4565b500190565b60008261591c57634e487b7160e01b81526012600452602481fd5b500490565b600181815b8085111561595c57816000190482111561594257615942615ac4565b8085161561594f57918102915b93841c9390800290615926565b509250929050565b6000611652838360008261597a575060016112ac565b81615987575060006112ac565b816001811461599d57600281146159a7576159c3565b60019150506112ac565b60ff8411156159b8576159b8615ac4565b50506001821b6112ac565b5060208310610133831016604e8410600b84101617156159e6575081810a6112ac565b6159f08383615921565b8060001904821115615a0457615a04615ac4565b029392505050565b6000816000190483118215151615615a2657615a26615ac4565b500290565b600082821015615a3d57615a3d615ac4565b500390565b60005b83811015615a5d578181015183820152602001615a45565b838111156138e35750506000910152565b600181811c90821680615a8257607f821691505b60208210811415615aa357634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415615abd57615abd615ac4565b5060010190565b634e487b7160e01b600052601160045260246000fd5b600081356112ac81615c12565b600081356112ac81615c35565b600081356112ac81615c4a565b8135615b0c81615c27565b815460ff19811691151560ff1691821783556020840135615b2c81615c5f565b61ff008160081b169050808361ffff198416171784556040850135615b5081615c12565b6001600160b01b0319929092169092179190911760109190911b62010000600160b01b031617815560018101615ba8615b8b60608501615ada565b82546001600160a01b0319166001600160a01b0391909116178255565b615be1615bb760808501615af4565b82805466ffffffffffffff60a01b191660a09290921b66ffffffffffffff60a01b16919091179055565b50614457615bf160a08401615ae7565b600283016001600160681b0382166001600160681b03198254161781555050565b6001600160a01b0381168114612df657600080fd5b8015158114612df657600080fd5b6001600160681b0381168114612df657600080fd5b66ffffffffffffff81168114612df657600080fd5b60ff81168114612df657600080fdfea2646970667358221220220ea42baa538ad6df1a5280f14eee73d27e2877dc7cbe3ea9702e1fb9e4f82164736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000007c06792af1632e77cb27a558dc0885338f4bdf8e0000000000000000000000004ccc2339f87f6c59c6893e1a678c2266ca58dc720000000000000000000000005934807cc0654d46755ebd2848840b616256c6ef000000000000000000000000f0e5c92cedd66c7985c354c35e2bc37e685b99da
-----Decoded View---------------
Arg [0] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [1] : _usdc (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [2] : _oTokenFactory (address): 0x7C06792Af1632E77cb27a558Dc0885338F4Bdf8E
Arg [3] : _gammaController (address): 0x4ccc2339F87F6c59c6893E1A678c2266cA58dC72
Arg [4] : _marginPool (address): 0x5934807cC0654d46755eBd2848840b616256C6Ef
Arg [5] : _swapContract (address): 0xF0E5c92cEdd66C7985C354C35e2bC37E685b99Da
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [2] : 0000000000000000000000007c06792af1632e77cb27a558dc0885338f4bdf8e
Arg [3] : 0000000000000000000000004ccc2339f87f6c59c6893e1a678c2266ca58dc72
Arg [4] : 0000000000000000000000005934807cc0654d46755ebd2848840b616256c6ef
Arg [5] : 000000000000000000000000f0e5c92cedd66c7985c354c35e2bc37e685b99da
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.