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
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x614a2061 | 15652047 | 668 days ago | IN | 0 ETH | 0.02315293 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
VaultLifecycleTreasury
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 {Vault} from "./Vault.sol"; import {ShareMath} from "./ShareMath.sol"; import {IStrikeSelection} from "../interfaces/IRibbon.sol"; import {GnosisAuction} from "./GnosisAuction.sol"; import {DateTime} from "./DateTime.sol"; import { IOtokenFactory, IOtoken, IController, GammaTypes } from "../interfaces/GammaInterface.sol"; import {IERC20Detailed} from "../interfaces/IERC20Detailed.sol"; import {IGnosisAuction} from "../interfaces/IGnosisAuction.sol"; import {SupportsNonCompliantERC20} from "./SupportsNonCompliantERC20.sol"; library VaultLifecycleTreasury { using SafeMath for uint256; using SupportsNonCompliantERC20 for IERC20; struct CloseParams { address OTOKEN_FACTORY; address USDC; address currentOption; uint256 delay; uint16 lastStrikeOverrideRound; uint256 overriddenStrikePrice; uint256 period; } /** * @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 * @param _auctionDuration is the duration of the gnosis auction * @param _period is the period between each option sales */ struct InitParams { address _owner; address _keeper; address _feeRecipient; uint256 _managementFee; uint256 _performanceFee; string _tokenName; string _tokenSymbol; address _optionsPremiumPricer; address _strikeSelection; uint32 _premiumDiscount; uint256 _auctionDuration; uint256 _period; uint256 _maxDepositors; uint256 _minDeposit; } /** * @notice Sets the next option the vault will be shorting, and calculates its premium for the auction * @param strikeSelection is the address of the contract with strike selection logic * @param optionsPremiumPricer is the address of the contract with the black-scholes premium calculation logic * @param premiumDiscount is the vault's discount applied to the premium * @param closeParams 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 premium is the premium of the new option * @return strikePrice is the strike price of the new option * @return delta is the delta of the new option */ function commitAndClose( address strikeSelection, address optionsPremiumPricer, uint256 premiumDiscount, CloseParams calldata closeParams, Vault.VaultParams storage vaultParams, Vault.VaultState storage vaultState ) external returns ( address otokenAddress, uint256 premium, uint256 strikePrice, uint256 delta ) { uint256 expiry; // uninitialized state if (closeParams.currentOption == address(0)) { expiry = getNextExpiry(block.timestamp, closeParams.period); } else { expiry = getNextExpiry( IOtoken(closeParams.currentOption).expiryTimestamp(), closeParams.period ); } IStrikeSelection selection = IStrikeSelection(strikeSelection); bool isPut = vaultParams.isPut; address underlying = vaultParams.underlying; address asset = vaultParams.asset; (strikePrice, delta) = closeParams.lastStrikeOverrideRound == vaultState.round ? (closeParams.overriddenStrikePrice, 0) : selection.getStrikePrice(expiry, isPut); require(strikePrice != 0, "!strikePrice"); // retrieve address if option already exists, or deploy it otokenAddress = getOrDeployOtoken( closeParams, vaultParams, underlying, asset, strikePrice, expiry, isPut ); // get the black scholes premium of the option premium = GnosisAuction.getOTokenPremiumInStables( otokenAddress, optionsPremiumPricer, premiumDiscount ); require(premium > 0, "!premium"); return (otokenAddress, premium, 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 currentShareSupply is the supply of the shares invoked with totalSupply() * @param asset is the address of the vault's asset * @param decimals is the decimals of the asset * @param lastQueuedWithdrawAmount is the amount queued for withdrawals from last round * @param managementFee is the management fee percent to charge on the AUM */ struct RolloverParams { uint256 decimals; uint256 totalBalance; uint256 currentShareSupply; uint256 lastQueuedWithdrawAmount; uint256 managementFee; } /** * @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 managementFeeInAsset is the amount of management fee charged by vault */ function rollover( Vault.VaultState storage vaultState, RolloverParams calldata params ) external view returns ( uint256 newLockedAmount, uint256 queuedWithdrawAmount, uint256 newPricePerShare, uint256 mintShares, uint256 managementFeeInAsset ) { uint256 currentBalance = params.totalBalance; uint256 pendingAmount = vaultState.totalPending; uint256 queuedWithdrawShares = vaultState.queuedWithdrawShares; uint256 balanceForVaultFees; { uint256 pricePerShareBeforeFee = ShareMath.pricePerShare( params.currentShareSupply, currentBalance, pendingAmount, params.decimals ); uint256 queuedWithdrawBeforeFee = params.currentShareSupply > 0 ? ShareMath.sharesToAsset( queuedWithdrawShares, pricePerShareBeforeFee, params.decimals ) : 0; // Deduct the difference between the newly scheduled withdrawals // and the older withdrawals // so we can charge them fees before they leave uint256 withdrawAmountDiff = queuedWithdrawBeforeFee > params.lastQueuedWithdrawAmount ? queuedWithdrawBeforeFee.sub( params.lastQueuedWithdrawAmount ) : 0; balanceForVaultFees = currentBalance .sub(queuedWithdrawBeforeFee) .add(withdrawAmountDiff); } managementFeeInAsset = getManagementFee( balanceForVaultFees, vaultState.totalPending, params.managementFee ); // Take into account the fee // so we can calculate the newPricePerShare currentBalance = currentBalance.sub(managementFeeInAsset); { newPricePerShare = ShareMath.pricePerShare( params.currentShareSupply, currentBalance, pendingAmount, 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 ); uint256 newSupply = params.currentShareSupply.add(mintShares); queuedWithdrawAmount = newSupply > 0 ? ShareMath.sharesToAsset( queuedWithdrawShares, newPricePerShare, params.decimals ) : 0; } return ( currentBalance.sub(queuedWithdrawAmount), // new locked balance subtracts the queued withdrawals queuedWithdrawAmount, newPricePerShare, mintShares, managementFeeInAsset ); } /** * @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 management fee for this week's round * @param currentBalance is the balance of funds held on the vault after closing short * @param pendingAmount is the pending deposit amount * @param managementFeePercent is the management fee pct. * @return managementFeeInAsset is the management fee */ function getManagementFee( uint256 currentBalance, uint256 pendingAmount, uint256 managementFeePercent ) internal pure returns (uint256 managementFeeInAsset) { // 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 _managementFeeInAsset; // Always charge management fee regardless of whether the vault is // making a profit from the previous options sale _managementFeeInAsset = managementFeePercent > 0 ? lockedBalanceSansPending.mul(managementFeePercent).div( 100 * Vault.FEE_MULTIPLIER ) : 0; return _managementFeeInAsset; } /** * @notice Either retrieves the option token if it already exists, or deploy it * @param closeParams 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( CloseParams calldata closeParams, Vault.VaultParams storage vaultParams, address underlying, address collateralAsset, uint256 strikePrice, uint256 expiry, bool isPut ) internal returns (address) { IOtokenFactory factory = IOtokenFactory(closeParams.OTOKEN_FACTORY); address otokenFromFactory = factory.getOtoken( underlying, closeParams.USDC, collateralAsset, strikePrice, expiry, isPut ); if (otokenFromFactory != address(0)) { return otokenFromFactory; } address otoken = factory.createOtoken( underlying, closeParams.USDC, collateralAsset, strikePrice, expiry, isPut ); verifyOtoken( otoken, vaultParams, collateralAsset, closeParams.USDC, closeParams.delay ); return otoken; } /** * @notice Starts the gnosis auction * @param auctionDetails is the struct with all the custom parameters of the auction * @return the auction id of the newly created auction */ function startAuction(GnosisAuction.AuctionDetails calldata auctionDetails) external returns (uint256) { return GnosisAuction.startAuction(auctionDetails); } /** * @notice Settles the gnosis auction * @param gnosisEasyAuction is the contract address of Gnosis easy auction protocol * @param auctionID is the auction ID of the gnosis easy auction */ function settleAuction(address gnosisEasyAuction, uint256 auctionID) internal { IGnosisAuction(gnosisEasyAuction).settleAuction(auctionID); } /** * @notice Places a bid in an auction * @param bidDetails is the struct with all the details of the bid including the auction's id and how much to bid */ function placeBid(GnosisAuction.BidDetails calldata bidDetails) external returns ( uint256 sellAmount, uint256 buyAmount, uint64 userId ) { return GnosisAuction.placeBid(bidDetails); } /** * @notice Claims the oTokens belonging to the vault * @param auctionSellOrder is the sell order of the bid * @param gnosisEasyAuction is the address of the gnosis auction contract holding custody to the funds * @param counterpartyThetaVault is the address of the counterparty theta vault of this delta vault */ function claimAuctionOtokens( Vault.AuctionSellOrder calldata auctionSellOrder, address gnosisEasyAuction, address counterpartyThetaVault ) external { GnosisAuction.claimAuctionOtokens( auctionSellOrder, gnosisEasyAuction, counterpartyThetaVault ); } /** * @notice Verify the constructor params satisfy requirements * @param _initParams is the initialization parameter including owner, keeper, etc. * @param _vaultParams is the struct with vault general data */ function verifyInitializerParams( InitParams calldata _initParams, Vault.VaultParams calldata _vaultParams, uint256 _min_auction_duration ) external pure { require(_initParams._owner != address(0), "!_owner"); require(_initParams._keeper != address(0), "!_keeper"); require(_initParams._feeRecipient != address(0), "!_feeRecipient"); require( _initParams._performanceFee < 100 * Vault.FEE_MULTIPLIER, "performanceFee >= 100%" ); require( _initParams._managementFee < 100 * Vault.FEE_MULTIPLIER, "managementFee >= 100%" ); require(bytes(_initParams._tokenName).length > 0, "!_tokenName"); require(bytes(_initParams._tokenSymbol).length > 0, "!_tokenSymbol"); require( (_initParams._period == 7) || (_initParams._period == 14) || (_initParams._period == 30) || (_initParams._period == 90) || (_initParams._period == 180), "!_period" ); require( _initParams._optionsPremiumPricer != address(0), "!_optionsPremiumPricer" ); require( _initParams._strikeSelection != address(0), "!_strikeSelection" ); require( _initParams._premiumDiscount > 0 && _initParams._premiumDiscount < 100 * Vault.PREMIUM_DISCOUNT_MULTIPLIER, "!_premiumDiscount" ); require( _initParams._auctionDuration >= _min_auction_duration, "!_auctionDuration" ); require(_initParams._maxDepositors > 0, "!_maxDepositors"); require(_initParams._minDeposit > 0, "!_minDeposit"); 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 options expiry timestamp, this function should be called when there is sufficient guard to ensure valid period * @param timestamp is the expiry timestamp of the current option * @param period is no. of days in between option sales. Available periods are: * 7(1w), 14(2w), 30(1m), 90(3m), 180(6m) */ function getNextExpiry(uint256 timestamp, uint256 period) internal pure returns (uint256 nextExpiry) { if (period == 7) { nextExpiry = DateTime.getNextFriday(timestamp); nextExpiry = nextExpiry <= timestamp ? nextExpiry + 1 weeks : nextExpiry; } else if (period == 14) { nextExpiry = DateTime.getNextFriday(timestamp); nextExpiry = nextExpiry <= timestamp ? nextExpiry + 2 weeks : nextExpiry; } else if (period == 30) { nextExpiry = DateTime.getMonthLastFriday(timestamp); nextExpiry = nextExpiry <= timestamp ? DateTime.getMonthLastFriday(nextExpiry + 1 weeks) : nextExpiry; } else if (period == 90) { nextExpiry = DateTime.getQuarterLastFriday(timestamp); nextExpiry = nextExpiry <= timestamp ? DateTime.getQuarterLastFriday(nextExpiry + 1 weeks) : nextExpiry; } else if (period == 180) { nextExpiry = DateTime.getBiannualLastFriday(timestamp); nextExpiry = nextExpiry <= timestamp ? DateTime.getBiannualLastFriday(nextExpiry + 1 weeks) : nextExpiry; } nextExpiry = nextExpiry - (nextExpiry % (24 hours)) + (8 hours); } }
// 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.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 {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; 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 // Source: https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary // ---------------------------------------------------------------------------- // BokkyPooBah's DateTime Library v1.01 // ---------------------------------------------------------------------------- pragma solidity =0.8.4; library DateTime { uint256 constant SECONDS_PER_DAY = 24 * 60 * 60; uint256 constant SECONDS_PER_HOUR = 60 * 60; uint256 constant SECONDS_PER_MINUTE = 60; int256 constant OFFSET19700101 = 2440588; uint256 constant DOW_MON = 1; uint256 constant DOW_TUE = 2; uint256 constant DOW_WED = 3; uint256 constant DOW_THU = 4; uint256 constant DOW_FRI = 5; uint256 constant DOW_SAT = 6; uint256 constant DOW_SUN = 7; // ------------------------------------------------------------------------ // Calculate the number of days from 1970/01/01 to year/month/day using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and subtracting the offset 2440588 so that 1970/01/01 is day 0 // // days = day // - 32075 // + 1461 * (year + 4800 + (month - 14) / 12) / 4 // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 // - offset // ------------------------------------------------------------------------ function _daysFromDate( uint256 year, uint256 month, uint256 day ) internal pure returns (uint256 _days) { require(year >= 1970); int256 _year = int256(year); int256 _month = int256(month); int256 _day = int256(day); int256 __days = _day - 32075 + (1461 * (_year + 4800 + (_month - 14) / 12)) / 4 + (367 * (_month - 2 - ((_month - 14) / 12) * 12)) / 12 - (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) / 4 - OFFSET19700101; _days = uint256(__days); } // ------------------------------------------------------------------------ // Calculate year/month/day from the number of days since 1970/01/01 using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and adding the offset 2440588 so that 1970/01/01 is day 0 // // int L = days + 68569 + offset // int N = 4 * L / 146097 // L = L - (146097 * N + 3) / 4 // year = 4000 * (L + 1) / 1461001 // L = L - 1461 * year / 4 + 31 // month = 80 * L / 2447 // dd = L - 2447 * month / 80 // L = month / 11 // month = month + 2 - 12 * L // year = 100 * (N - 49) + year + L // ------------------------------------------------------------------------ function _daysToDate(uint256 _days) internal pure returns ( uint256 year, uint256 month, uint256 day ) { int256 __days = int256(_days); int256 L = __days + 68569 + OFFSET19700101; int256 N = (4 * L) / 146097; L = L - (146097 * N + 3) / 4; int256 _year = (4000 * (L + 1)) / 1461001; L = L - (1461 * _year) / 4 + 31; int256 _month = (80 * L) / 2447; int256 _day = L - (2447 * _month) / 80; L = _month / 11; _month = _month + 2 - 12 * L; _year = 100 * (N - 49) + _year + L; year = uint256(_year); month = uint256(_month); day = uint256(_day); } function isLeapYear(uint256 timestamp) internal pure returns (bool leapYear) { (uint256 year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY); leapYear = _isLeapYear(year); } function _isLeapYear(uint256 year) internal pure returns (bool leapYear) { leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); } function getDaysInMonth(uint256 timestamp) internal pure returns (uint256 daysInMonth) { (uint256 year, uint256 month, ) = _daysToDate(timestamp / SECONDS_PER_DAY); daysInMonth = _getDaysInMonth(year, month); } function _getDaysInMonth(uint256 year, uint256 month) internal pure returns (uint256 daysInMonth) { if ( month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 ) { daysInMonth = 31; } else if (month != 2) { daysInMonth = 30; } else { daysInMonth = _isLeapYear(year) ? 29 : 28; } } // 1 = Monday, 7 = Sunday function getDayOfWeek(uint256 timestamp) internal pure returns (uint256 dayOfWeek) { uint256 _days = timestamp / SECONDS_PER_DAY; dayOfWeek = ((_days + 3) % 7) + 1; } function getYear(uint256 timestamp) internal pure returns (uint256 year) { (year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getMonth(uint256 timestamp) internal pure returns (uint256 month) { (, month, ) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getDay(uint256 timestamp) internal pure returns (uint256 day) { (, , day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function timestampFromDate( uint256 year, uint256 month, uint256 day ) internal pure returns (uint256 timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; } /** * @notice Gets the Friday of the same week * @param timestamp is the given date and time * @return the Friday of the same week in unix time */ function getThisWeekFriday(uint256 timestamp) internal pure returns (uint256) { return timestamp + 5 days - getDayOfWeek(timestamp) * 1 days; } /** * @notice Gets the next friday after the given date and time * @param timestamp is the given date and time * @return the next friday after the given date and time */ function getNextFriday(uint256 timestamp) internal pure returns (uint256) { uint256 friday = getThisWeekFriday(timestamp); return friday >= timestamp ? friday : friday + 1 weeks; } /** * @notice Gets the last day of the month * @param timestamp is the given date and time * @return the last day of the same month in unix time */ function getLastDayOfMonth(uint256 timestamp) internal pure returns (uint256) { return timestampFromDate(getYear(timestamp), getMonth(timestamp) + 1, 1) - 1 days; } /** * @notice Gets the last Friday of the month * @param timestamp is the given date and time * @return the last Friday of the same month in unix time */ function getMonthLastFriday(uint256 timestamp) internal pure returns (uint256) { uint256 lastDay = getLastDayOfMonth(timestamp); uint256 friday = getThisWeekFriday(lastDay); return friday > lastDay ? friday - 1 weeks : friday; } /** * @notice Gets the last Friday of the quarter * @param timestamp is the given date and time * @return the last Friday of the quarter in unix time */ function getQuarterLastFriday(uint256 timestamp) internal pure returns (uint256) { uint256 month = getMonth(timestamp); uint256 quarterMonth = (month <= 3) ? 3 : (month <= 6) ? 6 : (month <= 9) ? 9 : 12; uint256 quarterDate = timestampFromDate(getYear(timestamp), quarterMonth, 1); return getMonthLastFriday(quarterDate); } /** * @notice Gets the last Friday of the half-year * @param timestamp is the given date and time * @return the last friday of the half-year */ function getBiannualLastFriday(uint256 timestamp) internal pure returns (uint256) { uint256 month = getMonth(timestamp); uint256 biannualMonth = (month <= 6) ? 6 : 12; uint256 biannualDate = timestampFromDate(getYear(timestamp), biannualMonth, 1); return getMonthLastFriday(biannualDate); } }
// 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.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 {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 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 /// 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 {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; /** * @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); } } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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":"uint256","name":"_auctionDuration","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"},{"internalType":"uint256","name":"_maxDepositors","type":"uint256"},{"internalType":"uint256","name":"_minDeposit","type":"uint256"}],"internalType":"struct VaultLifecycleTreasury.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"},{"internalType":"uint256","name":"_min_auction_duration","type":"uint256"}],"name":"verifyInitializerParams","outputs":[],"stateMutability":"pure","type":"function"}]
Contract Creation Code
614a2061003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100a85760003560e01c806384d831a91161007057806384d831a9146101a757806395a170d7146101ba578063d8dfd0fe146101ff578063de8e34181461021f578063eebc5ff41461023f57600080fd5b806307cc4239146100ad5780632904c239146100cf57806358ffbb3d146101025780635a90235d14610122578063686fb2f21461016c575b600080fd5b8180156100b957600080fd5b506100cd6100c8366004613fb6565b61025f565b005b8180156100db57600080fd5b506100ef6100ea366004613ebb565b61026f565b6040519081526020015b60405180910390f35b81801561010e57600080fd5b506100ef61011d366004613e39565b6107d9565b81801561012e57600080fd5b5061014261013d366004613f0b565b610d6e565b604080516001600160a01b03909516855260208501939093529183015260608201526080016100f9565b61017f61017a366004614068565b610fb3565b604080519586526020860194909452928401919091526060830152608082015260a0016100f9565b6100cd6101b536600461400c565b6110e5565b8180156101c657600080fd5b506101da6101d5366004613ffa565b6117ae565b60408051938452602084019290925267ffffffffffffffff16908201526060016100f9565b81801561020b57600080fd5b506100ef61021a366004613e01565b6117c9565b81801561022b57600080fd5b506100ef61023a366004613e71565b611b9d565b81801561024b57600080fd5b506100ef61025a366004613f9b565b611ee9565b61026a838383611ef4565b505050565b604051636553690d60e11b8152306004820152600090859082906102fa906001906001600160a01b0385169063caa6d21a9060240160206040518083038186803b1580156102bc57600080fd5b505afa1580156102d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f491906141ff565b90612077565b905060008590506000816001600160a01b031663aabaecd66040518163ffffffff1660e01b815260040160206040518083038186803b15801561033c57600080fd5b505afa158015610350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103749190613e1d565b90506000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156103b157600080fd5b505afa1580156103c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e991906142bd565b60ff1690506000836001600160a01b031663f3c274a66040518163ffffffff1660e01b815260040160206040518083038186803b15801561042957600080fd5b505afa15801561043d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104619190613f7b565b15610528576105216104f961047784600a6146f9565b61048290600a614796565b866001600160a01b031663c52987cf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156104bb57600080fd5b505afa1580156104cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f391906141ff565b90612083565b61051b670de0b6b3a76400006104f36105146008600a614796565b8d90612083565b9061208f565b9050610564565b5086600882111561056457600061054083600861209b565b61054b90600a614796565b9050808211156105625761055f898261208f565b91505b505b826105796001600160a01b0382168c8b6120a7565b60408051600380825260808201909252600091816020015b610599613cb4565b815260200190600190039081610591579050506040805161010081019091529091508060008152602001306001600160a01b03168152602001306001600160a01b0316815260200160006001600160a01b031681526020018881526020016000815260200160008152602001604051806020016040528060008152508152508160008151811061063957634e487b7160e01b600052603260045260246000fd5b60209081029190910101526040805161010081019091528060058152602001306001600160a01b03168152602001306001600160a01b03168152602001866001600160a01b031681526020018881526020018b81526020016000815260200160405180602001604052806000815250815250816001815181106106cc57634e487b7160e01b600052603260045260246000fd5b60209081029190910101526040805161010081019091528060018152602001306001600160a01b03168152602001306001600160a01b031681526020018c6001600160a01b0316815260200188815260200184815260200160008152602001604051806020016040528060008152508152508160028151811061075f57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051635b0bf86360e11b81526001600160a01b0389169063b617f0c69061079690849060040161447d565b600060405180830381600087803b1580156107b057600080fd5b505af11580156107c4573d6000803e3d6000fd5b50949f9e505050505050505050505050505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a082319060240160206040518083038186803b15801561081d57600080fd5b505afa158015610831573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085591906141ff565b9050600081116108a15760405162461bcd60e51b815260206004820152601260248201527127379037aa37b5b2b739903a3790313ab93760711b60448201526064015b60405180910390fd5b604051636553690d60e11b815230600482015284906000906001600160a01b0383169063caa6d21a9060240160206040518083038186803b1580156108e557600080fd5b505afa1580156108f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091d91906141ff565b60405163d99d13f560e01b8152306004820152602481018290529091506000906001600160a01b0384169063d99d13f59060440160006040518083038186803b15801561096957600080fd5b505afa15801561097d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109a5919081019061409e565b8051519091506109e25760405162461bcd60e51b8152602060048201526008602482015267139bc81cda1bdc9d60c21b6044820152606401610898565b60008160400151600081518110610a0957634e487b7160e01b600052603260045260246000fd5b60209081029190910101516040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b158015610a5957600080fd5b505afa158015610a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9191906141ff565b6040805160028082526060820190925291925060009190816020015b610ab5613cb4565b815260200190600190039081610aad5790505060408051610100810190915290915080600281523060208201819052604082015285518051606090920191600090610b1057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03168152602001868152602001888152602001600081526020016040518060200160405280600081525081525081600081518110610b6d57634e487b7160e01b600052603260045260246000fd5b60209081029190910101526040805161010081019091528060068152602001306001600160a01b03168152602001306001600160a01b03168152602001846001600160a01b03168152602001868152602001610c2e8660600151600081518110610be757634e487b7160e01b600052603260045260246000fd5b602002602001015161051b8b8960a00151600081518110610c1857634e487b7160e01b600052603260045260246000fd5b602002602001015161208390919063ffffffff16565b8152602001600081526020016040518060200160405280600081525081525081600181518110610c6e57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051635b0bf86360e11b81526001600160a01b0387169063b617f0c690610ca590849060040161447d565b600060405180830381600087803b158015610cbf57600080fd5b505af1158015610cd3573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03861691506370a082319060240160206040518083038186803b158015610d1957600080fd5b505afa158015610d2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5191906141ff565b9050610d5d818461209b565b985050505050505050505b92915050565b60008080808080610d8560608a0160408b01613e01565b6001600160a01b03161415610da957610da2428960c001356120e3565b9050610e39565b610e36610dbc60608a0160408b01613e01565b6001600160a01b031663ade6e2aa6040518163ffffffff1660e01b815260040160206040518083038186803b158015610df457600080fd5b505afa158015610e08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2c91906141ff565b8960c001356120e3565b90505b8654600188015487548d9260ff8116926001600160a01b039081169262010000909204169061ffff16610e7260a08e0160808f016141dd565b61ffff1614610eff5760405163e436b89160e01b81526004810186905283151560248201526001600160a01b0385169063e436b89190604401604080518083038186803b158015610ec257600080fd5b505afa158015610ed6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610efa9190614217565b610f07565b8b60a0013560005b909750955086610f485760405162461bcd60e51b815260206004820152600c60248201526b21737472696b65507269636560a01b6044820152606401610898565b610f578c8c84848b8a89612215565b9850610f64898f8f6123a9565b975060008811610fa15760405162461bcd60e51b8152602060048201526008602482015267217072656d69756d60c01b6044820152606401610898565b50505050509650965096509692505050565b600182015460009081908190819081906020870135906001600160801b0380821691600160801b9004168380610ff060408c013586868e35612624565b90506000808c6040013511611006576000611012565b61101284838e3561265a565b905060008c606001358211611028576000611036565b6110368260608f013561209b565b9050611046816102f4898561209b565b60018f015490945061106b93508492506001600160801b0316905060808d01356126c4565b9450611077848661209b565b935061108a60408b013585858d35612624565b965061109883888c3561270c565b955060006110aa60408c013588612077565b9050600081116110bb5760006110c7565b6110c783898d3561265a565b98506110d59050848961209b565b9850505050509295509295909350565b60006110f46020850185613e01565b6001600160a01b031614156111355760405162461bcd60e51b815260206004820152600760248201526610afb7bbb732b960c91b6044820152606401610898565b60006111476040850160208601613e01565b6001600160a01b031614156111895760405162461bcd60e51b815260206004820152600860248201526710afb5b2b2b832b960c11b6044820152606401610898565b600061119b6060850160408601613e01565b6001600160a01b031614156111e35760405162461bcd60e51b815260206004820152600e60248201526d0857d99959549958da5c1a595b9d60921b6044820152606401610898565b6111f1620f424060646148c1565b83608001351061123c5760405162461bcd60e51b8152602060048201526016602482015275706572666f726d616e6365466565203e3d203130302560501b6044820152606401610898565b61124a620f424060646148c1565b8360600135106112945760405162461bcd60e51b81526020600482015260156024820152746d616e6167656d656e74466565203e3d203130302560581b6044820152606401610898565b60006112a360a08501856145ee565b9050116112e05760405162461bcd60e51b815260206004820152600b60248201526a215f746f6b656e4e616d6560a81b6044820152606401610898565b60006112ef60c08501856145ee565b90501161132e5760405162461bcd60e51b815260206004820152600d60248201526c0857dd1bdad95b94de5b589bdb609a1b6044820152606401610898565b826101600135600714806113475750826101600135600e145b806113575750826101600135601e145b806113675750826101600135605a145b80611377575082610160013560b4145b6113ae5760405162461bcd60e51b81526020600482015260086024820152670857dc195c9a5bd960c21b6044820152606401610898565b60006113c1610100850160e08601613e01565b6001600160a01b031614156114115760405162461bcd60e51b815260206004820152601660248201527510afb7b83a34b7b739a83932b6b4bab6a83934b1b2b960511b6044820152606401610898565b600061142561012085016101008601613e01565b6001600160a01b031614156114705760405162461bcd60e51b815260206004820152601160248201527010afb9ba3934b5b2a9b2b632b1ba34b7b760791b6044820152606401610898565b60006114846101408501610120860161423a565b63ffffffff161180156114b8575061149e600a60646148c1565b6114b06101408501610120860161423a565b63ffffffff16105b6114f85760405162461bcd60e51b81526020600482015260116024820152700857dc1c995b5a5d5b511a5cd8dbdd5b9d607a1b6044820152606401610898565b8083610140013510156115415760405162461bcd60e51b815260206004820152601160248201527010afb0bab1ba34b7b7223ab930ba34b7b760791b6044820152606401610898565b6000836101800135116115885760405162461bcd60e51b815260206004820152600f60248201526e215f6d61784465706f7369746f727360881b6044820152606401610898565b6000836101a00135116115cc5760405162461bcd60e51b815260206004820152600c60248201526b0857db5a5b91195c1bdcda5d60a21b6044820152606401610898565b60006115de6060840160408501613e01565b6001600160a01b0316141561161e5760405162461bcd60e51b815260206004820152600660248201526508585cdcd95d60d21b6044820152606401610898565b60006116306080840160608501613e01565b6001600160a01b031614156116755760405162461bcd60e51b815260206004820152600b60248201526a21756e6465726c79696e6760a81b6044820152606401610898565b600061168760a084016080850161425e565b66ffffffffffffff16116116ce5760405162461bcd60e51b815260206004820152600e60248201526d216d696e696d756d537570706c7960901b6044820152606401610898565b60006116e060c0840160a085016141b6565b6001600160681b03161161171f5760405162461bcd60e51b8152600401610898906020808252600490820152630216361760e41b604082015260600190565b61172f60a083016080840161425e565b66ffffffffffffff1661174860c0840160a085016141b6565b6001600160681b03161161026a5760405162461bcd60e51b815260206004820152602760248201527f6361702068617320746f20626520686967686572207468616e206d696e696d756044820152666d537570706c7960c81b6064820152608401610898565b60008060006117bc8461276f565b9250925092509193909250565b604051636553690d60e11b8152306004820152600090829082906001600160a01b0383169063caa6d21a9060240160206040518083038186803b15801561180f57600080fd5b505afa158015611823573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184791906141ff565b60405163d99d13f560e01b8152306004820152602481018290529091506000906001600160a01b0384169063d99d13f59060440160006040518083038186803b15801561189357600080fd5b505afa1580156118a7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118cf919081019061409e565b80515190915061190c5760405162461bcd60e51b8152602060048201526008602482015267139bc81cda1bdc9d60c21b6044820152606401610898565b6000816040015160008151811061193357634e487b7160e01b600052603260045260246000fd5b6020026020010151905060006001600160a01b0316816001600160a01b031614156119645750600095945050505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b1580156119a657600080fd5b505afa1580156119ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119de91906141ff565b60408051600180825281830190925291925060009190816020015b611a01613cb4565b8152602001906001900390816119f9579050506040805161010081019091529091508060078152602001306001600160a01b03168152602001306001600160a01b0316815260200160006001600160a01b0316815260200186815260200160008152602001600081526020016040518060200160405280600081525081525081600081518110611aa157634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051635b0bf86360e11b81526001600160a01b0387169063b617f0c690611ad890849060040161447d565b600060405180830381600087803b158015611af257600080fd5b505af1158015611b06573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03861691506370a082319060240160206040518083038186803b158015611b4c57600080fd5b505afa158015611b60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8491906141ff565b9050611b90818461209b565b9998505050505050505050565b6040516370a0823160e01b8152306004820152600090849082906001600160a01b038616906370a082319060240160206040518083038186803b158015611be357600080fd5b505afa158015611bf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1b91906141ff565b60405163565eea1960e01b81526001600160a01b038781166004830152602482018390529192509083169063565eea199060440160206040518083038186803b158015611c6757600080fd5b505afa158015611c7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9f91906141ff565b611cae57600092505050611ee2565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a082319060240160206040518083038186803b158015611cf057600080fd5b505afa158015611d04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2891906141ff565b60408051600180825281830190925291925060009190816020015b611d4b613cb4565b815260200190600190039081611d4357905050604080516101008101909152909150806008815260200160006001600160a01b03168152602001306001600160a01b03168152602001886001600160a01b0316815260200160008152602001848152602001600081526020016040518060200160405280600081525081525081600081518110611deb57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051635b0bf86360e11b81526001600160a01b0385169063b617f0c690611e2290849060040161447d565b600060405180830381600087803b158015611e3c57600080fd5b505af1158015611e50573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03891691506370a082319060240160206040518083038186803b158015611e9657600080fd5b505afa158015611eaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ece91906141ff565b9050611eda818461209b565b955050505050505b9392505050565b6000610d6882612b0b565b6000611f2b611f096060860160408701614285565b611f1960408701602088016142de565b611f2660208801886142de565b612e59565b60408051600180825281830190925291925060009190602080830190803683370190505090508181600081518110611f7357634e487b7160e01b600052603260045260246000fd5b602002602001018181525050836001600160a01b0316637882deaf846001600160a01b031663432833a66040518163ffffffff1660e01b815260040160206040518083038186803b158015611fc757600080fd5b505afa158015611fdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fff91906141ff565b836040518363ffffffff1660e01b815260040161201d92919061456e565b6040805180830381600087803b15801561203657600080fd5b505af115801561204a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206e9190614217565b50505050505050565b6000611ee282846146f9565b6000611ee282846148c1565b6000611ee2828461473f565b6000611ee2828461491f565b6001600160a01b03831673dac17f958d2ee523a2206206994597c13d831ec714156120d8576120d883836000612e9c565b61026a838383612e9c565b6000816007141561211b576120f783612fe2565b9050828111156121075780612114565b6121148162093a806146f9565b90506121f2565b81600e141561214a5761212d83612fe2565b90508281111561213d5780612114565b61211481621275006146f9565b81601e14156121815761215c8361300a565b90508281111561216c5780612114565b61211461217c8262093a806146f9565b61300a565b81605a14156121b8576121938361303f565b9050828111156121a35780612114565b6121146121b38262093a806146f9565b61303f565b8160b414156121f2576121ca836130b1565b9050828111156121da57806121ef565b6121ef6121ea8262093a806146f9565b6130b1565b90505b6121ff6201518082614966565b612209908261491f565b611ee2906170806146f9565b60008061222560208a018a613e01565b905060006001600160a01b03821663115470548961224960408e0160208f01613e01565b8a8a8a8a6040518763ffffffff1660e01b815260040161226e969594939291906143bf565b60206040518083038186803b15801561228657600080fd5b505afa15801561229a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122be9190613e1d565b90506001600160a01b038116156122d857915061239e9050565b6000826001600160a01b031663c09746308a8d60200160208101906122fd9190613e01565b8b8b8b8b6040518763ffffffff1660e01b8152600401612322969594939291906143bf565b602060405180830381600087803b15801561233c57600080fd5b505af1158015612350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123749190613e1d565b9050612399818b8a8e602001602081019061238f9190613e01565b8f606001356130e2565b925050505b979650505050505050565b60008084905060008490506000816001600160a01b03166330a75871846001600160a01b031663c52987cf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156123fe57600080fd5b505afa158015612412573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243691906141ff565b856001600160a01b031663ade6e2aa6040518163ffffffff1660e01b815260040160206040518083038186803b15801561246f57600080fd5b505afa158015612483573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a791906141ff565b866001600160a01b031663f3c274a66040518163ffffffff1660e01b815260040160206040518083038186803b1580156124e057600080fd5b505afa1580156124f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125189190613f7b565b6040516001600160e01b031960e086901b168152600481019390935260248301919091521515604482015260640160206040518083038186803b15801561255e57600080fd5b505afa158015612572573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259691906141ff565b90506125b16125a7600a60646148c1565b61051b8388612083565b90506001600160601b0381111561261a5760405162461bcd60e51b815260206004820152602760248201527f6f7074696f6e5072656d69756d203e20747970652875696e74393629206d61786044820152662076616c75652160c81b6064820152608401610898565b9695505050505050565b60008061263283600a614796565b905060008611612642578061261a565b61261a8661051b612653888861209b565b8490612083565b6000600183116126a45760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b6044820152606401610898565b6126bc6126b283600a614796565b61051b8686612083565b949350505050565b6000808385116126d55760006126df565b6126df858561209b565b905060008084116126f157600061261a565b61261a612702620f424060646148c1565b61051b8487612083565b6000600183116127565760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b6044820152606401610898565b6126bc8361051b61276885600a614796565b8790612083565b600080806127936127816064806148c1565b61051b60a087013560c0880135612083565b92506127d16127a76060860135600a614796565b61051b60e0870135816127bf60608a01356008612077565b6127ca90600a614796565b8890612083565b91506001600160601b038311156128365760405162461bcd60e51b8152602060048201526024808201527f73656c6c416d6f756e74203e20747970652875696e74393629206d61782076616044820152636c75652160e01b6064820152608401610898565b6001600160601b038211156128995760405162461bcd60e51b815260206004820152602360248201527f627579416d6f756e74203e20747970652875696e74393629206d61782076616c60448201526275652160e81b6064820152608401610898565b6128cd6128ac6040860160208701613e01565b846128bd6060880160408901613e01565b6001600160a01b03169190612e9c565b6040805160018082528183019092526000916020808301908036833750506040805160018082528183019092529293506000929150602080830190803683375050604080516001808252818301909252929350600092915060208083019080368337019050509050848360008151811061295757634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160601b031690816001600160601b031681525050858260008151811061299957634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160601b031690816001600160601b031681525050600160001b816000815181106129df57634e487b7160e01b600052603260045260246000fd5b6020026020010181815250508660200160208101906129fe9190613e01565b6001600160a01b031663d225269c88608001358585856040518563ffffffff1660e01b8152600401612a339493929190614587565b602060405180830381600087803b158015612a4d57600080fd5b505af1158015612a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8591906142a1565b9350612a9961012088016101008901613e01565b6001600160a01b0316612aaf6020890189613e01565b6040805160808b01358152602081018a90529081018890526001600160a01b0391909116907fa227b5eceb2bd983c0ed9dd34c971be74cd4f386b289d4415602a1fbcf2cb53b9060600160405180910390a35050509193909250565b600080612b23612b1e6020850185613e01565b61350e565b905060008111612b6a5760405162461bcd60e51b8152602060048201526012602482015271139bc81bdd1bdad95b9cc81d1bc81cd95b1b60721b6044820152606401610898565b612c10612b7d6040850160208601613e01565b612b8a6020860186613e01565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b158015612bcb57600080fd5b505afa158015612bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0391906141ff565b6128bd6020870187613e01565b6000612c2e612c24836402540be400612083565b85608001356135f6565b90506012846060013511612c6557612c60612c4e6012606087013561209b565b612c5990600a614796565b829061208f565b612c89565b612c89612c776060860135601261209b565b612c8290600a614796565b8290612083565b90506001600160601b03811115612d085760405162461bcd60e51b815260206004820152603a60248201527f6f7074696f6e5072656d69756d202a206f546f6b656e53656c6c416d6f756e7460448201527f203e20747970652875696e74393629206d61782076616c7565210000000000006064820152608401610898565b6000612d184260a0870135612077565b9050612d2a6040860160208701613e01565b6001600160a01b0316630a4cd6c9612d456020880188613e01565b612d556060890160408a01613e01565b60408051602081018252600080825291516001600160e01b031960e087901b168152612d94949392889283928c928c92600192829182916004016143f8565b602060405180830381600087803b158015612dae57600080fd5b505af1158015612dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de691906141ff565b935033612df96060870160408801613e01565b6001600160a01b0316612e0f6020880188613e01565b6001600160a01b03167f95ad3b10488285d6307fda297f633faaf2a0d713c08ebe5f49c1b9255b01d29e87604051612e4991815260200190565b60405180910390a4505050919050565b60006001600160601b038216612e926bffffffffffffffffffffffff60601b606086901b166001600160c01b031960c088901b166146f9565b6126bc91906146f9565b801580612f255750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015612eeb57600080fd5b505afa158015612eff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2391906141ff565b155b612f905760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610898565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261026a908490613630565b600080612fee83613702565b905082811015610d68576130058162093a806146f9565b611ee2565b60008061301683613731565b9050600061302382613702565b905081811161303257806126bc565b6126bc62093a808261491f565b60008061304b8361375e565b90506000600382111561307f57600682111561307857600982111561307157600c613082565b6009613082565b6006613082565b60035b60ff169050600061309d6130958661377d565b836001613798565b90506130a88161300a565b95945050505050565b6000806130bd8361375e565b9050600060068211156130d157600c613082565b506006600061309d6130958661377d565b6001600160a01b0385166131295760405162461bcd60e51b815260206004820152600e60248201526d216f746f6b656e4164647265737360901b6044820152606401610898565b8354604080516379e13a5360e11b81529051879260ff161515916001600160a01b0384169163f3c274a691600480820192602092909190829003018186803b15801561317457600080fd5b505afa158015613188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131ac9190613f7b565b1515146131eb5760405162461bcd60e51b815260206004820152600d60248201526c0a8f2e0ca40dad2e6dac2e8c6d609b1b6044820152606401610898565b600185015460408051631c56369f60e21b815290516001600160a01b0392831692841691637158da7c916004808301926020929190829003018186803b15801561323457600080fd5b505afa158015613248573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326c9190613e1d565b6001600160a01b0316146132ba5760405162461bcd60e51b815260206004820152601560248201527415dc9bdb99c81d5b99195c9b1e5a5b99d05cdcd95d605a1b6044820152606401610898565b836001600160a01b0316816001600160a01b031663aabaecd66040518163ffffffff1660e01b815260040160206040518083038186803b1580156132fd57600080fd5b505afa158015613311573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133359190613e1d565b6001600160a01b0316146133835760405162461bcd60e51b815260206004820152601560248201527415dc9bdb99c818dbdb1b185d195c985b105cdcd95d605a1b6044820152606401610898565b826001600160a01b0316816001600160a01b03166317d69bc86040518163ffffffff1660e01b815260040160206040518083038186803b1580156133c657600080fd5b505afa1580156133da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fe9190613e1d565b6001600160a01b03161461344a5760405162461bcd60e51b8152602060048201526013602482015272737472696b65417373657420213d205553444360681b6044820152606401610898565b60006134564284612077565b905080826001600160a01b031663ade6e2aa6040518163ffffffff1660e01b815260040160206040518083038186803b15801561349257600080fd5b505afa1580156134a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ca91906141ff565b101561206e5760405162461bcd60e51b8152602060048201526013602482015272457870697279206265666f72652064656c617960681b6044820152606401610898565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a082319060240160206040518083038186803b15801561355257600080fd5b505afa158015613566573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358a91906141ff565b90506001600160601b03811115610d685760405162461bcd60e51b815260206004820152602a60248201527f6f546f6b656e53656c6c416d6f756e74203e20747970652875696e74393629206044820152696d61782076616c75652160b01b6064820152608401610898565b6000670de0b6b3a764000061362661360e85856137b3565b6136216002670de0b6b3a764000061473f565b61381a565b611ee2919061473f565b6000613685826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661386f9092919063ffffffff16565b80519091501561026a57808060200190518101906136a39190613f7b565b61026a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610898565b600061370d8261387e565b61371a90620151806148c1565b61372783620697806146f9565b610d68919061491f565b6000620151806137276137438461377d565b61374c8561375e565b6137579060016146f9565b6001613798565b6000613775613770620151808461473f565b6138b2565b509392505050565b600061378f613770620151808461473f565b50909392505050565b6000620151806137a9858585613a26565b6126bc91906148c1565b60008115806137d7575082826137c981836148c1565b92506137d5908361473f565b145b610d685760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b6044820152606401610898565b60008261382783826146f9565b9150811015610d685760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b6044820152606401610898565b60606126bc8484600085613b63565b60008061388e620151808461473f565b9050600761389d8260036146f9565b6138a79190614966565b611ee29060016146f9565b60008080838162253d8c6138c98362010bd96146b8565b6138d391906146b8565b9050600062023ab16138e683600461483e565b6138f09190614711565b905060046139018262023ab161483e565b61390c9060036146b8565b6139169190614711565b61392090836148e0565b9150600062164b096139338460016146b8565b61393f90610fa061483e565b6139499190614711565b90506004613959826105b561483e565b6139639190614711565b61396d90846148e0565b61397890601f6146b8565b9250600061098f61398a85605061483e565b6139949190614711565b9050600060506139a68361098f61483e565b6139b09190614711565b6139ba90866148e0565b90506139c7600b83614711565b94506139d485600c61483e565b6139df8360026146b8565b6139e991906148e0565b915084836139f86031876148e0565b613a0390606461483e565b613a0d91906146b8565b613a1791906146b8565b9a919950975095505050505050565b60006107b2841015613a3757600080fd5b838383600062253d8c60046064600c613a51600e886148e0565b613a5b9190614711565b613a67886113246146b8565b613a7191906146b8565b613a7b9190614711565b613a8690600361483e565b613a909190614711565b600c80613a9e600e886148e0565b613aa89190614711565b613ab390600c61483e565b613abe6002886148e0565b613ac891906148e0565b613ad49061016f61483e565b613ade9190614711565b6004600c613aed600e896148e0565b613af79190614711565b613b03896112c06146b8565b613b0d91906146b8565b613b19906105b561483e565b613b239190614711565b613b2f617d4b876148e0565b613b3991906146b8565b613b4391906146b8565b613b4d91906148e0565b613b5791906148e0565b98975050505050505050565b606082471015613bc45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610898565b843b613c125760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610898565b600080866001600160a01b03168587604051613c2e91906143a3565b60006040518083038185875af1925050503d8060008114613c6b576040519150601f19603f3d011682016040523d82523d6000602084013e613c70565b606091505b509150915061239e82828660608315613c8a575081611ee2565b825115613c9a5782518084602001fd5b8160405162461bcd60e51b8152600401610898919061455b565b604080516101008101909152806000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001606081525090565b600082601f830112613d25578081fd5b81516020613d3a613d3583614694565b614663565b80838252828201915082860187848660051b8901011115613d59578586fd5b855b85811015613d80578151613d6e816149bc565b84529284019290840190600101613d5b565b5090979650505050505050565b600082601f830112613d9d578081fd5b81516020613dad613d3583614694565b80838252828201915082860187848660051b8901011115613dcc578586fd5b855b85811015613d8057815184529284019290840190600101613dce565b600060c08284031215613dfb578081fd5b50919050565b600060208284031215613e12578081fd5b8135611ee2816149bc565b600060208284031215613e2e578081fd5b8151611ee2816149bc565b60008060408385031215613e4b578081fd5b8235613e56816149bc565b91506020830135613e66816149bc565b809150509250929050565b600080600060608486031215613e85578081fd5b8335613e90816149bc565b92506020840135613ea0816149bc565b91506040840135613eb0816149bc565b809150509250925092565b60008060008060808587031215613ed0578182fd5b8435613edb816149bc565b93506020850135613eeb816149bc565b92506040850135613efb816149bc565b9396929550929360600135925050565b600080600080600080868803610180811215613f25578485fd5b8735613f30816149bc565b96506020880135613f40816149bc565b95506040880135945060e0605f1982011215613f5a578283fd5b50606087019250610140870135915061016087013590509295509295509295565b600060208284031215613f8c578081fd5b81518015158114611ee2578182fd5b600060c08284031215613fac578081fd5b611ee28383613dea565b600080600083850360a0811215613fcb578182fd5b6060811215613fd8578182fd5b508392506060840135613fea816149bc565b91506080840135613eb0816149bc565b60006101208284031215613dfb578081fd5b60008060006101008486031215614021578081fd5b833567ffffffffffffffff811115614037578182fd5b84016101c08187031215614049578182fd5b92506140588560208601613dea565b915060e084013590509250925092565b60008082840360c081121561407b578283fd5b8335925060a0601f1982011215614090578182fd5b506020830190509250929050565b6000602082840312156140af578081fd5b815167ffffffffffffffff808211156140c6578283fd5b9083019060c082860312156140d9578283fd5b6140e161463a565b8251828111156140ef578485fd5b6140fb87828601613d15565b82525060208301518281111561410f578485fd5b61411b87828601613d15565b602083015250604083015182811115614132578485fd5b61413e87828601613d15565b604083015250606083015182811115614155578485fd5b61416187828601613d8d565b606083015250608083015182811115614178578485fd5b61418487828601613d8d565b60808301525060a08301518281111561419b578485fd5b6141a787828601613d8d565b60a08301525095945050505050565b6000602082840312156141c7578081fd5b81356001600160681b0381168114611ee2578182fd5b6000602082840312156141ee578081fd5b813561ffff81168114611ee2578182fd5b600060208284031215614210578081fd5b5051919050565b60008060408385031215614229578182fd5b505080516020909101519092909150565b60006020828403121561424b578081fd5b813563ffffffff81168114611ee2578182fd5b60006020828403121561426f578081fd5b813566ffffffffffffff81168114611ee2578182fd5b600060208284031215614296578081fd5b8135611ee2816149d4565b6000602082840312156142b2578081fd5b8151611ee2816149d4565b6000602082840312156142ce578081fd5b815160ff81168114611ee2578182fd5b6000602082840312156142ef578081fd5b81356001600160601b0381168114611ee2578182fd5b6000815180845260208085019450808401835b8381101561433457815187529582019590820190600101614318565b509495945050505050565b6000815180845260208085019450808401835b838110156143345781516001600160601b031687529582019590820190600101614352565b6000815180845261438f816020860160208601614936565b601f01601f19169290920160200192915050565b600082516143b5818460208701614936565b9190910192915050565b6001600160a01b03968716815294861660208601529290941660408401526060830152608082019290925290151560a082015260c00190565b6001600160a01b038c811682528b81166020830152604082018b9052606082018a90526001600160601b038981166080840152881660a083015260c0820187905260e082018690528415156101008301528316610120820152610160610140820181905260009061446b83820185614377565b9e9d5050505050505050505050505050565b60006020808301818452808551808352604092508286019150828160051b870101848801865b8381101561454d57603f1989840301855281516101008151600b81106144d757634e487b7160e01b8b52602160045260248bfd5b8552818901516001600160a01b039081168a87015288830151811689870152606080840151909116908601526080808301519086015260a0808301519086015260c0808301519086015260e09182015191850181905261453981860183614377565b9689019694505050908601906001016144a3565b509098975050505050505050565b602081526000611ee26020830184614377565b8281526040602082015260006126bc6040830184614305565b84815260a0602082015260006145a060a083018661433f565b82810360408401526145b2818661433f565b905082810360608401526145c68185614305565b83810360809094019390935250506002815261060f60f31b6020820152604001949350505050565b6000808335601e19843603018112614604578283fd5b83018035915067ffffffffffffffff82111561461e578283fd5b60200191503681900382131561463357600080fd5b9250929050565b60405160c0810167ffffffffffffffff8111828210171561465d5761465d6149a6565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561468c5761468c6149a6565b604052919050565b600067ffffffffffffffff8211156146ae576146ae6149a6565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146da576146da61497a565b600160ff1b83900384128116156146f3576146f361497a565b50500190565b6000821982111561470c5761470c61497a565b500190565b60008261472057614720614990565b600160ff1b82146000198414161561473a5761473a61497a565b500590565b60008261474e5761474e614990565b500490565b600181815b8085111561478e5781600019048211156147745761477461497a565b8085161561478157918102915b93841c9390800290614758565b509250929050565b6000611ee283836000826147ac57506001610d68565b816147b957506000610d68565b81600181146147cf57600281146147d9576147f5565b6001915050610d68565b60ff8411156147ea576147ea61497a565b50506001821b610d68565b5060208310610133831016604e8410600b8410161715614818575081810a610d68565b6148228383614753565b80600019048211156148365761483661497a565b029392505050565b60006001600160ff1b03818413828413808216868404861116156148645761486461497a565b600160ff1b848712828116878305891216156148825761488261497a565b85871292508782058712848416161561489d5761489d61497a565b878505871281841616156148b3576148b361497a565b505050929093029392505050565b60008160001904831182151516156148db576148db61497a565b500290565b60008083128015600160ff1b8501841216156148fe576148fe61497a565b6001600160ff1b03840183138116156149195761491961497a565b50500390565b6000828210156149315761493161497a565b500390565b60005b83811015614951578181015183820152602001614939565b83811115614960576000848401525b50505050565b60008261497557614975614990565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146149d157600080fd5b50565b67ffffffffffffffff811681146149d157600080fdfea2646970667358221220b95c20f4c0d0bb193e394828202857e8f6d4228ea2ec08f64b51a549981e37f564736f6c63430008040033
Deployed Bytecode
0x73e1d00f9bafea5aa40a2192af12b68af3d390afe230146080604052600436106100a85760003560e01c806384d831a91161007057806384d831a9146101a757806395a170d7146101ba578063d8dfd0fe146101ff578063de8e34181461021f578063eebc5ff41461023f57600080fd5b806307cc4239146100ad5780632904c239146100cf57806358ffbb3d146101025780635a90235d14610122578063686fb2f21461016c575b600080fd5b8180156100b957600080fd5b506100cd6100c8366004613fb6565b61025f565b005b8180156100db57600080fd5b506100ef6100ea366004613ebb565b61026f565b6040519081526020015b60405180910390f35b81801561010e57600080fd5b506100ef61011d366004613e39565b6107d9565b81801561012e57600080fd5b5061014261013d366004613f0b565b610d6e565b604080516001600160a01b03909516855260208501939093529183015260608201526080016100f9565b61017f61017a366004614068565b610fb3565b604080519586526020860194909452928401919091526060830152608082015260a0016100f9565b6100cd6101b536600461400c565b6110e5565b8180156101c657600080fd5b506101da6101d5366004613ffa565b6117ae565b60408051938452602084019290925267ffffffffffffffff16908201526060016100f9565b81801561020b57600080fd5b506100ef61021a366004613e01565b6117c9565b81801561022b57600080fd5b506100ef61023a366004613e71565b611b9d565b81801561024b57600080fd5b506100ef61025a366004613f9b565b611ee9565b61026a838383611ef4565b505050565b604051636553690d60e11b8152306004820152600090859082906102fa906001906001600160a01b0385169063caa6d21a9060240160206040518083038186803b1580156102bc57600080fd5b505afa1580156102d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f491906141ff565b90612077565b905060008590506000816001600160a01b031663aabaecd66040518163ffffffff1660e01b815260040160206040518083038186803b15801561033c57600080fd5b505afa158015610350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103749190613e1d565b90506000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156103b157600080fd5b505afa1580156103c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e991906142bd565b60ff1690506000836001600160a01b031663f3c274a66040518163ffffffff1660e01b815260040160206040518083038186803b15801561042957600080fd5b505afa15801561043d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104619190613f7b565b15610528576105216104f961047784600a6146f9565b61048290600a614796565b866001600160a01b031663c52987cf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156104bb57600080fd5b505afa1580156104cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f391906141ff565b90612083565b61051b670de0b6b3a76400006104f36105146008600a614796565b8d90612083565b9061208f565b9050610564565b5086600882111561056457600061054083600861209b565b61054b90600a614796565b9050808211156105625761055f898261208f565b91505b505b826105796001600160a01b0382168c8b6120a7565b60408051600380825260808201909252600091816020015b610599613cb4565b815260200190600190039081610591579050506040805161010081019091529091508060008152602001306001600160a01b03168152602001306001600160a01b0316815260200160006001600160a01b031681526020018881526020016000815260200160008152602001604051806020016040528060008152508152508160008151811061063957634e487b7160e01b600052603260045260246000fd5b60209081029190910101526040805161010081019091528060058152602001306001600160a01b03168152602001306001600160a01b03168152602001866001600160a01b031681526020018881526020018b81526020016000815260200160405180602001604052806000815250815250816001815181106106cc57634e487b7160e01b600052603260045260246000fd5b60209081029190910101526040805161010081019091528060018152602001306001600160a01b03168152602001306001600160a01b031681526020018c6001600160a01b0316815260200188815260200184815260200160008152602001604051806020016040528060008152508152508160028151811061075f57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051635b0bf86360e11b81526001600160a01b0389169063b617f0c69061079690849060040161447d565b600060405180830381600087803b1580156107b057600080fd5b505af11580156107c4573d6000803e3d6000fd5b50949f9e505050505050505050505050505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a082319060240160206040518083038186803b15801561081d57600080fd5b505afa158015610831573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085591906141ff565b9050600081116108a15760405162461bcd60e51b815260206004820152601260248201527127379037aa37b5b2b739903a3790313ab93760711b60448201526064015b60405180910390fd5b604051636553690d60e11b815230600482015284906000906001600160a01b0383169063caa6d21a9060240160206040518083038186803b1580156108e557600080fd5b505afa1580156108f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091d91906141ff565b60405163d99d13f560e01b8152306004820152602481018290529091506000906001600160a01b0384169063d99d13f59060440160006040518083038186803b15801561096957600080fd5b505afa15801561097d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109a5919081019061409e565b8051519091506109e25760405162461bcd60e51b8152602060048201526008602482015267139bc81cda1bdc9d60c21b6044820152606401610898565b60008160400151600081518110610a0957634e487b7160e01b600052603260045260246000fd5b60209081029190910101516040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a082319060240160206040518083038186803b158015610a5957600080fd5b505afa158015610a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9191906141ff565b6040805160028082526060820190925291925060009190816020015b610ab5613cb4565b815260200190600190039081610aad5790505060408051610100810190915290915080600281523060208201819052604082015285518051606090920191600090610b1057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03168152602001868152602001888152602001600081526020016040518060200160405280600081525081525081600081518110610b6d57634e487b7160e01b600052603260045260246000fd5b60209081029190910101526040805161010081019091528060068152602001306001600160a01b03168152602001306001600160a01b03168152602001846001600160a01b03168152602001868152602001610c2e8660600151600081518110610be757634e487b7160e01b600052603260045260246000fd5b602002602001015161051b8b8960a00151600081518110610c1857634e487b7160e01b600052603260045260246000fd5b602002602001015161208390919063ffffffff16565b8152602001600081526020016040518060200160405280600081525081525081600181518110610c6e57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051635b0bf86360e11b81526001600160a01b0387169063b617f0c690610ca590849060040161447d565b600060405180830381600087803b158015610cbf57600080fd5b505af1158015610cd3573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03861691506370a082319060240160206040518083038186803b158015610d1957600080fd5b505afa158015610d2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5191906141ff565b9050610d5d818461209b565b985050505050505050505b92915050565b60008080808080610d8560608a0160408b01613e01565b6001600160a01b03161415610da957610da2428960c001356120e3565b9050610e39565b610e36610dbc60608a0160408b01613e01565b6001600160a01b031663ade6e2aa6040518163ffffffff1660e01b815260040160206040518083038186803b158015610df457600080fd5b505afa158015610e08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2c91906141ff565b8960c001356120e3565b90505b8654600188015487548d9260ff8116926001600160a01b039081169262010000909204169061ffff16610e7260a08e0160808f016141dd565b61ffff1614610eff5760405163e436b89160e01b81526004810186905283151560248201526001600160a01b0385169063e436b89190604401604080518083038186803b158015610ec257600080fd5b505afa158015610ed6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610efa9190614217565b610f07565b8b60a0013560005b909750955086610f485760405162461bcd60e51b815260206004820152600c60248201526b21737472696b65507269636560a01b6044820152606401610898565b610f578c8c84848b8a89612215565b9850610f64898f8f6123a9565b975060008811610fa15760405162461bcd60e51b8152602060048201526008602482015267217072656d69756d60c01b6044820152606401610898565b50505050509650965096509692505050565b600182015460009081908190819081906020870135906001600160801b0380821691600160801b9004168380610ff060408c013586868e35612624565b90506000808c6040013511611006576000611012565b61101284838e3561265a565b905060008c606001358211611028576000611036565b6110368260608f013561209b565b9050611046816102f4898561209b565b60018f015490945061106b93508492506001600160801b0316905060808d01356126c4565b9450611077848661209b565b935061108a60408b013585858d35612624565b965061109883888c3561270c565b955060006110aa60408c013588612077565b9050600081116110bb5760006110c7565b6110c783898d3561265a565b98506110d59050848961209b565b9850505050509295509295909350565b60006110f46020850185613e01565b6001600160a01b031614156111355760405162461bcd60e51b815260206004820152600760248201526610afb7bbb732b960c91b6044820152606401610898565b60006111476040850160208601613e01565b6001600160a01b031614156111895760405162461bcd60e51b815260206004820152600860248201526710afb5b2b2b832b960c11b6044820152606401610898565b600061119b6060850160408601613e01565b6001600160a01b031614156111e35760405162461bcd60e51b815260206004820152600e60248201526d0857d99959549958da5c1a595b9d60921b6044820152606401610898565b6111f1620f424060646148c1565b83608001351061123c5760405162461bcd60e51b8152602060048201526016602482015275706572666f726d616e6365466565203e3d203130302560501b6044820152606401610898565b61124a620f424060646148c1565b8360600135106112945760405162461bcd60e51b81526020600482015260156024820152746d616e6167656d656e74466565203e3d203130302560581b6044820152606401610898565b60006112a360a08501856145ee565b9050116112e05760405162461bcd60e51b815260206004820152600b60248201526a215f746f6b656e4e616d6560a81b6044820152606401610898565b60006112ef60c08501856145ee565b90501161132e5760405162461bcd60e51b815260206004820152600d60248201526c0857dd1bdad95b94de5b589bdb609a1b6044820152606401610898565b826101600135600714806113475750826101600135600e145b806113575750826101600135601e145b806113675750826101600135605a145b80611377575082610160013560b4145b6113ae5760405162461bcd60e51b81526020600482015260086024820152670857dc195c9a5bd960c21b6044820152606401610898565b60006113c1610100850160e08601613e01565b6001600160a01b031614156114115760405162461bcd60e51b815260206004820152601660248201527510afb7b83a34b7b739a83932b6b4bab6a83934b1b2b960511b6044820152606401610898565b600061142561012085016101008601613e01565b6001600160a01b031614156114705760405162461bcd60e51b815260206004820152601160248201527010afb9ba3934b5b2a9b2b632b1ba34b7b760791b6044820152606401610898565b60006114846101408501610120860161423a565b63ffffffff161180156114b8575061149e600a60646148c1565b6114b06101408501610120860161423a565b63ffffffff16105b6114f85760405162461bcd60e51b81526020600482015260116024820152700857dc1c995b5a5d5b511a5cd8dbdd5b9d607a1b6044820152606401610898565b8083610140013510156115415760405162461bcd60e51b815260206004820152601160248201527010afb0bab1ba34b7b7223ab930ba34b7b760791b6044820152606401610898565b6000836101800135116115885760405162461bcd60e51b815260206004820152600f60248201526e215f6d61784465706f7369746f727360881b6044820152606401610898565b6000836101a00135116115cc5760405162461bcd60e51b815260206004820152600c60248201526b0857db5a5b91195c1bdcda5d60a21b6044820152606401610898565b60006115de6060840160408501613e01565b6001600160a01b0316141561161e5760405162461bcd60e51b815260206004820152600660248201526508585cdcd95d60d21b6044820152606401610898565b60006116306080840160608501613e01565b6001600160a01b031614156116755760405162461bcd60e51b815260206004820152600b60248201526a21756e6465726c79696e6760a81b6044820152606401610898565b600061168760a084016080850161425e565b66ffffffffffffff16116116ce5760405162461bcd60e51b815260206004820152600e60248201526d216d696e696d756d537570706c7960901b6044820152606401610898565b60006116e060c0840160a085016141b6565b6001600160681b03161161171f5760405162461bcd60e51b8152600401610898906020808252600490820152630216361760e41b604082015260600190565b61172f60a083016080840161425e565b66ffffffffffffff1661174860c0840160a085016141b6565b6001600160681b03161161026a5760405162461bcd60e51b815260206004820152602760248201527f6361702068617320746f20626520686967686572207468616e206d696e696d756044820152666d537570706c7960c81b6064820152608401610898565b60008060006117bc8461276f565b9250925092509193909250565b604051636553690d60e11b8152306004820152600090829082906001600160a01b0383169063caa6d21a9060240160206040518083038186803b15801561180f57600080fd5b505afa158015611823573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184791906141ff565b60405163d99d13f560e01b8152306004820152602481018290529091506000906001600160a01b0384169063d99d13f59060440160006040518083038186803b15801561189357600080fd5b505afa1580156118a7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118cf919081019061409e565b80515190915061190c5760405162461bcd60e51b8152602060048201526008602482015267139bc81cda1bdc9d60c21b6044820152606401610898565b6000816040015160008151811061193357634e487b7160e01b600052603260045260246000fd5b6020026020010151905060006001600160a01b0316816001600160a01b031614156119645750600095945050505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b1580156119a657600080fd5b505afa1580156119ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119de91906141ff565b60408051600180825281830190925291925060009190816020015b611a01613cb4565b8152602001906001900390816119f9579050506040805161010081019091529091508060078152602001306001600160a01b03168152602001306001600160a01b0316815260200160006001600160a01b0316815260200186815260200160008152602001600081526020016040518060200160405280600081525081525081600081518110611aa157634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051635b0bf86360e11b81526001600160a01b0387169063b617f0c690611ad890849060040161447d565b600060405180830381600087803b158015611af257600080fd5b505af1158015611b06573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03861691506370a082319060240160206040518083038186803b158015611b4c57600080fd5b505afa158015611b60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8491906141ff565b9050611b90818461209b565b9998505050505050505050565b6040516370a0823160e01b8152306004820152600090849082906001600160a01b038616906370a082319060240160206040518083038186803b158015611be357600080fd5b505afa158015611bf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1b91906141ff565b60405163565eea1960e01b81526001600160a01b038781166004830152602482018390529192509083169063565eea199060440160206040518083038186803b158015611c6757600080fd5b505afa158015611c7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9f91906141ff565b611cae57600092505050611ee2565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a082319060240160206040518083038186803b158015611cf057600080fd5b505afa158015611d04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2891906141ff565b60408051600180825281830190925291925060009190816020015b611d4b613cb4565b815260200190600190039081611d4357905050604080516101008101909152909150806008815260200160006001600160a01b03168152602001306001600160a01b03168152602001886001600160a01b0316815260200160008152602001848152602001600081526020016040518060200160405280600081525081525081600081518110611deb57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051635b0bf86360e11b81526001600160a01b0385169063b617f0c690611e2290849060040161447d565b600060405180830381600087803b158015611e3c57600080fd5b505af1158015611e50573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03891691506370a082319060240160206040518083038186803b158015611e9657600080fd5b505afa158015611eaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ece91906141ff565b9050611eda818461209b565b955050505050505b9392505050565b6000610d6882612b0b565b6000611f2b611f096060860160408701614285565b611f1960408701602088016142de565b611f2660208801886142de565b612e59565b60408051600180825281830190925291925060009190602080830190803683370190505090508181600081518110611f7357634e487b7160e01b600052603260045260246000fd5b602002602001018181525050836001600160a01b0316637882deaf846001600160a01b031663432833a66040518163ffffffff1660e01b815260040160206040518083038186803b158015611fc757600080fd5b505afa158015611fdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fff91906141ff565b836040518363ffffffff1660e01b815260040161201d92919061456e565b6040805180830381600087803b15801561203657600080fd5b505af115801561204a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206e9190614217565b50505050505050565b6000611ee282846146f9565b6000611ee282846148c1565b6000611ee2828461473f565b6000611ee2828461491f565b6001600160a01b03831673dac17f958d2ee523a2206206994597c13d831ec714156120d8576120d883836000612e9c565b61026a838383612e9c565b6000816007141561211b576120f783612fe2565b9050828111156121075780612114565b6121148162093a806146f9565b90506121f2565b81600e141561214a5761212d83612fe2565b90508281111561213d5780612114565b61211481621275006146f9565b81601e14156121815761215c8361300a565b90508281111561216c5780612114565b61211461217c8262093a806146f9565b61300a565b81605a14156121b8576121938361303f565b9050828111156121a35780612114565b6121146121b38262093a806146f9565b61303f565b8160b414156121f2576121ca836130b1565b9050828111156121da57806121ef565b6121ef6121ea8262093a806146f9565b6130b1565b90505b6121ff6201518082614966565b612209908261491f565b611ee2906170806146f9565b60008061222560208a018a613e01565b905060006001600160a01b03821663115470548961224960408e0160208f01613e01565b8a8a8a8a6040518763ffffffff1660e01b815260040161226e969594939291906143bf565b60206040518083038186803b15801561228657600080fd5b505afa15801561229a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122be9190613e1d565b90506001600160a01b038116156122d857915061239e9050565b6000826001600160a01b031663c09746308a8d60200160208101906122fd9190613e01565b8b8b8b8b6040518763ffffffff1660e01b8152600401612322969594939291906143bf565b602060405180830381600087803b15801561233c57600080fd5b505af1158015612350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123749190613e1d565b9050612399818b8a8e602001602081019061238f9190613e01565b8f606001356130e2565b925050505b979650505050505050565b60008084905060008490506000816001600160a01b03166330a75871846001600160a01b031663c52987cf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156123fe57600080fd5b505afa158015612412573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243691906141ff565b856001600160a01b031663ade6e2aa6040518163ffffffff1660e01b815260040160206040518083038186803b15801561246f57600080fd5b505afa158015612483573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a791906141ff565b866001600160a01b031663f3c274a66040518163ffffffff1660e01b815260040160206040518083038186803b1580156124e057600080fd5b505afa1580156124f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125189190613f7b565b6040516001600160e01b031960e086901b168152600481019390935260248301919091521515604482015260640160206040518083038186803b15801561255e57600080fd5b505afa158015612572573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259691906141ff565b90506125b16125a7600a60646148c1565b61051b8388612083565b90506001600160601b0381111561261a5760405162461bcd60e51b815260206004820152602760248201527f6f7074696f6e5072656d69756d203e20747970652875696e74393629206d61786044820152662076616c75652160c81b6064820152608401610898565b9695505050505050565b60008061263283600a614796565b905060008611612642578061261a565b61261a8661051b612653888861209b565b8490612083565b6000600183116126a45760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b6044820152606401610898565b6126bc6126b283600a614796565b61051b8686612083565b949350505050565b6000808385116126d55760006126df565b6126df858561209b565b905060008084116126f157600061261a565b61261a612702620f424060646148c1565b61051b8487612083565b6000600183116127565760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b6044820152606401610898565b6126bc8361051b61276885600a614796565b8790612083565b600080806127936127816064806148c1565b61051b60a087013560c0880135612083565b92506127d16127a76060860135600a614796565b61051b60e0870135816127bf60608a01356008612077565b6127ca90600a614796565b8890612083565b91506001600160601b038311156128365760405162461bcd60e51b8152602060048201526024808201527f73656c6c416d6f756e74203e20747970652875696e74393629206d61782076616044820152636c75652160e01b6064820152608401610898565b6001600160601b038211156128995760405162461bcd60e51b815260206004820152602360248201527f627579416d6f756e74203e20747970652875696e74393629206d61782076616c60448201526275652160e81b6064820152608401610898565b6128cd6128ac6040860160208701613e01565b846128bd6060880160408901613e01565b6001600160a01b03169190612e9c565b6040805160018082528183019092526000916020808301908036833750506040805160018082528183019092529293506000929150602080830190803683375050604080516001808252818301909252929350600092915060208083019080368337019050509050848360008151811061295757634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160601b031690816001600160601b031681525050858260008151811061299957634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160601b031690816001600160601b031681525050600160001b816000815181106129df57634e487b7160e01b600052603260045260246000fd5b6020026020010181815250508660200160208101906129fe9190613e01565b6001600160a01b031663d225269c88608001358585856040518563ffffffff1660e01b8152600401612a339493929190614587565b602060405180830381600087803b158015612a4d57600080fd5b505af1158015612a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8591906142a1565b9350612a9961012088016101008901613e01565b6001600160a01b0316612aaf6020890189613e01565b6040805160808b01358152602081018a90529081018890526001600160a01b0391909116907fa227b5eceb2bd983c0ed9dd34c971be74cd4f386b289d4415602a1fbcf2cb53b9060600160405180910390a35050509193909250565b600080612b23612b1e6020850185613e01565b61350e565b905060008111612b6a5760405162461bcd60e51b8152602060048201526012602482015271139bc81bdd1bdad95b9cc81d1bc81cd95b1b60721b6044820152606401610898565b612c10612b7d6040850160208601613e01565b612b8a6020860186613e01565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b158015612bcb57600080fd5b505afa158015612bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0391906141ff565b6128bd6020870187613e01565b6000612c2e612c24836402540be400612083565b85608001356135f6565b90506012846060013511612c6557612c60612c4e6012606087013561209b565b612c5990600a614796565b829061208f565b612c89565b612c89612c776060860135601261209b565b612c8290600a614796565b8290612083565b90506001600160601b03811115612d085760405162461bcd60e51b815260206004820152603a60248201527f6f7074696f6e5072656d69756d202a206f546f6b656e53656c6c416d6f756e7460448201527f203e20747970652875696e74393629206d61782076616c7565210000000000006064820152608401610898565b6000612d184260a0870135612077565b9050612d2a6040860160208701613e01565b6001600160a01b0316630a4cd6c9612d456020880188613e01565b612d556060890160408a01613e01565b60408051602081018252600080825291516001600160e01b031960e087901b168152612d94949392889283928c928c92600192829182916004016143f8565b602060405180830381600087803b158015612dae57600080fd5b505af1158015612dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de691906141ff565b935033612df96060870160408801613e01565b6001600160a01b0316612e0f6020880188613e01565b6001600160a01b03167f95ad3b10488285d6307fda297f633faaf2a0d713c08ebe5f49c1b9255b01d29e87604051612e4991815260200190565b60405180910390a4505050919050565b60006001600160601b038216612e926bffffffffffffffffffffffff60601b606086901b166001600160c01b031960c088901b166146f9565b6126bc91906146f9565b801580612f255750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015612eeb57600080fd5b505afa158015612eff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2391906141ff565b155b612f905760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610898565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261026a908490613630565b600080612fee83613702565b905082811015610d68576130058162093a806146f9565b611ee2565b60008061301683613731565b9050600061302382613702565b905081811161303257806126bc565b6126bc62093a808261491f565b60008061304b8361375e565b90506000600382111561307f57600682111561307857600982111561307157600c613082565b6009613082565b6006613082565b60035b60ff169050600061309d6130958661377d565b836001613798565b90506130a88161300a565b95945050505050565b6000806130bd8361375e565b9050600060068211156130d157600c613082565b506006600061309d6130958661377d565b6001600160a01b0385166131295760405162461bcd60e51b815260206004820152600e60248201526d216f746f6b656e4164647265737360901b6044820152606401610898565b8354604080516379e13a5360e11b81529051879260ff161515916001600160a01b0384169163f3c274a691600480820192602092909190829003018186803b15801561317457600080fd5b505afa158015613188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131ac9190613f7b565b1515146131eb5760405162461bcd60e51b815260206004820152600d60248201526c0a8f2e0ca40dad2e6dac2e8c6d609b1b6044820152606401610898565b600185015460408051631c56369f60e21b815290516001600160a01b0392831692841691637158da7c916004808301926020929190829003018186803b15801561323457600080fd5b505afa158015613248573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326c9190613e1d565b6001600160a01b0316146132ba5760405162461bcd60e51b815260206004820152601560248201527415dc9bdb99c81d5b99195c9b1e5a5b99d05cdcd95d605a1b6044820152606401610898565b836001600160a01b0316816001600160a01b031663aabaecd66040518163ffffffff1660e01b815260040160206040518083038186803b1580156132fd57600080fd5b505afa158015613311573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133359190613e1d565b6001600160a01b0316146133835760405162461bcd60e51b815260206004820152601560248201527415dc9bdb99c818dbdb1b185d195c985b105cdcd95d605a1b6044820152606401610898565b826001600160a01b0316816001600160a01b03166317d69bc86040518163ffffffff1660e01b815260040160206040518083038186803b1580156133c657600080fd5b505afa1580156133da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fe9190613e1d565b6001600160a01b03161461344a5760405162461bcd60e51b8152602060048201526013602482015272737472696b65417373657420213d205553444360681b6044820152606401610898565b60006134564284612077565b905080826001600160a01b031663ade6e2aa6040518163ffffffff1660e01b815260040160206040518083038186803b15801561349257600080fd5b505afa1580156134a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ca91906141ff565b101561206e5760405162461bcd60e51b8152602060048201526013602482015272457870697279206265666f72652064656c617960681b6044820152606401610898565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a082319060240160206040518083038186803b15801561355257600080fd5b505afa158015613566573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358a91906141ff565b90506001600160601b03811115610d685760405162461bcd60e51b815260206004820152602a60248201527f6f546f6b656e53656c6c416d6f756e74203e20747970652875696e74393629206044820152696d61782076616c75652160b01b6064820152608401610898565b6000670de0b6b3a764000061362661360e85856137b3565b6136216002670de0b6b3a764000061473f565b61381a565b611ee2919061473f565b6000613685826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661386f9092919063ffffffff16565b80519091501561026a57808060200190518101906136a39190613f7b565b61026a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610898565b600061370d8261387e565b61371a90620151806148c1565b61372783620697806146f9565b610d68919061491f565b6000620151806137276137438461377d565b61374c8561375e565b6137579060016146f9565b6001613798565b6000613775613770620151808461473f565b6138b2565b509392505050565b600061378f613770620151808461473f565b50909392505050565b6000620151806137a9858585613a26565b6126bc91906148c1565b60008115806137d7575082826137c981836148c1565b92506137d5908361473f565b145b610d685760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b6044820152606401610898565b60008261382783826146f9565b9150811015610d685760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b6044820152606401610898565b60606126bc8484600085613b63565b60008061388e620151808461473f565b9050600761389d8260036146f9565b6138a79190614966565b611ee29060016146f9565b60008080838162253d8c6138c98362010bd96146b8565b6138d391906146b8565b9050600062023ab16138e683600461483e565b6138f09190614711565b905060046139018262023ab161483e565b61390c9060036146b8565b6139169190614711565b61392090836148e0565b9150600062164b096139338460016146b8565b61393f90610fa061483e565b6139499190614711565b90506004613959826105b561483e565b6139639190614711565b61396d90846148e0565b61397890601f6146b8565b9250600061098f61398a85605061483e565b6139949190614711565b9050600060506139a68361098f61483e565b6139b09190614711565b6139ba90866148e0565b90506139c7600b83614711565b94506139d485600c61483e565b6139df8360026146b8565b6139e991906148e0565b915084836139f86031876148e0565b613a0390606461483e565b613a0d91906146b8565b613a1791906146b8565b9a919950975095505050505050565b60006107b2841015613a3757600080fd5b838383600062253d8c60046064600c613a51600e886148e0565b613a5b9190614711565b613a67886113246146b8565b613a7191906146b8565b613a7b9190614711565b613a8690600361483e565b613a909190614711565b600c80613a9e600e886148e0565b613aa89190614711565b613ab390600c61483e565b613abe6002886148e0565b613ac891906148e0565b613ad49061016f61483e565b613ade9190614711565b6004600c613aed600e896148e0565b613af79190614711565b613b03896112c06146b8565b613b0d91906146b8565b613b19906105b561483e565b613b239190614711565b613b2f617d4b876148e0565b613b3991906146b8565b613b4391906146b8565b613b4d91906148e0565b613b5791906148e0565b98975050505050505050565b606082471015613bc45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610898565b843b613c125760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610898565b600080866001600160a01b03168587604051613c2e91906143a3565b60006040518083038185875af1925050503d8060008114613c6b576040519150601f19603f3d011682016040523d82523d6000602084013e613c70565b606091505b509150915061239e82828660608315613c8a575081611ee2565b825115613c9a5782518084602001fd5b8160405162461bcd60e51b8152600401610898919061455b565b604080516101008101909152806000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001606081525090565b600082601f830112613d25578081fd5b81516020613d3a613d3583614694565b614663565b80838252828201915082860187848660051b8901011115613d59578586fd5b855b85811015613d80578151613d6e816149bc565b84529284019290840190600101613d5b565b5090979650505050505050565b600082601f830112613d9d578081fd5b81516020613dad613d3583614694565b80838252828201915082860187848660051b8901011115613dcc578586fd5b855b85811015613d8057815184529284019290840190600101613dce565b600060c08284031215613dfb578081fd5b50919050565b600060208284031215613e12578081fd5b8135611ee2816149bc565b600060208284031215613e2e578081fd5b8151611ee2816149bc565b60008060408385031215613e4b578081fd5b8235613e56816149bc565b91506020830135613e66816149bc565b809150509250929050565b600080600060608486031215613e85578081fd5b8335613e90816149bc565b92506020840135613ea0816149bc565b91506040840135613eb0816149bc565b809150509250925092565b60008060008060808587031215613ed0578182fd5b8435613edb816149bc565b93506020850135613eeb816149bc565b92506040850135613efb816149bc565b9396929550929360600135925050565b600080600080600080868803610180811215613f25578485fd5b8735613f30816149bc565b96506020880135613f40816149bc565b95506040880135945060e0605f1982011215613f5a578283fd5b50606087019250610140870135915061016087013590509295509295509295565b600060208284031215613f8c578081fd5b81518015158114611ee2578182fd5b600060c08284031215613fac578081fd5b611ee28383613dea565b600080600083850360a0811215613fcb578182fd5b6060811215613fd8578182fd5b508392506060840135613fea816149bc565b91506080840135613eb0816149bc565b60006101208284031215613dfb578081fd5b60008060006101008486031215614021578081fd5b833567ffffffffffffffff811115614037578182fd5b84016101c08187031215614049578182fd5b92506140588560208601613dea565b915060e084013590509250925092565b60008082840360c081121561407b578283fd5b8335925060a0601f1982011215614090578182fd5b506020830190509250929050565b6000602082840312156140af578081fd5b815167ffffffffffffffff808211156140c6578283fd5b9083019060c082860312156140d9578283fd5b6140e161463a565b8251828111156140ef578485fd5b6140fb87828601613d15565b82525060208301518281111561410f578485fd5b61411b87828601613d15565b602083015250604083015182811115614132578485fd5b61413e87828601613d15565b604083015250606083015182811115614155578485fd5b61416187828601613d8d565b606083015250608083015182811115614178578485fd5b61418487828601613d8d565b60808301525060a08301518281111561419b578485fd5b6141a787828601613d8d565b60a08301525095945050505050565b6000602082840312156141c7578081fd5b81356001600160681b0381168114611ee2578182fd5b6000602082840312156141ee578081fd5b813561ffff81168114611ee2578182fd5b600060208284031215614210578081fd5b5051919050565b60008060408385031215614229578182fd5b505080516020909101519092909150565b60006020828403121561424b578081fd5b813563ffffffff81168114611ee2578182fd5b60006020828403121561426f578081fd5b813566ffffffffffffff81168114611ee2578182fd5b600060208284031215614296578081fd5b8135611ee2816149d4565b6000602082840312156142b2578081fd5b8151611ee2816149d4565b6000602082840312156142ce578081fd5b815160ff81168114611ee2578182fd5b6000602082840312156142ef578081fd5b81356001600160601b0381168114611ee2578182fd5b6000815180845260208085019450808401835b8381101561433457815187529582019590820190600101614318565b509495945050505050565b6000815180845260208085019450808401835b838110156143345781516001600160601b031687529582019590820190600101614352565b6000815180845261438f816020860160208601614936565b601f01601f19169290920160200192915050565b600082516143b5818460208701614936565b9190910192915050565b6001600160a01b03968716815294861660208601529290941660408401526060830152608082019290925290151560a082015260c00190565b6001600160a01b038c811682528b81166020830152604082018b9052606082018a90526001600160601b038981166080840152881660a083015260c0820187905260e082018690528415156101008301528316610120820152610160610140820181905260009061446b83820185614377565b9e9d5050505050505050505050505050565b60006020808301818452808551808352604092508286019150828160051b870101848801865b8381101561454d57603f1989840301855281516101008151600b81106144d757634e487b7160e01b8b52602160045260248bfd5b8552818901516001600160a01b039081168a87015288830151811689870152606080840151909116908601526080808301519086015260a0808301519086015260c0808301519086015260e09182015191850181905261453981860183614377565b9689019694505050908601906001016144a3565b509098975050505050505050565b602081526000611ee26020830184614377565b8281526040602082015260006126bc6040830184614305565b84815260a0602082015260006145a060a083018661433f565b82810360408401526145b2818661433f565b905082810360608401526145c68185614305565b83810360809094019390935250506002815261060f60f31b6020820152604001949350505050565b6000808335601e19843603018112614604578283fd5b83018035915067ffffffffffffffff82111561461e578283fd5b60200191503681900382131561463357600080fd5b9250929050565b60405160c0810167ffffffffffffffff8111828210171561465d5761465d6149a6565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561468c5761468c6149a6565b604052919050565b600067ffffffffffffffff8211156146ae576146ae6149a6565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146da576146da61497a565b600160ff1b83900384128116156146f3576146f361497a565b50500190565b6000821982111561470c5761470c61497a565b500190565b60008261472057614720614990565b600160ff1b82146000198414161561473a5761473a61497a565b500590565b60008261474e5761474e614990565b500490565b600181815b8085111561478e5781600019048211156147745761477461497a565b8085161561478157918102915b93841c9390800290614758565b509250929050565b6000611ee283836000826147ac57506001610d68565b816147b957506000610d68565b81600181146147cf57600281146147d9576147f5565b6001915050610d68565b60ff8411156147ea576147ea61497a565b50506001821b610d68565b5060208310610133831016604e8410600b8410161715614818575081810a610d68565b6148228383614753565b80600019048211156148365761483661497a565b029392505050565b60006001600160ff1b03818413828413808216868404861116156148645761486461497a565b600160ff1b848712828116878305891216156148825761488261497a565b85871292508782058712848416161561489d5761489d61497a565b878505871281841616156148b3576148b361497a565b505050929093029392505050565b60008160001904831182151516156148db576148db61497a565b500290565b60008083128015600160ff1b8501841216156148fe576148fe61497a565b6001600160ff1b03840183138116156149195761491961497a565b50500390565b6000828210156149315761493161497a565b500390565b60005b83811015614951578181015183820152602001614939565b83811115614960576000848401525b50505050565b60008261497557614975614990565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146149d157600080fd5b50565b67ffffffffffffffff811681146149d157600080fdfea2646970667358221220b95c20f4c0d0bb193e394828202857e8f6d4228ea2ec08f64b51a549981e37f564736f6c63430008040033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 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.