Contract
0x965e460bF5cb38BadA79fB2293c6304C799D0b1c
7
Contract Overview
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
GammaVault
Compiler Version
v0.8.9+commit.e5eed63a
Contract Source Code (Solidity)
/** *Submitted for verification at Optimistic.Etherscan.io on 2022-08-25 */ // Sources flattened with hardhat v2.9.6 https://hardhat.org // File @rari-capital/solmate/src/auth/[email protected] // -License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) abstract contract Auth { event OwnerUpdated(address indexed user, address indexed newOwner); event AuthorityUpdated(address indexed user, Authority indexed newAuthority); address public owner; Authority public authority; constructor(address _owner, Authority _authority) { owner = _owner; authority = _authority; emit OwnerUpdated(msg.sender, _owner); emit AuthorityUpdated(msg.sender, _authority); } modifier requiresAuth() virtual { require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED"); _; } function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) { Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas. // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be // aware that this makes protected functions uncallable even to the owner if the authority is out of order. return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner; } function setAuthority(Authority newAuthority) public virtual { // We check if the caller is the owner first because we want to ensure they can // always swap out the authority even if it's reverting or using up a lot of gas. require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig)); authority = newAuthority; emit AuthorityUpdated(msg.sender, newAuthority); } function setOwner(address newOwner) public virtual requiresAuth { owner = newOwner; emit OwnerUpdated(msg.sender, newOwner); } } /// @notice A generic interface for a contract which provides authorization data to an Auth instance. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) interface Authority { function canCall( address user, address target, bytes4 functionSig ) external view returns (bool); } // File @rari-capital/solmate/src/tokens/[email protected] // -License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } } // File @rari-capital/solmate/src/utils/[email protected] // -License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // Divide z by the denominator. z := div(z, denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // First, divide z - 1 by the denominator and add 1. // We allow z - 1 to underflow if z is 0, because we multiply the // end result by 0 if z is zero, ensuring we return 0 if z is zero. z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { assembly { // Start off with z at 1. z := 1 // Used below to help find a nearby power of 2. let y := x // Find the lowest power of 2 that is at least sqrt(x). if iszero(lt(y, 0x100000000000000000000000000000000)) { y := shr(128, y) // Like dividing by 2 ** 128. z := shl(64, z) // Like multiplying by 2 ** 64. } if iszero(lt(y, 0x10000000000000000)) { y := shr(64, y) // Like dividing by 2 ** 64. z := shl(32, z) // Like multiplying by 2 ** 32. } if iszero(lt(y, 0x100000000)) { y := shr(32, y) // Like dividing by 2 ** 32. z := shl(16, z) // Like multiplying by 2 ** 16. } if iszero(lt(y, 0x10000)) { y := shr(16, y) // Like dividing by 2 ** 16. z := shl(8, z) // Like multiplying by 2 ** 8. } if iszero(lt(y, 0x100)) { y := shr(8, y) // Like dividing by 2 ** 8. z := shl(4, z) // Like multiplying by 2 ** 4. } if iszero(lt(y, 0x10)) { y := shr(4, y) // Like dividing by 2 ** 4. z := shl(2, z) // Like multiplying by 2 ** 2. } if iszero(lt(y, 0x8)) { // Equivalent to 2 ** z. z := shl(1, z) } // Shifting right by 1 is like dividing by 2. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // Compute a rounded down version of z. let zRoundDown := div(x, z) // If zRoundDown is smaller, use it. if lt(zRoundDown, z) { z := zRoundDown } } } } // File @rari-capital/solmate/src/utils/[email protected] // -License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Gas optimized reentrancy protection for smart contracts. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol) abstract contract ReentrancyGuard { uint256 private locked = 1; modifier nonReentrant() virtual { require(locked == 1, "REENTRANCY"); locked = 2; _; locked = 1; } } // File @rari-capital/solmate/src/utils/[email protected] // -License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } } // File contracts/utils/Pausable.sol // -License-Identifier: MIT pragma solidity 0.8.9; abstract contract Pausable { bool private _paused; bool private _depositsPaused; constructor() { _paused = false; _depositsPaused = false; } function paused() public view virtual returns (bool) { return _paused; } function depositsPaused() public view virtual returns (bool) { return _depositsPaused; } modifier whenNotPaused() { if (paused()) { revert Paused(); } _; } modifier whenPaused() { if (!paused()) { revert NotPaused(); } _; } modifier whenDepositsNotPaused() { if(depositsPaused()) { revert DepositsPaused(); } _; } modifier whenDepositsPaused() { if (!depositsPaused()) { revert DepositsNotPaused(); } _; } function _pause() internal virtual whenNotPaused { _paused = true; _depositsPaused = true; emit SetPaused(msg.sender); } function _pauseDeposits() internal virtual whenDepositsNotPaused { _depositsPaused = true; emit SetDepositsPaused(msg.sender); } function _unpause() internal virtual whenPaused { _paused = false; _depositsPaused = false; emit SetUnpaused(msg.sender); } function _unpauseDeposits() internal virtual whenDepositsPaused { _depositsPaused = false; emit SetDepositsUnpaused(msg.sender); } error Paused(); error DepositsPaused(); error NotPaused(); error DepositsNotPaused(); event SetPaused(address account); event SetDepositsPaused(address account); event SetUnpaused(address account); event SetDepositsUnpaused(address account); } // File contracts/interfaces/IAllowList.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IAllowList { function isAllowed(address) external view returns (bool); } // File contracts/interfaces/IPolynomialVaultToken.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IPolynomialVaultToken { function mint(address _user, uint256 _amt) external; function burn(address _user, uint256 _amt) external; function totalSupply() external view returns (uint256 totalSupply); function balanceOf(address user) external view returns (uint256 balance); } // File contracts/interfaces/IPolynomialVault.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IPolynomialVault {} // File contracts/interfaces/synthetix/IExchangeRates.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IExchangeRates { function rateAndInvalid( bytes32 currencyKey ) external view returns (uint rate, bool isInvalid); } // File contracts/interfaces/synthetix/IFuturesMarket.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IFuturesMarket { function assetPrice() external view returns (uint256 price, bool invalid); function baseAsset() external view returns (bytes32 key); function remainingMargin(address account) external view returns (uint256 marginRemaining, bool invalid); function transferMargin(int256 marginDelta) external; function withdrawAllMargin() external; function modifyPositionWithTracking(int256 sizeDelta, bytes32 trackingCode) external; } // File contracts/interfaces/lyra/IOptionMarket.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IOptionMarket { enum OptionType { LONG_CALL, LONG_PUT, SHORT_CALL_BASE, SHORT_CALL_QUOTE, SHORT_PUT_QUOTE } struct Strike { // strike listing identifier uint id; // strike price uint strikePrice; // volatility component specific to the strike listing (boardIv * skew = vol of strike) uint skew; // total user long call exposure uint longCall; // total user short call (base collateral) exposure uint shortCallBase; // total user short call (quote collateral) exposure uint shortCallQuote; // total user long put exposure uint longPut; // total user short put (quote collateral) exposure uint shortPut; // id of board to which strike belongs uint boardId; } struct OptionBoard { // board identifier uint id; // expiry of all strikes belonging to board uint expiry; // volatility component specific to board (boardIv * skew = vol of strike) uint iv; // admin settable flag blocking all trading on this board bool frozen; // list of all strikes belonging to this board uint[] strikeIds; } function getStrikeAndBoard(uint strikeId) external view returns (Strike memory, OptionBoard memory); function getStrikeAndExpiry(uint strikeId) external view returns (uint strikePrice, uint expiry); function getSettlementParameters(uint strikeId) external view returns ( uint strikePrice, uint priceAtExpiry, uint strikeToBaseReturned ); function addCollateral(uint positionId, uint amountCollateral) external; } // File contracts/interfaces/lyra/IOptionMarketWrapperWithSwaps.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IOptionMarketWrapperWithSwaps { struct ReturnDetails { address market; uint positionId; address owner; uint amount; uint totalCost; uint totalFee; int swapFee; address token; } struct OptionPositionParams { IOptionMarket optionMarket; uint strikeId; // The id of the relevant OptionListing uint positionId; uint iterations; uint setCollateralTo; uint currentCollateral; IOptionMarket.OptionType optionType; // Is the trade a long/short & call/put? uint amount; // The amount the user has requested to close uint minCost; // Min amount for the cost of the trade uint maxCost; // Max amount for the cost of the trade uint inputAmount; // Amount of stable coins the user can use ERC20 inputAsset; // Address of coin user wants to open with } function openPosition(OptionPositionParams memory params) external returns (ReturnDetails memory returnDetails); function closePosition(OptionPositionParams memory params) external returns (ReturnDetails memory returnDetails); } // File contracts/interfaces/lyra/IOptionToken.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IOptionToken { enum PositionState { EMPTY, ACTIVE, CLOSED, LIQUIDATED, SETTLED, MERGED } function getPositionState(uint positionId) external view returns (PositionState); function getApproved(uint256 tokenId) external view returns (address operator); function approve(address to, uint256 tokenId) external; } // File contracts/interfaces/lyra/IOptionGreekCache.sol // -License-Identifier: MIT pragma solidity 0.8.9; interface IOptionGreekCache { struct GreekCacheParameters { // Cap the number of strikes per board to avoid hitting gasLimit constraints uint maxStrikesPerBoard; // How much spot price can move since last update before deposits/withdrawals are blocked uint acceptableSpotPricePercentMove; // How much time has passed since last update before deposits/withdrawals are blocked uint staleUpdateDuration; // Length of the GWAV for the baseline volatility used to fire the vol circuit breaker uint varianceIvGWAVPeriod; // Length of the GWAV for the skew ratios used to fire the vol circuit breaker uint varianceSkewGWAVPeriod; // Length of the GWAV for the baseline used to determine the NAV of the pool uint optionValueIvGWAVPeriod; // Length of the GWAV for the skews used to determine the NAV of the pool uint optionValueSkewGWAVPeriod; // Minimum skew that will be fed into the GWAV calculation // Prevents near 0 values being used to heavily manipulate the GWAV uint gwavSkewFloor; // Maximum skew that will be fed into the GWAV calculation uint gwavSkewCap; // Interest/risk free rate int rateAndCarry; } function getGreekCacheParams() external view returns (GreekCacheParameters memory); function getIvGWAV(uint boardId, uint secondsAgo) external view returns (uint ivGWAV); function getSkewGWAV(uint strikeId, uint secondsAgo) external view returns (uint skewGWAV); } // File contracts/libraries/DecimalMath.sol //-License-Identifier: MIT // //Copyright (c) 2019 Synthetix // //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: // //The above copyright notice and this permission notice shall be included in all //copies or substantial portions of the Software. // //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE //SOFTWARE. pragma solidity ^0.8.9; /** * @title DecimalMath * @author Lyra * @dev Modified synthetix SafeDecimalMath to include internal arithmetic underflow/overflow. * @dev https://docs.synthetix.io/contracts/source/libraries/SafeDecimalMath/ */ library DecimalMath { /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ uint public constant UNIT = 10**uint(decimals); /* The number representing 1.0 for higher fidelity numbers. */ uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals); uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (uint) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (uint) { return PRECISE_UNIT; } /** * @return The result of multiplying x and y, interpreting the operands as fixed-point * decimals. * * @dev A unit factor is divided out after the product of x and y is evaluated, * so that product must be less than 2**256. As this is an integer division, * the internal division always rounds down. This helps save on gas. Rounding * is more expensive on gas. */ function multiplyDecimal(uint x, uint y) internal pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ return (x * y) / UNIT; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of the specified precision unit. * * @dev The operands should be in the form of a the specified unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function _multiplyDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ uint quotientTimesTen = (x * y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a precise unit. * * @dev The operands should be in the precise unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a standard unit. * * @dev The operands should be in the standard unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is a high * precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and UNIT must be less than 2**256. As * this is an integer division, the result is always rounded down. * This helps save on gas. Rounding is more expensive on gas. */ function divideDecimal(uint x, uint y) internal pure returns (uint) { /* Reintroduce the UNIT factor that will be divided out by y. */ return (x * UNIT) / y; } /** * @return The result of safely dividing x and y. The return value is as a rounded * decimal in the precision unit specified in the parameter. * * @dev y is divided after the product of x and the specified precision unit * is evaluated, so the product of x and the specified precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function _divideDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint resultTimesTen = (x * (precisionUnit * 10)) / y; if (resultTimesTen % 10 >= 5) { resultTimesTen += 10; } return resultTimesTen / 10; } /** * @return The result of safely dividing x and y. The return value is as a rounded * standard precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and the standard precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRound(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is as a rounded * high precision decimal. * * @dev y is divided after the product of x and the high precision unit * is evaluated, so the product of x and the high precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(uint i) internal pure returns (uint) { return i * UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR; } /** * @dev Convert a high precision decimal to a standard decimal representation. */ function preciseDecimalToDecimal(uint i) internal pure returns (uint) { uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } } // File contracts/libraries/SignedDecimalMath.sol //-License-Identifier: MIT // //Copyright (c) 2019 Synthetix // //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: // //The above copyright notice and this permission notice shall be included in all //copies or substantial portions of the Software. // //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE //SOFTWARE. pragma solidity ^0.8.9; /** * @title SignedDecimalMath * @author Lyra * @dev Modified synthetix SafeSignedDecimalMath to include internal arithmetic underflow/overflow. * @dev https://docs.synthetix.io/contracts/source/libraries/safedecimalmath */ library SignedDecimalMath { /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ int public constant UNIT = int(10**uint(decimals)); /* The number representing 1.0 for higher fidelity numbers. */ int public constant PRECISE_UNIT = int(10**uint(highPrecisionDecimals)); int private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = int(10**uint(highPrecisionDecimals - decimals)); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (int) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (int) { return PRECISE_UNIT; } /** * @dev Rounds an input with an extra zero of precision, returning the result without the extra zero. * Half increments round away from zero; positive numbers at a half increment are rounded up, * while negative such numbers are rounded down. This behaviour is designed to be consistent with the * unsigned version of this library (SafeDecimalMath). */ function _roundDividingByTen(int valueTimesTen) private pure returns (int) { int increment; if (valueTimesTen % 10 >= 5) { increment = 10; } else if (valueTimesTen % 10 <= -5) { increment = -10; } return (valueTimesTen + increment) / 10; } /** * @return The result of multiplying x and y, interpreting the operands as fixed-point * decimals. * * @dev A unit factor is divided out after the product of x and y is evaluated, * so that product must be less than 2**256. As this is an integer division, * the internal division always rounds down. This helps save on gas. Rounding * is more expensive on gas. */ function multiplyDecimal(int x, int y) internal pure returns (int) { /* Divide by UNIT to remove the extra factor introduced by the product. */ return (x * y) / UNIT; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of the specified precision unit. * * @dev The operands should be in the form of a the specified unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function _multiplyDecimalRound( int x, int y, int precisionUnit ) private pure returns (int) { /* Divide by UNIT to remove the extra factor introduced by the product. */ int quotientTimesTen = (x * y) / (precisionUnit / 10); return _roundDividingByTen(quotientTimesTen); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a precise unit. * * @dev The operands should be in the precise unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRoundPrecise(int x, int y) internal pure returns (int) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a standard unit. * * @dev The operands should be in the standard unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRound(int x, int y) internal pure returns (int) { return _multiplyDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is a high * precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and UNIT must be less than 2**256. As * this is an integer division, the result is always rounded down. * This helps save on gas. Rounding is more expensive on gas. */ function divideDecimal(int x, int y) internal pure returns (int) { /* Reintroduce the UNIT factor that will be divided out by y. */ return (x * UNIT) / y; } /** * @return The result of safely dividing x and y. The return value is as a rounded * decimal in the precision unit specified in the parameter. * * @dev y is divided after the product of x and the specified precision unit * is evaluated, so the product of x and the specified precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function _divideDecimalRound( int x, int y, int precisionUnit ) private pure returns (int) { int resultTimesTen = (x * (precisionUnit * 10)) / y; return _roundDividingByTen(resultTimesTen); } /** * @return The result of safely dividing x and y. The return value is as a rounded * standard precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and the standard precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRound(int x, int y) internal pure returns (int) { return _divideDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is as a rounded * high precision decimal. * * @dev y is divided after the product of x and the high precision unit * is evaluated, so the product of x and the high precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRoundPrecise(int x, int y) internal pure returns (int) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(int i) internal pure returns (int) { return i * UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR; } /** * @dev Convert a high precision decimal to a standard decimal representation. */ function preciseDecimalToDecimal(int i) internal pure returns (int) { int quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); return _roundDividingByTen(quotientTimesTen); } } // File contracts/libraries/HigherMath.sol // -License-Identifier: UNLICENSED pragma solidity 0.8.9; // Slightly modified version of: // - https://github.com/recmo/experiment-solexp/blob/605738f3ed72d6c67a414e992be58262fbc9bb80/src/FixedPointMathLib.sol library HigherMath { /// @dev Computes ln(x) for a 1e27 fixed point. Loses 9 last significant digits of precision. function lnPrecise(int x) internal pure returns (int r) { return ln(x / 1e9) * 1e9; } /// @dev Computes e ^ x for a 1e27 fixed point. Loses 9 last significant digits of precision. function expPrecise(int x) internal pure returns (uint r) { return exp(x / 1e9) * 1e9; } // Computes ln(x) in 1e18 fixed point. // Reverts if x is negative or zero. // Consumes 670 gas. function ln(int x) internal pure returns (int r) { unchecked { if (x < 1) { if (x < 0) revert LnNegativeUndefined(); revert Overflow(); } // We want to convert x from 10**18 fixed point to 2**96 fixed point. // We do this by multiplying by 2**96 / 10**18. // But since ln(x * C) = ln(x) + ln(C), we can simply do nothing here // and add ln(2**96 / 10**18) at the end. // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) // Note: inlining ilog2 saves 8 gas. int k = int(ilog2(uint(x))) - 96; x <<= uint(159 - k); x = int(uint(x) >> 159); // Evaluate using a (8, 8)-term rational approximation // p is made monic, we will multiply by a scale factor later int p = x + 3273285459638523848632254066296; p = ((p * x) >> 96) + 24828157081833163892658089445524; p = ((p * x) >> 96) + 43456485725739037958740375743393; p = ((p * x) >> 96) - 11111509109440967052023855526967; p = ((p * x) >> 96) - 45023709667254063763336534515857; p = ((p * x) >> 96) - 14706773417378608786704636184526; p = p * x - (795164235651350426258249787498 << 96); //emit log_named_int("p", p); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // q is monic by convention int q = x + 5573035233440673466300451813936; q = ((q * x) >> 96) + 71694874799317883764090561454958; q = ((q * x) >> 96) + 283447036172924575727196451306956; q = ((q * x) >> 96) + 401686690394027663651624208769553; q = ((q * x) >> 96) + 204048457590392012362485061816622; q = ((q * x) >> 96) + 31853899698501571402653359427138; q = ((q * x) >> 96) + 909429971244387300277376558375; assembly { // Div in assembly because solidity adds a zero check despite the `unchecked`. // The q polynomial is known not to have zeros in the domain. (All roots are complex) // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r is in the range (0, 0.125) * 2**96 // Finalization, we need to // * multiply by the scale factor s = 5.549… // * add ln(2**96 / 10**18) // * add k * ln(2) // * multiply by 10**18 / 2**96 = 5**18 >> 78 // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 r *= 1677202110996718588342820967067443963516166; // add ln(2) * k * 5e18 * 2**192 r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; // add ln(2**96 / 10**18) * 5e18 * 2**192 r += 600920179829731861736702779321621459595472258049074101567377883020018308; // base conversion: mul 2**18 / 2**192 r >>= 174; } } // Integer log2 // @returns floor(log2(x)) if x is nonzero, otherwise 0. This is the same // as the location of the highest set bit. // Consumes 232 gas. This could have been an 3 gas EVM opcode though. function ilog2(uint x) internal pure returns (uint r) { assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) r := or(r, shl(2, lt(0xf, shr(r, x)))) r := or(r, shl(1, lt(0x3, shr(r, x)))) r := or(r, lt(0x1, shr(r, x))) } } // Computes e^x in 1e18 fixed point. function exp(int x) internal pure returns (uint r) { unchecked { // Input x is in fixed point format, with scale factor 1/1e18. // When the result is < 0.5 we return zero. This happens when // x <= floor(log(0.5e18) * 1e18) ~ -42e18 if (x <= -42139678854452767551) { return 0; } // When the result is > (2**255 - 1) / 1e18 we can not represent it // as an int256. This happens when x >= floor(log((2**255 -1) / 1e18) * 1e18) ~ 135. if (x >= 135305999368893231589) revert ExpOverflow(); // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5**18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers of two // such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96; x = x - k * 54916777467707473351141471128; // k is in the range [-61, 195]. // Evaluate using a (6, 7)-term rational approximation // p is made monic, we will multiply by a scale factor later int p = x + 2772001395605857295435445496992; p = ((p * x) >> 96) + 44335888930127919016834873520032; p = ((p * x) >> 96) + 398888492587501845352592340339721; p = ((p * x) >> 96) + 1993839819670624470859228494792842; p = p * x + (4385272521454847904632057985693276 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // Evaluate using using Knuth's scheme from p. 491. int z = x + 750530180792738023273180420736; z = ((z * x) >> 96) + 32788456221302202726307501949080; int w = x - 2218138959503481824038194425854; w = ((w * z) >> 96) + 892943633302991980437332862907700; int q = z + w - 78174809823045304726920794422040; q = ((q * w) >> 96) + 4203224763890128580604056984195872; assembly { // Div in assembly because solidity adds a zero check despite the `unchecked`. // The q polynomial is known not to have zeros in the domain. (All roots are complex) // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r should be in the range (0.09, 0.25) * 2**96. // We now need to multiply r by // * the scale factor s = ~6.031367120..., // * the 2**k factor from the range reduction, and // * the 1e18 / 2**96 factor for base converison. // We do all of this at once, with an intermediate result in 2**213 basis // so the final right shift is always by a positive amount. r = (uint(r) * 3822833074963236453042738258902158003155416615667) >> uint(195 - k); } } error Overflow(); error ExpOverflow(); error LnNegativeUndefined(); } // File contracts/libraries/BlackScholes.sol // -License-Identifier: ISC //ISC License // //Copyright (c) 2021 Lyra Finance // //Permission to use, copy, modify, and/or distribute this software for any //purpose with or without fee is hereby granted, provided that the above //copyright notice and this permission notice appear in all copies. // //THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH //REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY //AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, //INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM //LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR //OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR //PERFORMANCE OF THIS SOFTWARE. pragma solidity 0.8.9; /** * @title BlackScholes * @author Lyra * @dev Contract to compute the black scholes price of options. Where the unit is unspecified, it should be treated as a * PRECISE_DECIMAL, which has 1e27 units of precision. The default decimal matches the ethereum standard of 1e18 units * of precision. */ library BlackScholesLib { using DecimalMath for uint; using SignedDecimalMath for int; struct PricesDeltaStdVega { uint callPrice; uint putPrice; int callDelta; int putDelta; uint vega; uint stdVega; } /** * @param timeToExpirySec Number of seconds to the expiry of the option * @param volatilityDecimal Implied volatility over the period til expiry as a percentage * @param spotDecimal The current price of the base asset * @param strikePriceDecimal The strikePrice price of the option * @param rateDecimal The percentage risk free rate + carry cost */ struct BlackScholesInputs { uint timeToExpirySec; uint volatilityDecimal; uint spotDecimal; uint strikePriceDecimal; int rateDecimal; } uint private constant SECONDS_PER_YEAR = 31536000; /// @dev Internally this library uses 27 decimals of precision uint private constant PRECISE_UNIT = 1e27; uint private constant SQRT_TWOPI = 2506628274631000502415765285; /// @dev Below this value, return 0 int private constant MIN_CDF_STD_DIST_INPUT = (int(PRECISE_UNIT) * -45) / 10; // -4.5 /// @dev Above this value, return 1 int private constant MAX_CDF_STD_DIST_INPUT = int(PRECISE_UNIT) * 10; /// @dev Value to use to avoid any division by 0 or values near 0 uint private constant MIN_T_ANNUALISED = PRECISE_UNIT / SECONDS_PER_YEAR; // 1 second uint private constant MIN_VOLATILITY = PRECISE_UNIT / 10000; // 0.001% uint private constant VEGA_STANDARDISATION_MIN_DAYS = 7 days; /// @dev Magic numbers for normal CDF uint private constant SPLIT = 7071067811865470000000000000; uint private constant N0 = 220206867912376000000000000000; uint private constant N1 = 221213596169931000000000000000; uint private constant N2 = 112079291497871000000000000000; uint private constant N3 = 33912866078383000000000000000; uint private constant N4 = 6373962203531650000000000000; uint private constant N5 = 700383064443688000000000000; uint private constant N6 = 35262496599891100000000000; uint private constant M0 = 440413735824752000000000000000; uint private constant M1 = 793826512519948000000000000000; uint private constant M2 = 637333633378831000000000000000; uint private constant M3 = 296564248779674000000000000000; uint private constant M4 = 86780732202946100000000000000; uint private constant M5 = 16064177579207000000000000000; uint private constant M6 = 1755667163182640000000000000; uint private constant M7 = 88388347648318400000000000; ///////////////////////////////////// // Option Pricing public functions // ///////////////////////////////////// /** * @dev Returns call and put prices for options with given parameters. */ function optionPrices(BlackScholesInputs memory bsInput) public pure returns (uint call, uint put) { uint tAnnualised = _annualise(bsInput.timeToExpirySec); uint spotPrecise = bsInput.spotDecimal.decimalToPreciseDecimal(); uint strikePricePrecise = bsInput.strikePriceDecimal.decimalToPreciseDecimal(); int ratePrecise = bsInput.rateDecimal.decimalToPreciseDecimal(); (int d1, int d2) = _d1d2( tAnnualised, bsInput.volatilityDecimal.decimalToPreciseDecimal(), spotPrecise, strikePricePrecise, ratePrecise ); (call, put) = _optionPrices(tAnnualised, spotPrecise, strikePricePrecise, ratePrecise, d1, d2); return (call.preciseDecimalToDecimal(), put.preciseDecimalToDecimal()); } /** * @dev Returns call/put prices and delta/stdVega for options with given parameters. */ function pricesDeltaStdVega(BlackScholesInputs memory bsInput) public pure returns (PricesDeltaStdVega memory) { uint tAnnualised = _annualise(bsInput.timeToExpirySec); uint spotPrecise = bsInput.spotDecimal.decimalToPreciseDecimal(); (int d1, int d2) = _d1d2( tAnnualised, bsInput.volatilityDecimal.decimalToPreciseDecimal(), spotPrecise, bsInput.strikePriceDecimal.decimalToPreciseDecimal(), bsInput.rateDecimal.decimalToPreciseDecimal() ); (uint callPrice, uint putPrice) = _optionPrices( tAnnualised, spotPrecise, bsInput.strikePriceDecimal.decimalToPreciseDecimal(), bsInput.rateDecimal.decimalToPreciseDecimal(), d1, d2 ); (uint vegaPrecise, uint stdVegaPrecise) = _standardVega(d1, spotPrecise, bsInput.timeToExpirySec); (int callDelta, int putDelta) = _delta(d1); return PricesDeltaStdVega( callPrice.preciseDecimalToDecimal(), putPrice.preciseDecimalToDecimal(), callDelta.preciseDecimalToDecimal(), putDelta.preciseDecimalToDecimal(), vegaPrecise.preciseDecimalToDecimal(), stdVegaPrecise.preciseDecimalToDecimal() ); } /** * @dev Returns call delta given parameters. */ function delta(BlackScholesInputs memory bsInput) public pure returns (int callDeltaDecimal, int putDeltaDecimal) { uint tAnnualised = _annualise(bsInput.timeToExpirySec); uint spotPrecise = bsInput.spotDecimal.decimalToPreciseDecimal(); (int d1, ) = _d1d2( tAnnualised, bsInput.volatilityDecimal.decimalToPreciseDecimal(), spotPrecise, bsInput.strikePriceDecimal.decimalToPreciseDecimal(), bsInput.rateDecimal.decimalToPreciseDecimal() ); (int callDelta, int putDelta) = _delta(d1); return (callDelta.preciseDecimalToDecimal(), putDelta.preciseDecimalToDecimal()); } /** * @dev Returns non-normalized vega given parameters. Quoted in cents. */ function vega(BlackScholesInputs memory bsInput) public pure returns (uint vegaDecimal) { uint tAnnualised = _annualise(bsInput.timeToExpirySec); uint spotPrecise = bsInput.spotDecimal.decimalToPreciseDecimal(); (int d1, ) = _d1d2( tAnnualised, bsInput.volatilityDecimal.decimalToPreciseDecimal(), spotPrecise, bsInput.strikePriceDecimal.decimalToPreciseDecimal(), bsInput.rateDecimal.decimalToPreciseDecimal() ); return _vega(tAnnualised, spotPrecise, d1).preciseDecimalToDecimal(); } ////////////////////// // Computing Greeks // ////////////////////// /** * @dev Returns internal coefficients of the Black-Scholes call price formula, d1 and d2. * @param tAnnualised Number of years to expiry * @param volatility Implied volatility over the period til expiry as a percentage * @param spot The current price of the base asset * @param strikePrice The strikePrice price of the option * @param rate The percentage risk free rate + carry cost */ function _d1d2( uint tAnnualised, uint volatility, uint spot, uint strikePrice, int rate ) internal pure returns (int d1, int d2) { // Set minimum values for tAnnualised and volatility to not break computation in extreme scenarios // These values will result in option prices reflecting only the difference in stock/strikePrice, which is expected. // This should be caught before calling this function, however the function shouldn't break if the values are 0. tAnnualised = tAnnualised < MIN_T_ANNUALISED ? MIN_T_ANNUALISED : tAnnualised; volatility = volatility < MIN_VOLATILITY ? MIN_VOLATILITY : volatility; int vtSqrt = int(volatility.multiplyDecimalRoundPrecise(_sqrtPrecise(tAnnualised))); int log = HigherMath.lnPrecise(int(spot.divideDecimalRoundPrecise(strikePrice))); int v2t = (int(volatility.multiplyDecimalRoundPrecise(volatility) / 2) + rate).multiplyDecimalRoundPrecise( int(tAnnualised) ); d1 = (log + v2t).divideDecimalRoundPrecise(vtSqrt); d2 = d1 - vtSqrt; } /** * @dev Internal coefficients of the Black-Scholes call price formula. * @param tAnnualised Number of years to expiry * @param spot The current price of the base asset * @param strikePrice The strikePrice price of the option * @param rate The percentage risk free rate + carry cost * @param d1 Internal coefficient of Black-Scholes * @param d2 Internal coefficient of Black-Scholes */ function _optionPrices( uint tAnnualised, uint spot, uint strikePrice, int rate, int d1, int d2 ) internal pure returns (uint call, uint put) { uint strikePricePV = strikePrice.multiplyDecimalRoundPrecise( HigherMath.expPrecise(int(-rate.multiplyDecimalRoundPrecise(int(tAnnualised)))) ); uint spotNd1 = spot.multiplyDecimalRoundPrecise(_stdNormalCDF(d1)); uint strikePriceNd2 = strikePricePV.multiplyDecimalRoundPrecise(_stdNormalCDF(d2)); // We clamp to zero if the minuend is less than the subtrahend // In some scenarios it may be better to compute put price instead and derive call from it depending on which way // around is more precise. call = strikePriceNd2 <= spotNd1 ? spotNd1 - strikePriceNd2 : 0; put = call + strikePricePV; put = spot <= put ? put - spot : 0; } /* * Greeks */ /** * @dev Returns the option's delta value * @param d1 Internal coefficient of Black-Scholes */ function _delta(int d1) internal pure returns (int callDelta, int putDelta) { callDelta = int(_stdNormalCDF(d1)); putDelta = callDelta - int(PRECISE_UNIT); } /** * @dev Returns the option's vega value based on d1. Quoted in cents. * * @param d1 Internal coefficient of Black-Scholes * @param tAnnualised Number of years to expiry * @param spot The current price of the base asset */ function _vega( uint tAnnualised, uint spot, int d1 ) internal pure returns (uint) { return _sqrtPrecise(tAnnualised).multiplyDecimalRoundPrecise(_stdNormal(d1).multiplyDecimalRoundPrecise(spot)); } /** * @dev Returns the option's vega value with expiry modified to be at least VEGA_STANDARDISATION_MIN_DAYS * @param d1 Internal coefficient of Black-Scholes * @param spot The current price of the base asset * @param timeToExpirySec Number of seconds to expiry */ function _standardVega( int d1, uint spot, uint timeToExpirySec ) internal pure returns (uint, uint) { uint tAnnualised = _annualise(timeToExpirySec); uint normalisationFactor = _getVegaNormalisationFactorPrecise(timeToExpirySec); uint vegaPrecise = _vega(tAnnualised, spot, d1); return (vegaPrecise, vegaPrecise.multiplyDecimalRoundPrecise(normalisationFactor)); } function _getVegaNormalisationFactorPrecise(uint timeToExpirySec) internal pure returns (uint) { timeToExpirySec = timeToExpirySec < VEGA_STANDARDISATION_MIN_DAYS ? VEGA_STANDARDISATION_MIN_DAYS : timeToExpirySec; uint daysToExpiry = timeToExpirySec / 1 days; uint thirty = 30 * PRECISE_UNIT; return _sqrtPrecise(thirty / daysToExpiry) / 100; } ///////////////////// // Math Operations // ///////////////////// /** * @dev Compute the absolute value of `val`. * * @param val The number to absolute value. */ function _abs(int val) internal pure returns (uint) { return uint(val < 0 ? -val : val); } /// @notice Calculates the square root of x, rounding down (borrowed from https://github.com/paulrberg/prb-math) /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function _sqrt(uint x) internal pure returns (uint result) { if (x == 0) { return 0; } // Calculate the square root of the perfect square of a power of two that is the closest to x. uint xAux = uint(x); result = 1; if (xAux >= 0x100000000000000000000000000000000) { xAux >>= 128; result <<= 64; } if (xAux >= 0x10000000000000000) { xAux >>= 64; result <<= 32; } if (xAux >= 0x100000000) { xAux >>= 32; result <<= 16; } if (xAux >= 0x10000) { xAux >>= 16; result <<= 8; } if (xAux >= 0x100) { xAux >>= 8; result <<= 4; } if (xAux >= 0x10) { xAux >>= 4; result <<= 2; } if (xAux >= 0x8) { result <<= 1; } // The operations can never overflow because the result is max 2^127 when it enters this block. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Seven iterations should be enough uint roundedDownResult = x / result; return result >= roundedDownResult ? roundedDownResult : result; } } /** * @dev Returns the square root of the value using Newton's method. */ function _sqrtPrecise(uint x) internal pure returns (uint) { // Add in an extra unit factor for the square root to gobble; // otherwise, sqrt(x * UNIT) = sqrt(x) * sqrt(UNIT) return _sqrt(x * PRECISE_UNIT); } /** * @dev The standard normal distribution of the value. */ function _stdNormal(int x) internal pure returns (uint) { return HigherMath.expPrecise(int(-x.multiplyDecimalRoundPrecise(x / 2))).divideDecimalRoundPrecise(SQRT_TWOPI); } /** * @dev The standard normal cumulative distribution of the value. * borrowed from a C++ implementation https://stackoverflow.com/a/23119456 */ function _stdNormalCDF(int x) public pure returns (uint) { uint z = _abs(x); int c; if (z <= 37 * PRECISE_UNIT) { uint e = HigherMath.expPrecise(-int(z.multiplyDecimalRoundPrecise(z / 2))); if (z < SPLIT) { c = int( (_stdNormalCDFNumerator(z).divideDecimalRoundPrecise(_stdNormalCDFDenom(z)).multiplyDecimalRoundPrecise(e)) ); } else { uint f = (z + PRECISE_UNIT.divideDecimalRoundPrecise( z + (2 * PRECISE_UNIT).divideDecimalRoundPrecise( z + (3 * PRECISE_UNIT).divideDecimalRoundPrecise( z + (4 * PRECISE_UNIT).divideDecimalRoundPrecise(z + ((PRECISE_UNIT * 13) / 20)) ) ) )); c = int(e.divideDecimalRoundPrecise(f.multiplyDecimalRoundPrecise(SQRT_TWOPI))); } } return uint((x <= 0 ? c : (int(PRECISE_UNIT) - c))); } /** * @dev Helper for _stdNormalCDF */ function _stdNormalCDFNumerator(uint z) internal pure returns (uint) { uint numeratorInner = ((((((N6 * z) / PRECISE_UNIT + N5) * z) / PRECISE_UNIT + N4) * z) / PRECISE_UNIT + N3); return (((((numeratorInner * z) / PRECISE_UNIT + N2) * z) / PRECISE_UNIT + N1) * z) / PRECISE_UNIT + N0; } /** * @dev Helper for _stdNormalCDF */ function _stdNormalCDFDenom(uint z) internal pure returns (uint) { uint denominatorInner = ((((((M7 * z) / PRECISE_UNIT + M6) * z) / PRECISE_UNIT + M5) * z) / PRECISE_UNIT + M4); return (((((((denominatorInner * z) / PRECISE_UNIT + M3) * z) / PRECISE_UNIT + M2) * z) / PRECISE_UNIT + M1) * z) / PRECISE_UNIT + M0; } /** * @dev Converts an integer number of seconds to a fractional number of years. */ function _annualise(uint secs) internal pure returns (uint yearFraction) { return secs.divideDecimalRoundPrecise(SECONDS_PER_YEAR); } } // File contracts/core/GammaVault.sol // SPDX-License-Identifier: MIT pragma solidity 0.8.9; contract GammaVault is IPolynomialVault, Auth, ReentrancyGuard, Pausable { /// ----------------------------------------------------------------------- /// Library usage /// ----------------------------------------------------------------------- using FixedPointMathLib for uint256; using SafeTransferLib for ERC20; /// ----------------------------------------------------------------------- /// Data Structures /// ----------------------------------------------------------------------- struct PositionData { uint256 strikeId; uint256 positionId; uint256 optionAmount; uint256 premiumPaid; uint256 shortAmount; uint256 totalMargin; } struct QueuedDeposit { uint256 id; address user; uint256 depositedAmount; uint256 mintedTokens; uint256 requestedTime; } struct QueuedWithdraw { uint256 id; address user; uint256 withdrawnTokens; uint256 returnedAmount; uint256 requestedTime; } /// ----------------------------------------------------------------------- /// Constants /// ----------------------------------------------------------------------- IOptionMarket.OptionType private constant OPTION_TYPE = IOptionMarket.OptionType.LONG_CALL; /// ----------------------------------------------------------------------- /// Immutable parameters /// ----------------------------------------------------------------------- /// @notice Human Readable Name of the Vault bytes32 public immutable name; /// @notice Synthetix Synth key of the underlying token bytes32 public immutable UNDERLYING_SYNTH_KEY; /// @notice sUSD ERC20 public immutable SUSD; /// @notice Corresponding vault token IPolynomialVaultToken public immutable VAULT_TOKEN; /// @notice Lyra Option Market IOptionMarket public immutable OPTION_MARKET; /// @notice Synthetix Futures Market IFuturesMarket public immutable FUTURES_MARKET; /// @notice Lyra Option Market Wrapper IOptionMarketWrapperWithSwaps public immutable OPTION_MARKET_WRAPPER; /// @notice Lyra Option Token IOptionToken public immutable OPTION_TOKEN; /// @notice Lyra Options Greek Cache IOptionGreekCache public immutable GREEKS; /// @notice Synthetix Exchange Rates IExchangeRates public immutable RATES; /// ----------------------------------------------------------------------- /// Storage variables /// ----------------------------------------------------------------------- /// @notice Minimum deposit amount uint256 public minDepositAmount; /// @notice Maximum deposit amount uint256 public maxDepositAmount; /// @notice Minimum deposit delay uint256 public minDepositDelay; /// @notice Minimum withdrawal delay uint256 public minWithdrawDelay; /// @notice GWAV Length uint256 public gwavLength; /// @notice Leverage used for Futures positions uint256 public leverage; /// @notice Fee Receipient address public feeReceipient; /// @notice Performance Fee uint256 public performanceFee; /// @notice Withdrawal Fee uint256 public withdrawalFee; /// @notice Synthetix Tracking Code bytes32 public synthetixTrackingCode; /// @notice Total queued deposits uint256 public totalQueuedDeposits; /// @notice Total queued withdrawals uint256 public totalQueuedWithdrawals; /// @notice Next deposit queue item that needs to be processed uint256 public queuedDepositHead = 1; /// @notice Next deposit queue ID that needs to be processed uint256 public nextQueuedDepositId = 1; /// @notice Next withdrawal queue item that needs to be processed uint256 public queuedWithdrawalHead = 1; /// @notice Next withdrawal queue ID that needs to be processed uint256 public nextQueuedWithdrawalId = 1; /// @notice Total funds uint256 public totalFunds; /// @notice Used funds uint256 public usedFunds; /// @notice Boolean flag to stop from opening new position if closing has started bool public hasClosingStarted; /// @notice Position Data PositionData public positionData; /// @notice Allow List IAllowList public allowList; /// @notice Deposit Queue mapping (uint256 => QueuedDeposit) public depositQueue; /// @notice Withdrawal Queue mapping (uint256 => QueuedWithdraw) public withdrawalQueue; constructor( ERC20 _susd, IPolynomialVaultToken _vaultToken, IOptionMarket _optionMarket, IFuturesMarket _futuresMarket, IOptionMarketWrapperWithSwaps _optionMarketWrapper, IOptionToken _optionToken, IOptionGreekCache _greeks, IExchangeRates _rates, bytes32 _underlyingKey, bytes32 _name ) Auth(msg.sender, Authority(address(0x0))) { VAULT_TOKEN = _vaultToken; OPTION_MARKET = _optionMarket; FUTURES_MARKET = _futuresMarket; OPTION_MARKET_WRAPPER = _optionMarketWrapper; OPTION_TOKEN = _optionToken; RATES = _rates; GREEKS = _greeks; UNDERLYING_SYNTH_KEY = _underlyingKey; name = _name; SUSD = _susd; } /// ----------------------------------------------------------------------- /// User actions /// ----------------------------------------------------------------------- /// @notice Initiate deposit to the vault /// @notice If there are no active positions, deposits are processed immediately /// @notice Otherwise it is added to the deposit queue /// @param user Address of the user to receive the VAULT_TOKENs upon processing /// @param amount Amount of sUSD being depositted function initiateDeposit(address user, uint256 amount) external nonReentrant whenDepositsNotPaused { if (user == address(0x0)) { revert ExpectedNonZero(); } if (amount < minDepositAmount) { revert MinimumDepositRequired(minDepositAmount, amount); } // Instant processing if (positionData.optionAmount == 0) { uint256 tokenPrice = getTokenPrice(); uint256 tokensToMint = amount.divWadDown(tokenPrice); VAULT_TOKEN.mint(user, tokensToMint); totalFunds += amount; emit ProcessDeposit(0, user, amount, tokensToMint, block.timestamp); } else { // Queueing the deposit request QueuedDeposit storage newDeposit = depositQueue[nextQueuedDepositId]; newDeposit.id = nextQueuedDepositId++; newDeposit.user = user; newDeposit.depositedAmount = amount; newDeposit.requestedTime = block.timestamp; totalQueuedDeposits += amount; emit InitiateDeposit(newDeposit.id, msg.sender, user, amount); } SUSD.safeTransferFrom(msg.sender, address(this), amount); } /// @notice Initiate withdrawal from the vault /// @notice If there are no active positions, withdrawals are processed instantly /// @notice Otherwise the request is added to the withdrawal queue /// @param user Address of the user to receive the sUSD upon processing /// @param tokens Amounts of VAULT_TOKENs being requested to burn / withdraw function initiateWithdrawal(address user, uint256 tokens) external nonReentrant { if (user == address(0x0)) { revert ExpectedNonZero(); } // Instant processing if (positionData.optionAmount == 0) { uint256 tokenPrice = getTokenPrice(); uint256 susdToReturn = tokens.mulWadDown(tokenPrice); SUSD.safeTransfer(user, susdToReturn); totalFunds -= susdToReturn; emit ProcessWithdrawal(0, user, tokens, susdToReturn, block.timestamp); } else { // Queueing the withdrawal request QueuedWithdraw storage newWithdraw = withdrawalQueue[nextQueuedWithdrawalId]; newWithdraw.id = nextQueuedWithdrawalId++; newWithdraw.user = user; newWithdraw.withdrawnTokens = tokens; newWithdraw.requestedTime = block.timestamp; totalQueuedWithdrawals += tokens; emit InitiateWithdrawal(newWithdraw.id, msg.sender, user, tokens); } VAULT_TOKEN.burn(msg.sender, tokens); } /// @notice Process queued deposit requests /// @param idCount Number of deposit queue items to process function processDepositQueue(uint256 idCount) external nonReentrant { uint256 tokenPrice = getTokenPrice(); for (uint256 i = 0; i < idCount; i++) { QueuedDeposit storage current = depositQueue[queuedDepositHead]; if (current.requestedTime == 0 || block.timestamp < current.requestedTime + minDepositDelay) { return; } uint256 tokensToMint = current.depositedAmount.divWadDown(tokenPrice); current.mintedTokens = tokensToMint; totalQueuedDeposits -= current.depositedAmount; totalFunds += current.depositedAmount; VAULT_TOKEN.mint(current.user, tokensToMint); emit ProcessDeposit(current.id, current.user, current.depositedAmount, tokensToMint, current.requestedTime); current.depositedAmount = 0; queuedDepositHead++; } } /// @notice Process queued withdrawal requests /// @param idCount Number of withdrawal queue items to process function processWithdrawalQueue(uint256 idCount) external nonReentrant { for (uint256 i = 0; i < idCount; i++) { uint256 tokenPrice = getTokenPrice(); QueuedWithdraw storage current = withdrawalQueue[queuedWithdrawalHead]; if (current.requestedTime == 0 || block.timestamp < current.requestedTime + minWithdrawDelay) { return; } uint256 availableFunds = totalFunds - usedFunds; if (availableFunds == 0) { return; } uint256 susdToReturn = current.withdrawnTokens.mulWadDown(tokenPrice); // Partial withdrawals if not enough available funds in the vault // Queue head is not increased if (susdToReturn > availableFunds) { current.returnedAmount = availableFunds; uint256 tokensBurned = availableFunds.divWadUp(tokenPrice); totalQueuedWithdrawals -= tokensBurned; current.withdrawnTokens -= tokensBurned; totalFunds -= availableFunds; if (withdrawalFee > 0) { uint256 withdrawFees = availableFunds.mulWadDown(withdrawalFee); SUSD.safeTransfer(feeReceipient, withdrawFees); availableFunds -= withdrawFees; } SUSD.safeTransfer(current.user, availableFunds); emit ProcessWithdrawalPartially( current.id, current.user, tokensBurned, availableFunds, current.requestedTime ); return; } else { current.returnedAmount = susdToReturn; totalQueuedWithdrawals -= current.withdrawnTokens; current.withdrawnTokens = 0; totalFunds -= susdToReturn; if (withdrawalFee > 0) { uint256 withdrawFees = susdToReturn.mulWadDown(withdrawalFee); SUSD.safeTransfer(feeReceipient, withdrawFees); susdToReturn -= withdrawFees; } SUSD.safeTransfer(current.user, susdToReturn); emit ProcessWithdrawal( current.id, current.user, current.withdrawnTokens, susdToReturn, current.requestedTime ); } queuedWithdrawalHead++; } } /// ----------------------------------------------------------------------- /// View methods /// ----------------------------------------------------------------------- /// @notice Get VAULT_TOKEN price /// @notice Calculated using the Black-Scholes and margin value of the positions function getTokenPrice() public view returns (uint256) { if (totalFunds == 0) { return 1e18; } uint256 totalSupply = getTotalSupply(); if (positionData.optionAmount == 0) { return totalFunds.divWadDown(totalSupply); } (uint256 callPremium, ) = getPremiumForStrike(positionData.strikeId); (uint256 totalMargin, ) = FUTURES_MARKET.remainingMargin(address(this)); uint256 usedValue = callPremium.mulWadDown(positionData.optionAmount) + totalMargin; return (totalFunds + usedValue - usedFunds).divWadDown(totalSupply); } /// @notice Returns the total supply of the VAULT_TOKEN function getTotalSupply() public view returns (uint256) { return VAULT_TOKEN.totalSupply() + totalQueuedWithdrawals; } /// ----------------------------------------------------------------------- /// Internal View methods /// ----------------------------------------------------------------------- /// @notice Returns the Black-Scholes premium of call and put options /// @param _strikeId Lyra Strike ID function getPremiumForStrike(uint256 _strikeId) internal view returns (uint256 callPremium, uint256 putPremium) { ( IOptionMarket.Strike memory strike, IOptionMarket.OptionBoard memory board ) = OPTION_MARKET.getStrikeAndBoard(_strikeId); (uint256 spotPrice, bool isInvalid) = RATES.rateAndInvalid(UNDERLYING_SYNTH_KEY); if (spotPrice == 0 || isInvalid) { revert(); } if (block.timestamp > board.expiry) { ( uint256 strikePrice, uint256 priceAtExpiry, ) = OPTION_MARKET.getSettlementParameters(_strikeId); if (priceAtExpiry == 0) { revert ExpectedNonZero(); } callPremium = priceAtExpiry > strikePrice ? priceAtExpiry - strikePrice : 0; } else { uint256 boardIv = GREEKS.getIvGWAV(board.id, gwavLength); uint256 strikeSkew = GREEKS.getSkewGWAV(_strikeId, gwavLength); BlackScholesLib.BlackScholesInputs memory bsInput = BlackScholesLib.BlackScholesInputs({ timeToExpirySec: board.expiry - block.timestamp, volatilityDecimal: boardIv.mulWadDown(strikeSkew), spotDecimal: spotPrice, strikePriceDecimal: strike.strikePrice, rateDecimal: GREEKS.getGreekCacheParams().rateAndCarry }); (callPremium, putPremium) = BlackScholesLib.optionPrices(bsInput); } } /// @notice Returns the delta of the call option given its strike ID /// @param _strikeId Lyra Strike ID function getCallDelta(uint256 _strikeId) internal view returns (int256 callDelta) { ( IOptionMarket.Strike memory strike, IOptionMarket.OptionBoard memory board ) = OPTION_MARKET.getStrikeAndBoard(_strikeId); (uint256 spotPrice, bool isInvalid) = RATES.rateAndInvalid(UNDERLYING_SYNTH_KEY); if (spotPrice == 0 || isInvalid) { revert InvalidPrice(spotPrice, isInvalid); } BlackScholesLib.BlackScholesInputs memory bsInput = BlackScholesLib.BlackScholesInputs({ timeToExpirySec: board.expiry - block.timestamp, volatilityDecimal: board.iv.mulWadDown(strike.skew), spotDecimal: spotPrice, strikePriceDecimal: strike.strikePrice, rateDecimal: GREEKS.getGreekCacheParams().rateAndCarry }); (callDelta, ) = BlackScholesLib.delta(bsInput); } /// ----------------------------------------------------------------------- /// Keeper actions /// ----------------------------------------------------------------------- /// @notice Open a delta neutral position of a call option (of delta 0.4-0.6) and short futures /// @param strikeId Lyra strike ID of the call option /// @param amount Amount of options to buy /// @param maxPremiumAmount Maximum amount paid for purchasing the options function openPosition(uint256 strikeId, uint256 amount, uint256 maxPremiumAmount) external requiresAuth nonReentrant whenNotPaused { _openPosition(strikeId, amount, maxPremiumAmount); } /// @notice Close position (futures positions are closed propotional to total options size) /// @param amount Amount of options to close /// @param minPremium Minimum premium amount collected from each option closed function closePosition(uint256 amount, uint256 minPremium) external requiresAuth nonReentrant whenNotPaused { _closePosition(amount, minPremium); } /// ----------------------------------------------------------------------- /// Owner actions /// ----------------------------------------------------------------------- /// @notice Pause contracts function pause() external requiresAuth { _pause(); } /// @notice Pause deposits function pauseDeposits() external requiresAuth { _pauseDeposits(); } /// @notice Unpause contracts function unpause() external requiresAuth { _unpause(); } /// @notice Unpause deposits function unpauseDeposits() external requiresAuth { _unpauseDeposits(); } /// @notice Set fee receipient address /// @param _feeReceipient Address of the new fee receipient function setFeeReceipient(address _feeReceipient) external requiresAuth { if (_feeReceipient == address(0x0)) { revert ExpectedNonZero(); } emit UpdateFeeReceipient(feeReceipient, _feeReceipient); feeReceipient = _feeReceipient; } /// @notice Set Fees /// @param _performanceFee New Performance Fee /// @param _withdrawalFee New Withdrawal Fee function setFees(uint256 _performanceFee, uint256 _withdrawalFee) external requiresAuth { if (_performanceFee > 1e17 || _withdrawalFee > 1e16) { revert FeesTooHigh(performanceFee, withdrawalFee, _performanceFee, _withdrawalFee); } emit UpdateFees( performanceFee, withdrawalFee, _performanceFee, _withdrawalFee ); performanceFee = _performanceFee; withdrawalFee = _withdrawalFee; } /// @notice Set Synthetix Volume Program Tracking Code /// @param _code New tracking code function setSynthetixTracking(bytes32 _code) external requiresAuth { emit UpdateSynthetixTrackingCode(synthetixTrackingCode, _code); synthetixTrackingCode = _code; } /// @notice Set Minimum deposit amount /// @param _minAmt Minimum deposit amount function setMinDepositAmount(uint256 _minAmt) external requiresAuth { emit UpdateMinDeposit(minDepositAmount, _minAmt); minDepositAmount = _minAmt; } /// @notice Set Maximum deposit amount /// @param _maxAmt Maximum deposit amount function setMaxDepositAmount(uint256 _maxAmt) external requiresAuth { emit UpdateMaxDeposit(maxDepositAmount, _maxAmt); maxDepositAmount = _maxAmt; } /// @notice Set Deposit and Withdrawal delays /// @param _depositDelay New Deposit Delay /// @param _withdrawDelay New Withdrawal Delay function setDelays(uint256 _depositDelay, uint256 _withdrawDelay) external requiresAuth { emit UpdateDelays(minDepositDelay, _depositDelay, minWithdrawDelay, _withdrawDelay); minDepositDelay = _depositDelay; minWithdrawDelay = _withdrawDelay; } /// @notice Set GWAV Length /// @param length Length in seconds function setGWAVLength(uint256 length) external requiresAuth { emit UpdateGWAVLength(gwavLength, length); gwavLength = length; } /// @notice Set leverage used for futures positions /// @param _lev Leverage in 18 decimals function setLeverage(uint256 _lev) external requiresAuth { if (_lev > 5e18 || _lev < 1e18) { revert InvalidLeverage(leverage, _lev); } emit UpdateLeverage(leverage, _lev); leverage = _lev; } function setAllowList(IAllowList _list) external requiresAuth { emit UpdateAllowList(address(allowList), address(_list)); allowList = _list; } /// @notice Save ERC20 token from the vault (not SUSD or UNDERLYING) /// @param token Address of the token /// @param receiver Address of the receiver /// @param amt Amount to save function saveToken(address token, address receiver, uint256 amt) external requiresAuth { require(token != address(SUSD)); ERC20(token).transfer(receiver, amt); } /// ----------------------------------------------------------------------- /// Internal Methods /// ----------------------------------------------------------------------- function _openPosition(uint256 _strikeId, uint256 _amt, uint256 _maxPremium) internal { if ((positionData.positionId != 0 && positionData.strikeId != _strikeId) || hasClosingStarted) { revert InvalidRequest(); } int256 callDelta = getCallDelta(_strikeId); if (callDelta < 4e17 || callDelta > 6e17) { revert InvalidOption(_strikeId, uint256(callDelta)); } (uint256 spotPrice, bool isInvalid) = FUTURES_MARKET.assetPrice(); if (spotPrice == 0 || isInvalid) { revert InvalidPrice(spotPrice, isInvalid); } uint256 _shortPosition = _amt.mulWadDown(uint256(callDelta)); uint256 marginRequired = _shortPosition.mulDivDown(spotPrice, leverage); int256 shortPosition = -int256(_shortPosition); if (usedFunds + _maxPremium + marginRequired > totalFunds) { revert InsufficientFunds(totalFunds, usedFunds, _maxPremium + marginRequired); } ERC20(SUSD).safeApprove(address(OPTION_MARKET_WRAPPER), _maxPremium); IOptionMarketWrapperWithSwaps.OptionPositionParams memory params; params.optionMarket = OPTION_MARKET; params.strikeId = _strikeId; params.positionId = positionData.positionId; params.iterations = 4; // params.setCollateralTo = 0; // params.currentCollateral = 0; params.optionType = OPTION_TYPE; params.amount = _amt; // params.minCost = 0; params.maxCost = _maxPremium; params.inputAmount = _maxPremium; params.inputAsset = SUSD; IOptionMarketWrapperWithSwaps.ReturnDetails memory returnDetails = OPTION_MARKET_WRAPPER.openPosition(params); FUTURES_MARKET.transferMargin(int256(marginRequired)); FUTURES_MARKET.modifyPositionWithTracking(shortPosition, synthetixTrackingCode); if (positionData.positionId == 0) { positionData.positionId = returnDetails.positionId; positionData.strikeId = _strikeId; } positionData.optionAmount += _amt; positionData.premiumPaid += returnDetails.totalCost; positionData.shortAmount += _shortPosition; positionData.totalMargin += marginRequired; usedFunds += marginRequired + returnDetails.totalCost; emit OpenPosition( _strikeId, positionData.positionId, _amt, returnDetails.totalCost, uint256(callDelta), _shortPosition, marginRequired ); } function _closePosition(uint256 _amt, uint256 _minPremium) internal { if (positionData.positionId == 0) { revert ExpectedNonZero(); } (uint256 spotPrice, bool isInvalid) = FUTURES_MARKET.assetPrice(); if (spotPrice == 0 || isInvalid) { revert InvalidPrice(spotPrice, isInvalid); } if (!hasClosingStarted) { hasClosingStarted = true; } if (OPTION_TOKEN.getApproved(positionData.positionId) != address(OPTION_MARKET_WRAPPER)) { OPTION_TOKEN.approve(address(OPTION_MARKET_WRAPPER), positionData.positionId); } if (_amt >= positionData.optionAmount) { hasClosingStarted = false; IOptionMarketWrapperWithSwaps.OptionPositionParams memory params; params.optionMarket = OPTION_MARKET; params.strikeId = positionData.strikeId; params.positionId = positionData.positionId; params.iterations = 4; // params.setCollateralTo = 0; // params.currentCollateral = 0; params.optionType = OPTION_TYPE; params.amount = positionData.optionAmount; params.minCost = _minPremium.mulWadDown(params.amount); params.maxCost = type(uint256).max; // params.inputAmount = 0; params.inputAsset = SUSD; IOptionMarketWrapperWithSwaps.ReturnDetails memory returnDetails = OPTION_MARKET_WRAPPER.closePosition(params); FUTURES_MARKET.modifyPositionWithTracking(int256(positionData.shortAmount), synthetixTrackingCode); // No need to check for invalid since already done above (uint256 finalMargin, ) = FUTURES_MARKET.remainingMargin(address(this)); FUTURES_MARKET.withdrawAllMargin(); uint256 totalReceived = finalMargin + returnDetails.totalCost; if (totalReceived > usedFunds) { uint256 profit = totalReceived - usedFunds; uint256 perfFees = profit.mulWadDown(performanceFee); ERC20(SUSD).safeTransfer(feeReceipient, perfFees); totalFunds += (profit - perfFees); } else { totalFunds -= (usedFunds - totalReceived); } emit ClosePosition( positionData.strikeId, positionData.positionId, positionData.optionAmount, returnDetails.totalCost, positionData.shortAmount, finalMargin ); usedFunds = 0; positionData.optionAmount = 0; positionData.positionId = 0; positionData.strikeId = 0; positionData.premiumPaid = 0; positionData.shortAmount = 0; positionData.totalMargin = 0; } else { IOptionMarketWrapperWithSwaps.OptionPositionParams memory params; params.optionMarket = OPTION_MARKET; params.strikeId = positionData.strikeId; params.positionId = positionData.positionId; params.iterations = 4; // params.setCollateralTo = 0; // params.currentCollateral = 0; params.optionType = OPTION_TYPE; params.amount = _amt; params.minCost = _minPremium.mulWadDown(_amt); params.maxCost = type(uint256).max; // params.inputAmount = 0; params.inputAsset = SUSD; IOptionMarketWrapperWithSwaps.ReturnDetails memory returnDetails = OPTION_MARKET_WRAPPER.closePosition(params); uint256 shortPositionToClose = _amt.mulDivDown(positionData.shortAmount, positionData.optionAmount); FUTURES_MARKET.modifyPositionWithTracking(int256(shortPositionToClose), synthetixTrackingCode); emit ClosePosition( positionData.strikeId, positionData.positionId, _amt, returnDetails.totalCost, shortPositionToClose, 0 ); usedFunds -= returnDetails.totalCost; positionData.optionAmount -= _amt; positionData.shortAmount -= shortPositionToClose; } } /// ----------------------------------------------------------------------- /// Errors /// ----------------------------------------------------------------------- /// General error InsufficientFunds(uint256 totalFunds, uint256 usedFunds, uint256 requiredFunds); error ExpectedNonZero(); /// Trading errors error InvalidPrice(uint256 spotPrice, bool isInvalid); error InvalidOption(uint256 strikeId, uint256 callDelta); error InvalidRequest(); /// Deposit and Withdrawals error MinimumDepositRequired(uint256 minDeposit, uint256 requestedAmount); /// Owner actions error InvalidLeverage(uint256 currentLeverage, uint256 requestedLeverage); error FeesTooHigh(uint256 currentPerf, uint256 currentWithdraw, uint256 newPerf, uint256 newWithdraw); /// ----------------------------------------------------------------------- /// Events /// ----------------------------------------------------------------------- /// @notice Initiate Deposit Event /// @param depositId Deposit ID /// @param depositor Address of the fund depositor (msg.sender) /// @param user Address of the user who'll be getting the VAULT_TOKENs /// @param amount Amount depositted (in UNDERLYING) event InitiateDeposit( uint256 depositId, address depositor, address user, uint256 amount ); /// @notice Process Deposit Event /// @param depositId Deposit ID /// @param user Address of the user who'll be getting the VAULT_TOKENs /// @param amount Amount depositted (in UNDERLYING) /// @param tokens Amount of VAULT_TOKENs minted /// @param requestedTime Timestamp of the initiateDeposit call event ProcessDeposit( uint256 depositId, address user, uint256 amount, uint256 tokens, uint256 requestedTime ); /// @notice Initiate Withdrawal Event /// @param withdrawalId Withdrawal ID /// @param withdrawer Address of the user who requested withdraw (msg.sender) /// @param user Address of the user who'll be getting UNDERLYING tokens upon processing /// @param tokens Amount of VAULT_TOKENs to burn / withdraw event InitiateWithdrawal( uint256 withdrawalId, address withdrawer, address user, uint256 tokens ); /// @notice Process Withdrawal Event /// @param withdrawalId Withdrawal ID /// @param user Address of the user who's getting the funds /// @param tokens Amount of VAULT_TOKENs burned /// @param amount Amount of UNDERLYING returned /// @param requestedTime Timestamp of the initiateWithdraw call event ProcessWithdrawal( uint256 withdrawalId, address user, uint256 tokens, uint256 amount, uint256 requestedTime ); /// @notice Process Withdrawal Partially Event /// @param withdrawalId Withdrawal ID /// @param user Address of the user who's getting the funds /// @param tokens Amount of VAULT_TOKENs burned /// @param amount Amount of UNDERLYING returned /// @param requestedTime Timestamp of the initiateWithdraw call event ProcessWithdrawalPartially( uint256 withdrawalId, address user, uint256 tokens, uint256 amount, uint256 requestedTime ); /// @notice Update Fee Receipient Event /// @param oldFeeReceipient Address of the old fee receipient /// @param newFeeReceipient Address of the new fee receipient event UpdateFeeReceipient(address oldFeeReceipient, address newFeeReceipient); /// @notice Update Fees Event /// @param oldPerf Old Perfomance Fee /// @param oldWithdraw Old Withdrawal Fee /// @param newPerf New Performance Fee /// @param newWithdraw New Withdrawal Fee event UpdateFees(uint256 oldPerf, uint256 oldWithdraw, uint256 newPerf, uint256 newWithdraw); /// @notice Update Synthetix Tracking Code Event /// @param oldCode Existing code /// @param newCode New code event UpdateSynthetixTrackingCode(bytes32 oldCode, bytes32 newCode); /// @notice Update Minimum Deposit Amount Event /// @param oldMinimum Previous minimum deposit amount /// @param newMinimum New minimum deposit amount event UpdateMinDeposit(uint256 oldMinimum, uint256 newMinimum); /// @notice Update Maximum Deposit Amount Event /// @param oldMax Previous maximum deposit amount /// @param newMax New maximum deposit amount event UpdateMaxDeposit(uint256 oldMax, uint256 newMax); /// @notice Update Deposit and Withdraw delays Event /// @param oldDepositDelay Old Deposit Delay /// @param newDepositDelay New Deposit Delay /// @param oldWithdrawDelay Old Withdraw Delay /// @param newWithdrawDelay New Withdraw Delay event UpdateDelays( uint256 oldDepositDelay, uint256 newDepositDelay, uint256 oldWithdrawDelay, uint256 newWithdrawDelay ); /// @notice Update GWAV Length /// @param oldLength Old Length /// @param newLength New Length event UpdateGWAVLength( uint256 oldLength, uint256 newLength ); /// @notice Update Leverage Event /// @param oldLeverage Old leverage /// @param newLeverage New leverage event UpdateLeverage( uint256 oldLeverage, uint256 newLeverage ); /// @notice Update AllowList Event /// @param oldList Old AllowList /// @param newList New AllowList event UpdateAllowList( address oldList, address newList ); /// @notice Open Position Event /// @param strikeId Lyra Option Strike ID /// @param positionId Corresponding Position ID /// @param amount Amount of options purchased /// @param premiumPaid Total premium paid /// @param callDelta Delta of the option /// @param shortPosition Amount of UNDERLYING shorted /// @param marginUsed Margin used for opening the short position event OpenPosition( uint256 strikeId, uint256 positionId, uint256 amount, uint256 premiumPaid, uint256 callDelta, uint256 shortPosition, uint256 marginUsed ); /// @notice Close Position Event /// @param strikeId Lyra Option Strike ID /// @param positionId Corresponding Position ID /// @param amount Amount of options closed /// @param premiumCollected Total premium collected /// @param shortPosition Amount of futures position closed /// @param marginWithdrawn Margin withdrawn event ClosePosition( uint256 strikeId, uint256 positionId, uint256 amount, uint256 premiumCollected, uint256 shortPosition, uint256 marginWithdrawn ); }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ERC20","name":"_susd","type":"address"},{"internalType":"contract IPolynomialVaultToken","name":"_vaultToken","type":"address"},{"internalType":"contract IOptionMarket","name":"_optionMarket","type":"address"},{"internalType":"contract IFuturesMarket","name":"_futuresMarket","type":"address"},{"internalType":"contract IOptionMarketWrapperWithSwaps","name":"_optionMarketWrapper","type":"address"},{"internalType":"contract IOptionToken","name":"_optionToken","type":"address"},{"internalType":"contract IOptionGreekCache","name":"_greeks","type":"address"},{"internalType":"contract IExchangeRates","name":"_rates","type":"address"},{"internalType":"bytes32","name":"_underlyingKey","type":"bytes32"},{"internalType":"bytes32","name":"_name","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DepositsNotPaused","type":"error"},{"inputs":[],"name":"DepositsPaused","type":"error"},{"inputs":[],"name":"ExpectedNonZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentPerf","type":"uint256"},{"internalType":"uint256","name":"currentWithdraw","type":"uint256"},{"internalType":"uint256","name":"newPerf","type":"uint256"},{"internalType":"uint256","name":"newWithdraw","type":"uint256"}],"name":"FeesTooHigh","type":"error"},{"inputs":[{"internalType":"uint256","name":"totalFunds","type":"uint256"},{"internalType":"uint256","name":"usedFunds","type":"uint256"},{"internalType":"uint256","name":"requiredFunds","type":"uint256"}],"name":"InsufficientFunds","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentLeverage","type":"uint256"},{"internalType":"uint256","name":"requestedLeverage","type":"uint256"}],"name":"InvalidLeverage","type":"error"},{"inputs":[{"internalType":"uint256","name":"strikeId","type":"uint256"},{"internalType":"uint256","name":"callDelta","type":"uint256"}],"name":"InvalidOption","type":"error"},{"inputs":[{"internalType":"uint256","name":"spotPrice","type":"uint256"},{"internalType":"bool","name":"isInvalid","type":"bool"}],"name":"InvalidPrice","type":"error"},{"inputs":[],"name":"InvalidRequest","type":"error"},{"inputs":[{"internalType":"uint256","name":"minDeposit","type":"uint256"},{"internalType":"uint256","name":"requestedAmount","type":"uint256"}],"name":"MinimumDepositRequired","type":"error"},{"inputs":[],"name":"NotPaused","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strikeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"premiumCollected","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shortPosition","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marginWithdrawn","type":"uint256"}],"name":"ClosePosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"depositId","type":"uint256"},{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InitiateDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"withdrawalId","type":"uint256"},{"indexed":false,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"InitiateWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strikeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"premiumPaid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"callDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shortPosition","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marginUsed","type":"uint256"}],"name":"OpenPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"depositId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestedTime","type":"uint256"}],"name":"ProcessDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"withdrawalId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestedTime","type":"uint256"}],"name":"ProcessWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"withdrawalId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestedTime","type":"uint256"}],"name":"ProcessWithdrawalPartially","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"SetDepositsPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"SetDepositsUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"SetPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"SetUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldList","type":"address"},{"indexed":false,"internalType":"address","name":"newList","type":"address"}],"name":"UpdateAllowList","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldDepositDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDepositDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldWithdrawDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newWithdrawDelay","type":"uint256"}],"name":"UpdateDelays","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldFeeReceipient","type":"address"},{"indexed":false,"internalType":"address","name":"newFeeReceipient","type":"address"}],"name":"UpdateFeeReceipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPerf","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldWithdraw","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPerf","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newWithdraw","type":"uint256"}],"name":"UpdateFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLength","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLength","type":"uint256"}],"name":"UpdateGWAVLength","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLeverage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLeverage","type":"uint256"}],"name":"UpdateLeverage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMax","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"UpdateMaxDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMinimum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinimum","type":"uint256"}],"name":"UpdateMinDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"oldCode","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newCode","type":"bytes32"}],"name":"UpdateSynthetixTrackingCode","type":"event"},{"inputs":[],"name":"FUTURES_MARKET","outputs":[{"internalType":"contract IFuturesMarket","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GREEKS","outputs":[{"internalType":"contract IOptionGreekCache","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTION_MARKET","outputs":[{"internalType":"contract IOptionMarket","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTION_MARKET_WRAPPER","outputs":[{"internalType":"contract IOptionMarketWrapperWithSwaps","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTION_TOKEN","outputs":[{"internalType":"contract IOptionToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATES","outputs":[{"internalType":"contract IExchangeRates","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUSD","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNDERLYING_SYNTH_KEY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT_TOKEN","outputs":[{"internalType":"contract IPolynomialVaultToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowList","outputs":[{"internalType":"contract IAllowList","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minPremium","type":"uint256"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"depositQueue","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"depositedAmount","type":"uint256"},{"internalType":"uint256","name":"mintedTokens","type":"uint256"},{"internalType":"uint256","name":"requestedTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gwavLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasClosingStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"initiateDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"initiateWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"leverage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minWithdrawDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextQueuedDepositId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextQueuedWithdrawalId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"strikeId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"maxPremiumAmount","type":"uint256"}],"name":"openPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"performanceFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionData","outputs":[{"internalType":"uint256","name":"strikeId","type":"uint256"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"optionAmount","type":"uint256"},{"internalType":"uint256","name":"premiumPaid","type":"uint256"},{"internalType":"uint256","name":"shortAmount","type":"uint256"},{"internalType":"uint256","name":"totalMargin","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idCount","type":"uint256"}],"name":"processDepositQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"idCount","type":"uint256"}],"name":"processWithdrawalQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"queuedDepositHead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queuedWithdrawalHead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"saveToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAllowList","name":"_list","type":"address"}],"name":"setAllowList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositDelay","type":"uint256"},{"internalType":"uint256","name":"_withdrawDelay","type":"uint256"}],"name":"setDelays","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceipient","type":"address"}],"name":"setFeeReceipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_performanceFee","type":"uint256"},{"internalType":"uint256","name":"_withdrawalFee","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"setGWAVLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lev","type":"uint256"}],"name":"setLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAmt","type":"uint256"}],"name":"setMaxDepositAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minAmt","type":"uint256"}],"name":"setMinDepositAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_code","type":"bytes32"}],"name":"setSynthetixTracking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"synthetixTrackingCode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalQueuedDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalQueuedWithdrawals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usedFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdrawalQueue","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"withdrawnTokens","type":"uint256"},{"internalType":"uint256","name":"returnedAmount","type":"uint256"},{"internalType":"uint256","name":"requestedTime","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101c0604052600160025560016010556001601155600160125560016013553480156200002b57600080fd5b5060405162005446380380620054468339810160408190526200004e916200013f565b60008054336001600160a01b03199182168117835560018054909216909155604051909190829081907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908490a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350506003805461ffff191690556001600160a01b0398891660e052968816610100529487166101205292861661014052908516610160529084166101a05283166101805260a0526080521660c05262000215565b6001600160a01b03811681146200013c57600080fd5b50565b6000806000806000806000806000806101408b8d0312156200016057600080fd5b8a516200016d8162000126565b60208c0151909a50620001808162000126565b60408c0151909950620001938162000126565b60608c0151909850620001a68162000126565b60808c0151909750620001b98162000126565b60a08c0151909650620001cc8162000126565b60c08c0151909550620001df8162000126565b60e08c0151909450620001f28162000126565b809350506101008b015191506101208b015190509295989b9194979a5092959850565b60805160a05160c05160e05161010051610120516101405161016051610180516101a05161506c620003da6000396000818161064001528181613680015261450501526000818161089f015281816138730152818161392e01528181613a01015261462401526000818161087801528181612ac60152612b900152600081816105f301528181612aa201528181612bbd01528181612d4d015281816131eb01528181613df10152613edd015260008181610848015281816114780152818161295901528181612e1301528181612ea701528181612f2e015281816132c701528181613c3701528181613f97015261402c01526000818161078601528181612c6f01528181613111015281816135620152818161375b01528181613e2001526143e70152600081816104f60152818161168d01528181611f000152818161220301526124ab01526000818161043501528181610fcd01528181611017015281816111210152818161116b01528181611d60015281816120620152818161265b01528181612cfb01528181612ffa0152818161319901528181613dcf0152613e8b0152600081816107270152818161364801526144cd015260006103c3015261506c6000f3fe608060405234801561001057600080fd5b50600436106103af5760003560e01c806379575b23116101f4578063bf7e214f1161011a578063e3d51ddd116100ad578063ed6d06c01161007c578063ed6d06c0146108e1578063f6011230146108f4578063fc2da41f146108fd578063fd9d40771461090657600080fd5b8063e3d51ddd14610873578063e55d1a521461089a578063eb899c68146108c1578063ec552346146108ce57600080fd5b8063c8393ba9116100e9578063c8393ba91461081d578063ccf3aed214610830578063d3e6f7f314610843578063deccdf631461086a57600080fd5b8063bf7e214f146107a8578063c4511c6a146107bb578063c4e41b22146107ce578063c822adda146107d657600080fd5b8063892df74f116101925780638ed83271116101615780638ed832711461075c578063968ed600146107655780639afdb2c21461076e5780639be75fb71461078157600080fd5b8063892df74f146107105780638bc7e8c4146107195780638da4e2f9146107225780638da5cb5b1461074957600080fd5b806383290a3c116101ce57806383290a3c146106755780638456cb59146106ec57806387788782146106f457806387b9d25c146106fd57600080fd5b806379575b231461062857806379f67c441461063b5780637a9e5e4b1461066257600080fd5b80633f4ba83a116102d957806358f67c0b1161027757806363d8882a1161024657806363d8882a146105dd578063645006ca146105e557806366d0cb91146105ee5780637772ba071461061557600080fd5b806358f67c0b1461059a5780635c975abb146105a35780635ece09c5146105ba57806360da3e83146105cd57600080fd5b80634aab90f8116102b35780634aab90f8146105215780634b48f20d1461056c5780634b94f50e1461057f5780634d8737cb1461058757600080fd5b80633f4ba83a146104e95780634499d14b146104f1578063481bf0b81461051857600080fd5b8063208e7e93116103515780632d6ce61d116103205780632d6ce61d146104a7578063342c00b3146104ba57806335f748c2146104cd5780633740ebb3146104d657600080fd5b8063208e7e931461046f5780632a80cda3146104785780632b6fcf2e1461048b5780632c86d98e1461049e57600080fd5b80630b78f9c01161038d5780630b78f9c01461040157806313af40351461041457806315a01bc11461042757806315d8eeba1461043057600080fd5b806302191980146103b457806306fdde03146103be5780630b2ad088146103f8575b600080fd5b6103bc61090f565b005b6103e57f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b6103e560135481565b6103bc61040f3660046148b0565b610998565b6103bc6104223660046148ea565b610adb565b6103e560155481565b6104577f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016103ef565b6103e560105481565b6103bc610486366004614907565b610bb8565b6103bc610499366004614907565b610c73565b6103e560095481565b6103bc6104b53660046148b0565b610d2e565b6103bc6104c8366004614907565b610e4e565b6103e560065481565b600a54610457906001600160a01b031681565b6103bc61122d565b6104577f000000000000000000000000000000000000000000000000000000000000000081565b6103e5600f5481565b601754601854601954601a54601b54601c5461053f95949392919086565b604080519687526020870195909552938501929092526060840152608083015260a082015260c0016103ef565b6103bc61057a3660046148ea565b6112af565b6103e56113ea565b6103bc610595366004614907565b611549565b6103e5600e5481565b60035460ff165b60405190151581526020016103ef565b6103bc6105c8366004614920565b61178c565b600354610100900460ff166105aa565b6103bc6118ae565b6103e560045481565b6104577f000000000000000000000000000000000000000000000000000000000000000081565b6103bc6106233660046148b0565b611930565b6103bc610636366004614907565b611a00565b6104577f000000000000000000000000000000000000000000000000000000000000000081565b6103bc6106703660046148ea565b611b1d565b6106bc610683366004614907565b601e602052600090815260409020805460018201546002830154600384015460049094015492936001600160a01b039092169290919085565b604080519586526001600160a01b039094166020860152928401919091526060830152608082015260a0016103ef565b6103bc611c62565b6103e5600b5481565b601d54610457906001600160a01b031681565b6103e560125481565b6103e5600c5481565b6103e57f000000000000000000000000000000000000000000000000000000000000000081565b600054610457906001600160a01b031681565b6103e560055481565b6103e560145481565b6103bc61077c36600461494c565b611ce4565b6104577f000000000000000000000000000000000000000000000000000000000000000081565b600154610457906001600160a01b031681565b6103bc6107c9366004614907565b611e3e565b6103e5611ef9565b6106bc6107e4366004614907565b601f602052600090815260409020805460018201546002830154600384015460049094015492936001600160a01b039092169290919085565b6103bc61082b36600461498d565b611f9e565b6103bc61083e366004614907565b612270565b6104577f000000000000000000000000000000000000000000000000000000000000000081565b6103e560085481565b6104577f000000000000000000000000000000000000000000000000000000000000000081565b6104577f000000000000000000000000000000000000000000000000000000000000000081565b6016546105aa9060ff1681565b6103bc6108dc36600461498d565b61232b565b6103bc6108ef3660046148ea565b612683565b6103e5600d5481565b6103e560115481565b6103e560075481565b61093d336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b61098e5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b610996612877565b565b6109c6336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b610a125760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b67016345785d8a0000821180610a2e5750662386f26fc1000081115b15610a8257600b54600c546040517f0995039e000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044810183905260648101829052608401610985565b600b54600c546040805192835260208301919091528101839052606081018290527f5c3aee3d65f7eb02cded951435d06b06ef307bc7f57b98975c4a41dc116e711c9060800160405180910390a1600b91909155600c55565b610b09336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b610b555760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b610be6336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b610c325760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b60045460408051918252602082018390527f915e1f57375bebe5483299c788956d167e46a28a143974dc29bba5a420aa4354910160405180910390a1600455565b610ca1336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b610ced5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b60085460408051918252602082018390527f40777929ad14ec610067fc9c075e20805fe1c57e1879cf2b583355109971c546910160405180910390a1600855565b610d5c336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b610da85760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b600254600114610dfa5760405162461bcd60e51b815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610985565b6002805560035460ff1615610e3b576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e45828261291b565b50506001600255565b600254600114610ea05760405162461bcd60e51b815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610985565b6002805560005b81811015610e45576000610eb96113ea565b6012546000908152601f602052604090206004810154919250901580610eef57506007548160040154610eec91906149e8565b42105b15610efc57505050611225565b6000601554601454610f0e9190614a00565b905080610f1e5750505050611225565b6002820154600090610f3090856133e1565b9050818111156110ab57600383018290556000610f4d83866133fd565b905080600f6000828254610f619190614a00565b9250508190555080846002016000828254610f7c9190614a00565b925050819055508260146000828254610f959190614a00565b9091555050600c5415611004576000610fb9600c54856133e190919063ffffffff16565b600a54909150610ff6906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613412565b6110008185614a00565b9350505b6001840154611040906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911685613412565b835460018501546004860154604080519384526001600160a01b039092166020840152828201849052606083018690526080830152517f36a40db5d5631acd8e2764bd196c60dd82faed72aea6647297ab6af63309b58e9181900360a00190a1505050505050611225565b600383018190556002830154600f80546000906110c9908490614a00565b9091555050600060028401819055601480548392906110e9908490614a00565b9091555050600c541561115857600061110d600c54836133e190919063ffffffff16565b600a5490915061114a906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613412565b6111548183614a00565b9150505b6001830154611194906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613412565b8254600184015460028501546004860154604080519485526001600160a01b039093166020850152918301526060820183905260808201527f86dc3fd2a6c267674f2f2ef1b4b7283dcca31e1e2517a55358795c65eca1fe039060a00160405180910390a16012805490600061120983614a17565b919050555050505050808061121d90614a17565b915050610ea7565b506001600255565b61125b336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b6112a75760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b6109966134b1565b6112dd336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b6113295760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b6001600160a01b038116611369576040517f54db0c8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a54604080516001600160a01b03928316815291831660208301527fc8bc890a52e17e373db7ac75d8f97911a18bffc2ef18bd8047ed55770ee6ba8b910160405180910390a1600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000601454600014156114045750670de0b6b3a764000090565b600061140e611ef9565b60195490915061142b576014546114259082613545565b91505090565b600061143b60176000015461355a565b506040517f9cfbf4e40000000000000000000000000000000000000000000000000000000081523060048201529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639cfbf4e490602401604080518083038186803b1580156114b957600080fd5b505afa1580156114cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f19190614a65565b50905060008161150f601760020154856133e190919063ffffffff16565b61151991906149e8565b9050611540846015548360145461153091906149e8565b61153a9190614a00565b90613545565b94505050505090565b60025460011461159b5760405162461bcd60e51b815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610985565b6002805560006115a96113ea565b905060005b82811015611782576010546000908152601e60205260409020600481015415806115e8575060065481600401546115e591906149e8565b42105b156115f557505050611225565b60028101546000906116079085613545565b90508082600301819055508160020154600e60008282546116289190614a00565b90915550506002820154601480546000906116449084906149e8565b909155505060018201546040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018390527f0000000000000000000000000000000000000000000000000000000000000000909116906340c10f1990604401600060405180830381600087803b1580156116d357600080fd5b505af11580156116e7573d6000803e3d6000fd5b50508354600185015460028601546004870154604080519485526001600160a01b039093166020850152918301526060820185905260808201527f4d356a2d534287c80daa3bb725dcc09c0ad1049e50c1e328646c49e5a0b2c6cb925060a001905060405180910390a1600060028301819055601080549161176883614a17565b91905055505050808061177a90614a17565b9150506115ae565b5050506001600255565b6117ba336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b6118065760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b6002546001146118585760405162461bcd60e51b815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610985565b6002805560035460ff1615611899576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118a4838383613b70565b5050600160025550565b6118dc336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b6119285760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b6109966141b5565b61195e336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b6119aa5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b6006546007546040805192835260208301859052820152606081018290527fc8f5f7dffddfef257dee57a6cd0384a4900f2ab48c3e69766faa5577e6a7cbcb9060800160405180910390a1600691909155600755565b611a2e336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b611a7a5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b674563918244f40000811180611a975750670de0b6b3a764000081105b15611adc576009546040517f3a997bfc000000000000000000000000000000000000000000000000000000008152600481019190915260248101829052604401610985565b60095460408051918252602082018390527f0994a4aef927e586cf27b92c43c2e63b627e9a4892c704b4d73170655e6e6cf9910160405180910390a1600955565b6000546001600160a01b0316331480611bf557506001546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201526000357fffffffff000000000000000000000000000000000000000000000000000000001660448201526001600160a01b039091169063b70096139060640160206040518083038186803b158015611bbd57600080fd5b505afa158015611bd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf59190614a91565b611bfe57600080fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350565b611c90336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b611cdc5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b61099661424e565b611d12336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b611d5e5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161415611d9d57600080fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301526024820183905284169063a9059cbb90604401602060405180830381600087803b158015611e0057600080fd5b505af1158015611e14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e389190614a91565b50505050565b611e6c336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b611eb85760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b60055460408051918252602082018390527f37396aa6d615d710c40a1a725316294e4ff3ba20b5544b517a84d89f08178ad8910160405180910390a1600555565b6000600f547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f5757600080fd5b505afa158015611f6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f8f9190614aac565b611f9991906149e8565b905090565b600254600114611ff05760405162461bcd60e51b815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610985565b600280556001600160a01b038216612034576040517f54db0c8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6019546120fe5760006120456113ea565b9050600061205383836133e1565b90506120896001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168583613412565b806014600082825461209b9190614a00565b909155505060408051600081526001600160a01b0386166020820152908101849052606081018290524260808201527f86dc3fd2a6c267674f2f2ef1b4b7283dcca31e1e2517a55358795c65eca1fe039060a00160405180910390a150506121ce565b601380546000818152601f60205260408120929061211b83614a17565b9091555081556001810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03851617905560028101829055426004820155600f80548391906000906121789084906149e8565b90915550508054604080519182523360208301526001600160a01b0385168282015260608201849052517f6af4b9a67fcdcb6bdd58b7b26c00492d52c66372d350d228ec6a5420bb13fe329181900360800190a1505b6040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639dc29fac90604401600060405180830381600087803b15801561224f57600080fd5b505af1158015612263573d6000803e3d6000fd5b5050600160025550505050565b61229e336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b6122ea5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b600d5460408051918252602082018390527fe6a80d2c46fa6481cec16136a0a5b4f293bf679480d7790883589d7f54ce91d1910160405180910390a1600d55565b60025460011461237d5760405162461bcd60e51b815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610985565b60028055600354610100900460ff16156123c3576040517fdeeb694300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038216612403576040517f54db0c8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045481101561244a57600480546040517f54443ec40000000000000000000000000000000000000000000000000000000081529182015260248101829052604401610985565b60195461257e57600061245b6113ea565b905060006124698383613545565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529192507f0000000000000000000000000000000000000000000000000000000000000000909116906340c10f1990604401600060405180830381600087803b1580156124f157600080fd5b505af1158015612505573d6000803e3d6000fd5b50505050826014600082825461251b91906149e8565b909155505060408051600081526001600160a01b0386166020820152908101849052606081018290524260808201527f4d356a2d534287c80daa3bb725dcc09c0ad1049e50c1e328646c49e5a0b2c6cb9060a00160405180910390a1505061264e565b601180546000818152601e60205260408120929061259b83614a17565b9091555081556001810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03851617905560028101829055426004820155600e80548391906000906125f89084906149e8565b90915550508054604080519182523360208301526001600160a01b0385168282015260608201849052517f1ccb85c4426dacaaa67edc2ae6421283328736c96dd21b82026889d72414832c9181900360800190a1505b610e456001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163330846142e7565b6126b1336000357fffffffff000000000000000000000000000000000000000000000000000000001661277e565b6126fd5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610985565b601d54604080516001600160a01b03928316815291831660208301527f1926d1b6d5bb49538b382b82a523f908b1d71147ac6efdca65337bfc00adbefc910160405180910390a1601d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6001546000906001600160a01b0316801580159061285757506040517fb70096130000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301523060248301527fffffffff000000000000000000000000000000000000000000000000000000008516604483015282169063b70096139060640160206040518083038186803b15801561281f57600080fd5b505afa158015612833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128579190614a91565b8061286f57506000546001600160a01b038581169116145b949350505050565b600354610100900460ff16156128b9576040517fdeeb694300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556040513381527fcb92ca4a4d7ab7e82e1f35164d09a91663f3393b45f06fcac5a73f63ae6bf23f906020015b60405180910390a1565b601854612954576040517f54db0c8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d24378eb6040518163ffffffff1660e01b8152600401604080518083038186803b1580156129af57600080fd5b505afa1580156129c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e79190614a65565b9150915081600014806129f75750805b15612a39576040517f7ba84727000000000000000000000000000000000000000000000000000000008152600481018390528115156024820152604401610985565b60165460ff16612a6f57601680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6018546040517f081812fc0000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116927f00000000000000000000000000000000000000000000000000000000000000009091169163081812fc91612aff9160040190815260200190565b60206040518083038186803b158015612b1757600080fd5b505afa158015612b2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4f9190614ad0565b6001600160a01b031614612c2c576018546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163095ea7b391612bf9917f0000000000000000000000000000000000000000000000000000000000000000916004016001600160a01b03929092168252602082015260400190565b600060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050505b60195484106130ff57601680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612c6561482c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526017546020820152601854604082015260046060820152600060c082015260195460e08201819052612cc49085906133e1565b6101008201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101208201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166101608301526040517fb738a96b0000000000000000000000000000000000000000000000000000000081526000917f0000000000000000000000000000000000000000000000000000000000000000169063b738a96b90612d82908590600401614b57565b61010060405180830381600087803b158015612d9d57600080fd5b505af1158015612db1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd59190614ce3565b601b54600d546040517fa28a2bc0000000000000000000000000000000000000000000000000000000008152600481019290925260248201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a28a2bc090604401600060405180830381600087803b158015612e5f57600080fd5b505af1158015612e73573d6000803e3d6000fd5b50506040517f9cfbf4e4000000000000000000000000000000000000000000000000000000008152306004820152600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169150639cfbf4e490602401604080518083038186803b158015612ef157600080fd5b505afa158015612f05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f299190614a65565b5090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635a1cbd2b6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612f8757600080fd5b505af1158015612f9b573d6000803e3d6000fd5b505050506000826080015182612fb191906149e8565b905060155481111561304b57600060155482612fcd9190614a00565b90506000612fe6600b54836133e190919063ffffffff16565b600a54909150613023906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613412565b61302d8183614a00565b6014600082825461303e91906149e8565b9091555061307092505050565b806015546130599190614a00565b6014600082825461306a9190614a00565b90915550505b601754601854601954608086810151601b5460408051968752602087019590955285850193909352606085015283015260a08201849052517f9741bf68d4078249163675971e787afff796b7de3d42127e74eb3a541c1d14ca9181900360c00190a1505060006015819055601981905560188190556017819055601a819055601b819055601c5550611e389050565b61310761482c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526017546020820152601854604082015260046060820152600060c082015260e0810185905261316284866133e1565b6101008201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101208201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166101608301526040517fb738a96b0000000000000000000000000000000000000000000000000000000081526000917f0000000000000000000000000000000000000000000000000000000000000000169063b738a96b90613220908590600401614b57565b61010060405180830381600087803b15801561323b57600080fd5b505af115801561324f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132739190614ce3565b601b5460195491925060009161328a918991614393565b600d546040517fa28a2bc00000000000000000000000000000000000000000000000000000000081526004810183905260248101919091529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a28a2bc090604401600060405180830381600087803b15801561331357600080fd5b505af1158015613327573d6000803e3d6000fd5b50506017546018546080868101516040805194855260208501939093528383018d905260608401528201859052600060a0830152517f9741bf68d4078249163675971e787afff796b7de3d42127e74eb3a541c1d14ca93509081900360c0019150a181608001516015600082825461339f9190614a00565b9091555050601980548891906000906133b9908490614a00565b9091555050601b80548291906000906133d3908490614a00565b909155505050505050505050565b60006133f68383670de0b6b3a7640000614393565b9392505050565b60006133f683670de0b6b3a7640000846143b2565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611e385760405162461bcd60e51b815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610985565b60035460ff166134ed576040517f6cd6020100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556040513381527f3bd4fb9a28883a4c90034f2cd214c1f94fc09854604f38dee6a87e5455e2123b90602001612911565b60006133f683670de0b6b3a764000084614393565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c4c4a0d0866040518263ffffffff1660e01b81526004016135ae91815260200190565b60006040518083038186803b1580156135c657600080fd5b505afa1580156135da573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526136209190810190614e6a565b6040517f0c71cd230000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152919350915060009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630c71cd2390602401604080518083038186803b1580156136c157600080fd5b505afa1580156136d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f99190614a65565b9150915081600014806137095750805b1561371357600080fd5b8260200151421115613836576040517f1fdb6cbd0000000000000000000000000000000000000000000000000000000081526004810188905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631fdb6cbd9060240160606040518083038186803b15801561379d57600080fd5b505afa1580156137b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d59190614f24565b50915091508060001415613815576040517f54db0c8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81811161382357600061382d565b61382d8282614a00565b97505050613b67565b82516008546040517ff3fd9b3d000000000000000000000000000000000000000000000000000000008152600481019290925260248201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f3fd9b3d9060440160206040518083038186803b1580156138bd57600080fd5b505afa1580156138d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138f59190614aac565b6008546040517f7df712680000000000000000000000000000000000000000000000000000000081529192506000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691637df712689161396c918d91600401918252602082015260400190565b60206040518083038186803b15801561398457600080fd5b505afa158015613998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139bc9190614aac565b905060006040518060a001604052804288602001516139db9190614a00565b81526020016139ea85856133e1565b8152602001868152602001886020015181526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f369f2ac6040518163ffffffff1660e01b81526004016101406040518083038186803b158015613a5957600080fd5b505afa158015613a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a919190614f52565b61012001519052604080517fbcf1e77900000000000000000000000000000000000000000000000000000000815282516004820152602083015160248201529082015160448201526060820151606482015260808201516084820152909150730052a341bea99c4b452816235fc2216143c5f21c9063bcf1e7799060a401604080518083038186803b158015613b2657600080fd5b505af4158015613b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5e9190614fd9565b90995097505050505b50505050915091565b60185415801590613b8357506017548314155b80613b90575060165460ff165b15613bc7576040517f41abc80100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613bd2846143e0565b905067058d15e176280000811280613bf15750670853a0d2313c000081135b15613c32576040517ffbf7b2e80000000000000000000000000000000000000000000000000000000081526004810185905260248101829052604401610985565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d24378eb6040518163ffffffff1660e01b8152600401604080518083038186803b158015613c8d57600080fd5b505afa158015613ca1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc59190614a65565b915091508160001480613cd55750805b15613d17576040517f7ba84727000000000000000000000000000000000000000000000000000000008152600481018390528115156024820152604401610985565b6000613d2386856133e1565b90506000613d3e84600954846143939092919063ffffffff16565b90506000613d4b83614ffd565b90506014548288601554613d5f91906149e8565b613d6991906149e8565b1115613dc257601454601554613d7f848a6149e8565b6040517ff5623b72000000000000000000000000000000000000000000000000000000008152600481019390935260248301919091526044820152606401610985565b613e166001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008961478d565b613e1e61482c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602081018a9052601854604082015260046060820152600060c082018190525060e08101899052610120810188905261014081018890526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166101608301526040517f8bc369690000000000000000000000000000000000000000000000000000000081526000917f00000000000000000000000000000000000000000000000000000000000000001690638bc3696990613f12908590600401614b57565b61010060405180830381600087803b158015613f2d57600080fd5b505af1158015613f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f659190614ce3565b6040517f88a3c848000000000000000000000000000000000000000000000000000000008152600481018690529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906388a3c84890602401600060405180830381600087803b158015613fe357600080fd5b505af1158015613ff7573d6000803e3d6000fd5b5050600d546040517fa28a2bc00000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a28a2bc0925061406c918791600401918252602082015260400190565b600060405180830381600087803b15801561408657600080fd5b505af115801561409a573d6000803e3d6000fd5b5050601854151591506140b7905057602081015160185560178b90555b89601760020160008282546140cc91906149e8565b90915550506080810151601a80546000906140e89084906149e8565b9091555050601b80548691906000906141029084906149e8565b9091555050601c805485919060009061411c9084906149e8565b9091555050608081015161413090856149e8565b6015600082825461414191906149e8565b9091555050601854608082810151604080518f8152602081019490945283018d90526060830152810189905260a0810186905260c081018590527f119df371ee542c429dd5298bb603872532a3e9dfdc1c794ad226298126f295a19060e00160405180910390a15050505050505050505050565b600354610100900460ff166141f6576040517fa4d3098c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690556040513381527fd9b17f88c19eed029496a647acd647444182c708871dadb0b13c8db2bbcdff3690602001612911565b60035460ff161561428b576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790556040513381527ff87d42f34d6dc854596ee7e10d09f6ef97f38e4ab22330c4fcb384c7e7f81d1990602001612911565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d116001600051141617169150508061438c5760405162461bcd60e51b815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610985565b5050505050565b8282028115158415858304851417166143ab57600080fd5b0492915050565b8282028115158415858304851417166143ca57600080fd5b6001826001830304018115150290509392505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c4c4a0d0856040518263ffffffff1660e01b815260040161443391815260200190565b60006040518083038186803b15801561444b57600080fd5b505afa15801561445f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526144a59190810190614e6a565b6040517f0c71cd230000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152919350915060009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630c71cd2390602401604080518083038186803b15801561454657600080fd5b505afa15801561455a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061457e9190614a65565b91509150816000148061458e5750805b156145d0576040517f7ba84727000000000000000000000000000000000000000000000000000000008152600481018390528115156024820152604401610985565b60006040518060a001604052804286602001516145ed9190614a00565b815260200161460d876040015187604001516133e190919063ffffffff16565b8152602001848152602001866020015181526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f369f2ac6040518163ffffffff1660e01b81526004016101406040518083038186803b15801561467c57600080fd5b505afa158015614690573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146b49190614f52565b61012001519052604080517fdc1f2cd800000000000000000000000000000000000000000000000000000000815282516004820152602083015160248201529082015160448201526060820151606482015260808201516084820152909150730052a341bea99c4b452816235fc2216143c5f21c9063dc1f2cd89060a401604080518083038186803b15801561474957600080fd5b505af415801561475d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147819190614fd9565b50979650505050505050565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611e385760405162461bcd60e51b815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610985565b60405180610180016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000600481111561487e5761487e614aed565b81526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681525090565b600080604083850312156148c357600080fd5b50508035926020909101359150565b6001600160a01b03811681146148e757600080fd5b50565b6000602082840312156148fc57600080fd5b81356133f6816148d2565b60006020828403121561491957600080fd5b5035919050565b60008060006060848603121561493557600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561496157600080fd5b833561496c816148d2565b9250602084013561497c816148d2565b929592945050506040919091013590565b600080604083850312156149a057600080fd5b82356149ab816148d2565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156149fb576149fb6149b9565b500190565b600082821015614a1257614a126149b9565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614a4957614a496149b9565b5060010190565b80518015158114614a6057600080fd5b919050565b60008060408385031215614a7857600080fd5b82519150614a8860208401614a50565b90509250929050565b600060208284031215614aa357600080fd5b6133f682614a50565b600060208284031215614abe57600080fd5b5051919050565b8051614a60816148d2565b600060208284031215614ae257600080fd5b81516133f6816148d2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110614b53577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b81516001600160a01b0316815261018081016020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c0830151614bad60c0840182614b1c565b5060e08381015190830152610100808401519083015261012080840151908301526101408084015190830152610160928301516001600160a01b0316929091019190915290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715614c4657614c46614bf4565b60405290565b604051610120810167ffffffffffffffff81118282101715614c4657614c46614bf4565b604051610140810167ffffffffffffffff81118282101715614c4657614c46614bf4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614cdb57614cdb614bf4565b604052919050565b6000610100808385031215614cf757600080fd5b6040519081019067ffffffffffffffff82118183101715614d1a57614d1a614bf4565b8160405283519150614d2b826148d2565b81815260208401516020820152614d4460408501614ac5565b6040820152606084015160608201526080840151608082015260a084015160a082015260c084015160c0820152614d7d60e08501614ac5565b60e0820152949350505050565b600060a08284031215614d9c57600080fd5b614da4614c23565b9050815181526020808301518183015260408301516040830152614dca60608401614a50565b6060830152608083015167ffffffffffffffff80821115614dea57600080fd5b818501915085601f830112614dfe57600080fd5b815181811115614e1057614e10614bf4565b8060051b9150614e21848301614c94565b8181529183018401918481019088841115614e3b57600080fd5b938501935b83851015614e5957845182529385019390850190614e40565b608087015250939695505050505050565b600080828403610140811215614e7f57600080fd5b61012080821215614e8f57600080fd5b614e97614c4c565b9150845182526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e08301526101008086015181840152508193508085015191505067ffffffffffffffff811115614f0e57600080fd5b614f1a85828601614d8a565b9150509250929050565b600080600060608486031215614f3957600080fd5b8351925060208401519150604084015190509250925092565b60006101408284031215614f6557600080fd5b614f6d614c70565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152508091505092915050565b60008060408385031215614fec57600080fd5b505080516020909101519092909150565b60007f800000000000000000000000000000000000000000000000000000000000000082141561502f5761502f6149b9565b506000039056fea26469706673582212209d64b807adb35d317264c56167137a0c4c4c88d5a7bba2cbef2295c46501ced164736f6c634300080900330000000000000000000000008c6f28f2f1a3c87f0f938b96d27520d9751ec8d90000000000000000000000004beffd38832b5f158d5a05d374ae971dd0e326f20000000000000000000000001d42a98848e022908069c2c545ae44cc78509bc8000000000000000000000000f86048dff23cf130107dfb4e6386f574231a5c65000000000000000000000000cce7819d65f348c64b7beb205ba367b3fe33763b000000000000000000000000cfdff4e171133d55de2e45c66a0e144a135d93f2000000000000000000000000bb3e8eac35e649ed1071a9ec42223d474e67b19a00000000000000000000000022602469d704bffb0936c7a7cfcd18f7aa2693757345544800000000000000000000000000000000000000000000000000000000734554482047616d6d61205661756c7400000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008c6f28f2f1a3c87f0f938b96d27520d9751ec8d90000000000000000000000004beffd38832b5f158d5a05d374ae971dd0e326f20000000000000000000000001d42a98848e022908069c2c545ae44cc78509bc8000000000000000000000000f86048dff23cf130107dfb4e6386f574231a5c65000000000000000000000000cce7819d65f348c64b7beb205ba367b3fe33763b000000000000000000000000cfdff4e171133d55de2e45c66a0e144a135d93f2000000000000000000000000bb3e8eac35e649ed1071a9ec42223d474e67b19a00000000000000000000000022602469d704bffb0936c7a7cfcd18f7aa2693757345544800000000000000000000000000000000000000000000000000000000734554482047616d6d61205661756c7400000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _susd (address): 0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9
Arg [1] : _vaultToken (address): 0x4bEFFd38832b5F158d5a05D374AE971DD0e326F2
Arg [2] : _optionMarket (address): 0x1d42a98848e022908069c2c545aE44Cc78509Bc8
Arg [3] : _futuresMarket (address): 0xf86048DFf23cF130107dfB4e6386f574231a5C65
Arg [4] : _optionMarketWrapper (address): 0xCCE7819d65f348c64B7Beb205BA367b3fE33763B
Arg [5] : _optionToken (address): 0xCfDfF4E171133D55dE2e45c66a0E144a135D93f2
Arg [6] : _greeks (address): 0xbb3e8Eac35e649ed1071A9Ec42223d474e67b19A
Arg [7] : _rates (address): 0x22602469d704BfFb0936c7A7cfcD18f7aA269375
Arg [8] : _underlyingKey (bytes32): 0x7345544800000000000000000000000000000000000000000000000000000000
Arg [9] : _name (bytes32): 0x734554482047616d6d61205661756c7400000000000000000000000000000000
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 0000000000000000000000008c6f28f2f1a3c87f0f938b96d27520d9751ec8d9
Arg [1] : 0000000000000000000000004beffd38832b5f158d5a05d374ae971dd0e326f2
Arg [2] : 0000000000000000000000001d42a98848e022908069c2c545ae44cc78509bc8
Arg [3] : 000000000000000000000000f86048dff23cf130107dfb4e6386f574231a5c65
Arg [4] : 000000000000000000000000cce7819d65f348c64b7beb205ba367b3fe33763b
Arg [5] : 000000000000000000000000cfdff4e171133d55de2e45c66a0e144a135d93f2
Arg [6] : 000000000000000000000000bb3e8eac35e649ed1071a9ec42223d474e67b19a
Arg [7] : 00000000000000000000000022602469d704bffb0936c7a7cfcd18f7aa269375
Arg [8] : 7345544800000000000000000000000000000000000000000000000000000000
Arg [9] : 734554482047616d6d61205661756c7400000000000000000000000000000000
Deployed ByteCode Sourcemap
76377:35759:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94240:82;;;:::i;:::-;;78011:29;;;;;;;;160:25:1;;;148:2;133:18;78011:29:0;;;;;;;;80436:41;;;;;;95104:470;;;;;;:::i;:::-;;:::i;2109:151::-;;;;;;:::i;:::-;;:::i;80577:24::-;;;;;;78186:27;;;;;;;;-1:-1:-1;;;;;1358:55:1;;;1340:74;;1328:2;1313:18;78186:27:0;1181:239:1;80090:36:0;;;;;;95969:172;;;;;;:::i;:::-;;:::i;96929:151::-;;;;;;:::i;:::-;;:::i;79524:23::-;;;;;;93745:161;;;;;;:::i;:::-;;:::i;86272:2468::-;;;;;;:::i;:::-;;:::i;79287:30::-;;;;;;79588:28;;;;;-1:-1:-1;;;;;79588:28:0;;;94365:70;;;:::i;78265:50::-;;;;;79976:37;;;;;;80766:32;;;;;;;;;;;;;;;;;;;;;;;;;;2388:25:1;;;2444:2;2429:18;;2422:34;;;;2472:18;;;2465:34;;;;2530:2;2515:18;;2508:34;2573:3;2558:19;;2551:35;2617:3;2602:19;;2595:35;2375:3;2360:19;80766:32:0;2101:535:1;94680:288:0;;;;;;:::i;:::-;;:::i;89063:634::-;;;:::i;85219:925::-;;;;;;:::i;:::-;;:::i;79891:34::-;;;;;;24846:86;24917:7;;;;24846:86;;;2806:14:1;;2799:22;2781:41;;2769:2;2754:18;24846:86:0;2641:187:1;93307:199:0;;;;;;:::i;:::-;;:::i;24940:102::-;25019:15;;;;;;;24940:102;;94477:86;;;:::i;79128:31::-;;;;;;78554:68;;;;;96571:276;;;;;;:::i;:::-;;:::i;97190:244::-;;;;;;:::i;:::-;;:::i;78851:37::-;;;;;1659:442;;;;;;:::i;:::-;;:::i;80902:54::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;80902:54:0;;;;;;;;;;;;;4205:25:1;;;-1:-1:-1;;;;;4266:55:1;;;4261:2;4246:18;;4239:83;4338:18;;;4331:34;;;;4396:2;4381:18;;4374:34;4439:3;4424:19;;4417:35;4192:3;4177:19;80902:54:0;3946:512:1;94134:66:0;;;:::i;79659:29::-;;;;;;80835:27;;;;;-1:-1:-1;;;;;80835:27:0;;;80319:39;;;;;;79729:28;;;;;;78110:45;;;;;680:20;;;;;-1:-1:-1;;;;;680:20:0;;;79208:31;;;;;;80515:25;;;;;;97816:184;;;;;;:::i;:::-;;:::i;78360:44::-;;;;;709:26;;;;;-1:-1:-1;;;;;709:26:0;;;96240:172;;;;;;:::i;:::-;;:::i;89766:132::-;;;:::i;80999:58::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;80999:58:0;;;;;;;;;83995:1102;;;;;;:::i;:::-;;:::i;95682:188::-;;;;;;:::i;:::-;;:::i;78455:46::-;;;;;79437:25;;;;;;78666:42;;;;;78759:41;;;;;80697:29;;;;;;;;;82385:1232;;;;;;:::i;:::-;;:::i;97442:165::-;;;;;;:::i;:::-;;:::i;79807:36::-;;;;;;80201:38;;;;;;79368:31;;;;;;94240:82;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;;;;;;;;;94298:16:::1;:14;:16::i;:::-;94240:82::o:0;95104:470::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;95225:4:::1;95207:15;:22;:47;;;;95250:4;95233:14;:21;95207:47;95203:162;;;95290:14;::::0;95306:13:::1;::::0;95278:75:::1;::::0;::::1;::::0;;::::1;::::0;::::1;7784:25:1::0;;;;7825:18;;;7818:34;7868:18;;;7861:34;;;7911:18;;;7904:34;;;7756:19;;95278:75:0::1;7553:391:1::0;95203:162:0::1;95407:14;::::0;95423:13:::1;::::0;95382:98:::1;::::0;;7784:25:1;;;7840:2;7825:18;;7818:34;;;;7868:18;;7861:34;;;7926:2;7911:18;;7904:34;;;95382:98:0::1;::::0;7771:3:1;7756:19;95382:98:0::1;;;;;;;95493:14;:32:::0;;;;95536:13:::1;:30:::0;95104:470::o;2109:151::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;2184:5:::1;:16:::0;;;::::1;-1:-1:-1::0;;;;;2184:16:0;::::1;::::0;;::::1;::::0;;2218:34:::1;::::0;2184:16;;2231:10:::1;::::0;2218:34:::1;::::0;2184:5;2218:34:::1;2109:151:::0;:::o;95969:172::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;96070:16:::1;::::0;96053:43:::1;::::0;;8123:25:1;;;8179:2;8164:18;;8157:34;;;96053:43:0::1;::::0;8096:18:1;96053:43:0::1;;;;;;;96107:16;:26:::0;95969:172::o;96929:151::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;97023:10:::1;::::0;97006:36:::1;::::0;;8123:25:1;;;8179:2;8164:18;;8157:34;;;97006:36:0::1;::::0;8096:18:1;97006:36:0::1;;;;;;;97053:10;:19:::0;96929:151::o;93745:161::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;18530:6:::1;;18540:1;18530:11;18522:34;;;::::0;-1:-1:-1;;;18522:34:0;;8404:2:1;18522:34:0::1;::::0;::::1;8386:21:1::0;8443:2;8423:18;;;8416:30;8482:12;8462:18;;;8455:40;8512:18;;18522:34:0::1;8202:334:1::0;18522:34:0::1;18578:1;18569:10:::0;;24917:7;;;;25086:56:::2;;;25122:8;;;;;;;;;;;;;;25086:56;93864:34:::3;93879:6;93887:10;93864:14;:34::i;:::-;-1:-1:-1::0;;18615:1:0::1;18606:6;:10:::0;93745:161::o;86272:2468::-;18530:6;;18540:1;18530:11;18522:34;;;;-1:-1:-1;;;18522:34:0;;8404:2:1;18522:34:0;;;8386:21:1;8443:2;8423:18;;;8416:30;8482:12;8462:18;;;8455:40;8512:18;;18522:34:0;8202:334:1;18522:34:0;18578:1;18569:10;;86359:9:::1;86354:2379;86378:7;86374:1;:11;86354:2379;;;86407:18;86428:15;:13;:15::i;:::-;86509:20;::::0;86460:30:::1;86493:37:::0;;;:15:::1;:37;::::0;;;;86551:21:::1;::::0;::::1;::::0;86407:36;;-1:-1:-1;86493:37:0;86551:26;;:88:::1;;;86623:16;;86599:7;:21;;;:40;;;;:::i;:::-;86581:15;:58;86551:88;86547:135;;;86660:7;;;;;86547:135;86698:22;86736:9;;86723:10;;:22;;;;:::i;:::-;86698:47:::0;-1:-1:-1;86766:19:0;86762:66:::1;;86806:7;;;;;;86762:66;86867:23;::::0;::::1;::::0;86844:20:::1;::::0;86867:46:::1;::::0;86902:10;86867:34:::1;:46::i;:::-;86844:69;;87072:14;87057:12;:29;87053:1630;;;87107:22;::::0;::::1;:39:::0;;;87165:20:::1;87188:35;87132:14:::0;87212:10;87188:23:::1;:35::i;:::-;87165:58;;87270:12;87244:22;;:38;;;;;;;:::i;:::-;;;;;;;;87328:12;87301:7;:23;;;:39;;;;;;;:::i;:::-;;;;;;;;87375:14;87361:10;;:28;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;87414:13:0::1;::::0;:17;87410:251:::1;;87456:20;87479:40;87505:13;;87479:14;:25;;:40;;;;:::i;:::-;87560:13;::::0;87456:63;;-1:-1:-1;87542:46:0::1;::::0;-1:-1:-1;;;;;87542:4:0::1;:17:::0;::::1;::::0;87560:13:::1;87456:63:::0;87542:17:::1;:46::i;:::-;87611:30;87629:12:::0;87611:30;::::1;:::i;:::-;;;87433:228;87410:251;87699:12;::::0;::::1;::::0;87681:47:::1;::::0;-1:-1:-1;;;;;87681:4:0::1;:17:::0;::::1;::::0;87699:12:::1;87713:14:::0;87681:17:::1;:47::i;:::-;87803:10:::0;;87815:12:::1;::::0;::::1;::::0;87859:21:::1;::::0;::::1;::::0;87754:145:::1;::::0;;4205:25:1;;;-1:-1:-1;;;;;87815:12:0;;::::1;4261:2:1::0;4246:18;;4239:83;4338:18;;;4331:34;;;4396:2;4381:18;;4374:34;;;4439:3;4424:19;;4417:35;87754:145:0;::::1;::::0;;;;4192:3:1;87754:145:0;;::::1;87918:7;;;;;;;;87053:1630;87965:22;::::0;::::1;:37:::0;;;88047:23:::1;::::0;::::1;::::0;88021:22:::1;:49:::0;;:22:::1;::::0;:49:::1;::::0;88047:23;;88021:49:::1;:::i;:::-;::::0;;;-1:-1:-1;;88115:1:0::1;88089:23;::::0;::::1;:27:::0;;;88137:10:::1;:26:::0;;88151:12;;88115:1;88137:26:::1;::::0;88151:12;;88137:26:::1;:::i;:::-;::::0;;;-1:-1:-1;;88188:13:0::1;::::0;:17;88184:247:::1;;88230:20;88253:38;88277:13;;88253:12;:23;;:38;;;;:::i;:::-;88332:13;::::0;88230:61;;-1:-1:-1;88314:46:0::1;::::0;-1:-1:-1;;;;;88314:4:0::1;:17:::0;::::1;::::0;88332:13:::1;88230:61:::0;88314:17:::1;:46::i;:::-;88383:28;88399:12:::0;88383:28;::::1;:::i;:::-;;;88207:224;88184:247;88469:12;::::0;::::1;::::0;88451:45:::1;::::0;-1:-1:-1;;;;;88451:4:0::1;:17:::0;::::1;::::0;88469:12:::1;88483::::0;88451:17:::1;:45::i;:::-;88562:10:::0;;88574:12:::1;::::0;::::1;::::0;88588:23:::1;::::0;::::1;::::0;88627:21:::1;::::0;::::1;::::0;88522:145:::1;::::0;;4205:25:1;;;-1:-1:-1;;;;;88574:12:0;;::::1;4261:2:1::0;4246:18;;4239:83;4338:18;;;4331:34;4396:2;4381:18;;4374:34;;;4439:3;4424:19;;4417:35;88522:145:0::1;::::0;4192:3:1;4177:19;88522:145:0::1;;;;;;;88699:20;:22:::0;;;:20:::1;:22;::::0;::::1;:::i;:::-;;;;;;86392:2341;;;;86387:3;;;;;:::i;:::-;;;;86354:2379;;18592:1;-1:-1:-1::0;18615:1:0;18606:6;:10;86272:2468::o;94365:70::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;94417:10:::1;:8;:10::i;94680:288::-:0;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;-1:-1:-1;;;;;94767:30:0;::::1;94763:87;;94821:17;;;;;;;;;;;;;;94763:87;94887:13;::::0;94867:50:::1;::::0;;-1:-1:-1;;;;;94887:13:0;;::::1;9428:34:1::0;;9498:15;;;9493:2;9478:18;;9471:43;94867:50:0::1;::::0;9340:18:1;94867:50:0::1;;;;;;;94930:13;:30:::0;;;::::1;-1:-1:-1::0;;;;;94930:30:0;;;::::1;::::0;;;::::1;::::0;;94680:288::o;89063:634::-;89109:7;89133:10;;89147:1;89133:15;89129:59;;;-1:-1:-1;89172:4:0;;89063:634::o;89129:59::-;89200:19;89222:16;:14;:16::i;:::-;89253:25;;89200:38;;-1:-1:-1;89249:104:0;;89307:10;;:34;;89329:11;89307:21;:34::i;:::-;89300:41;;;89063:634;:::o;89249:104::-;89366:19;89391:42;89411:12;:21;;;89391:19;:42::i;:::-;-1:-1:-1;89470:45:0;;;;;89509:4;89470:45;;;1340:74:1;89365:68:0;;-1:-1:-1;89445:19:0;;-1:-1:-1;;;;;89470:14:0;:30;;;;1313:18:1;;89470:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;89444:71;;;89526:17;89598:11;89546:49;89569:12;:25;;;89546:11;:22;;:49;;;;:::i;:::-;:63;;;;:::i;:::-;89526:83;;89629:60;89677:11;89655:9;;89643;89630:10;;:22;;;;:::i;:::-;:34;;;;:::i;:::-;89629:47;;:60::i;:::-;89622:67;;;;;;89063:634;:::o;85219:925::-;18530:6;;18540:1;18530:11;18522:34;;;;-1:-1:-1;;;18522:34:0;;8404:2:1;18522:34:0;;;8386:21:1;8443:2;8423:18;;;8416:30;8482:12;8462:18;;;8455:40;8512:18;;18522:34:0;8202:334:1;18522:34:0;18578:1;18569:10;;85298:18:::1;85319:15;:13;:15::i;:::-;85298:36;;85352:9;85347:790;85371:7;85367:1;:11;85347:790;;;85445:17;::::0;85400:29:::1;85432:31:::0;;;:12:::1;:31;::::0;;;;85484:21:::1;::::0;::::1;::::0;:26;;:87:::1;;;85556:15;;85532:7;:21;;;:39;;;;:::i;:::-;85514:15;:57;85484:87;85480:134;;;85592:7;;;;;85480:134;85653:23;::::0;::::1;::::0;85630:20:::1;::::0;85653:46:::1;::::0;85688:10;85653:34:::1;:46::i;:::-;85630:69;;85739:12;85716:7;:20;;:35;;;;85789:7;:23;;;85766:19;;:46;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;85841:23:0::1;::::0;::::1;::::0;85827:10:::1;:37:::0;;:10:::1;::::0;:37:::1;::::0;85841:23;;85827:37:::1;:::i;:::-;::::0;;;-1:-1:-1;;85896:12:0::1;::::0;::::1;::::0;85879:44:::1;::::0;;;;-1:-1:-1;;;;;85896:12:0;;::::1;85879:44;::::0;::::1;10136:74:1::0;10226:18;;;10219:34;;;85879:11:0::1;:16:::0;;::::1;::::0;::::1;::::0;10109:18:1;;85879:44:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;85960:10:0;;85972:12:::1;::::0;::::1;::::0;85986:23:::1;::::0;::::1;::::0;86025:21:::1;::::0;::::1;::::0;85945:102:::1;::::0;;4205:25:1;;;-1:-1:-1;;;;;85972:12:0;;::::1;4261:2:1::0;4246:18;;4239:83;4338:18;;;4331:34;4396:2;4381:18;;4374:34;;;4439:3;4424:19;;4417:35;85945:102:0::1;::::0;-1:-1:-1;4192:3:1;4177:19;;-1:-1:-1;85945:102:0::1;;;;;;;86090:1;86064:23;::::0;::::1;:27:::0;;;86106:17:::1;:19:::0;;;::::1;::::0;::::1;:::i;:::-;;;;;;85385:752;;85380:3;;;;;:::i;:::-;;;;85347:790;;;;85287:857;-1:-1:-1::0;18615:1:0;18606:6;:10;85219:925::o;93307:199::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;18530:6:::1;;18540:1;18530:11;18522:34;;;::::0;-1:-1:-1;;;18522:34:0;;8404:2:1;18522:34:0::1;::::0;::::1;8386:21:1::0;8443:2;8423:18;;;8416:30;8482:12;8462:18;;;8455:40;8512:18;;18522:34:0::1;8202:334:1::0;18522:34:0::1;18578:1;18569:10:::0;;24917:7;;;;25086:56:::2;;;25122:8;;;;;;;;;;;;;;25086:56;93449:49:::3;93463:8;93473:6;93481:16;93449:13;:49::i;:::-;-1:-1:-1::0;;18615:1:0::1;18606:6;:10:::0;-1:-1:-1;93307:199:0:o;94477:86::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;94537:18:::1;:16;:18::i;96571:276::-:0;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;96688:15:::1;::::0;96720:16:::1;::::0;96675:78:::1;::::0;;7784:25:1;;;7840:2;7825:18;;7818:34;;;7868:18;;7861:34;7926:2;7911:18;;7904:34;;;96675:78:0::1;::::0;7771:3:1;7756:19;96675:78:0::1;;;;;;;96764:15;:31:::0;;;;96806:16:::1;:33:::0;96571:276::o;97190:244::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;97269:4:::1;97262;:11;:26;;;;97284:4;97277;:11;97262:26;97258:97;;;97328:8;::::0;97312:31:::1;::::0;::::1;::::0;;::::1;::::0;::::1;8123:25:1::0;;;;8164:18;;;8157:34;;;8096:18;;97312:31:0::1;7949:248:1::0;97258:97:0::1;97385:8;::::0;97370:30:::1;::::0;;8123:25:1;;;8179:2;8164:18;;8157:34;;;97370:30:0::1;::::0;8096:18:1;97370:30:0::1;;;;;;;97411:8;:15:::0;97190:244::o;1659:442::-;1933:5;;-1:-1:-1;;;;;1933:5:0;1919:10;:19;;:76;;-1:-1:-1;1942:9:0;;:53;;;;;1960:10;1942:53;;;10525:34:1;1980:4:0;10575:18:1;;;10568:43;1942:9:0;1987:7;;;10627:18:1;;;10620:107;-1:-1:-1;;;;;1942:9:0;;;;:17;;10437:18:1;;1942:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1911:85;;;;;;2009:9;:24;;;;-1:-1:-1;;;;;2009:24:0;;;;;;;;2051:42;;2068:10;;2051:42;;-1:-1:-1;;2051:42:0;1659:442;:::o;94134:66::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;94184:8:::1;:6;:8::i;97816:184::-:0;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;97939:4:::1;-1:-1:-1::0;;;;;97922:22:0::1;:5;-1:-1:-1::0;;;;;97922:22:0::1;;;97914:31;;;::::0;::::1;;97956:36;::::0;;;;-1:-1:-1;;;;;10154:55:1;;;97956:36:0::1;::::0;::::1;10136:74:1::0;10226:18;;;10219:34;;;97956:21:0;::::1;::::0;::::1;::::0;10109:18:1;;97956:36:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;97816:184:::0;;;:::o;96240:172::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;96341:16:::1;::::0;96324:43:::1;::::0;;8123:25:1;;;8179:2;8164:18;;8157:34;;;96324:43:0::1;::::0;8096:18:1;96324:43:0::1;;;;;;;96378:16;:26:::0;96240:172::o;89766:132::-;89813:7;89868:22;;89840:11;-1:-1:-1;;;;;89840:23:0;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:50;;;;:::i;:::-;89833:57;;89766:132;:::o;83995:1102::-;18530:6;;18540:1;18530:11;18522:34;;;;-1:-1:-1;;;18522:34:0;;8404:2:1;18522:34:0;;;8386:21:1;8443:2;8423:18;;;8416:30;8482:12;8462:18;;;8455:40;8512:18;;18522:34:0;8202:334:1;18522:34:0;18578:1;18569:10;;-1:-1:-1;;;;;84090:20:0;::::1;84086:77;;84134:17;;;;;;;;;;;;;;84086:77;84210:25:::0;;84206:835:::1;;84257:18;84278:15;:13;:15::i;:::-;84257:36:::0;-1:-1:-1;84308:20:0::1;84331:29;:6:::0;84257:36;84331:17:::1;:29::i;:::-;84308:52:::0;-1:-1:-1;84375:37:0::1;-1:-1:-1::0;;;;;84375:4:0::1;:17;84393:4:::0;84308:52;84375:17:::1;:37::i;:::-;84441:12;84427:10;;:26;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;84473:65:0::1;::::0;;84491:1:::1;4205:25:1::0;;-1:-1:-1;;;;;4266:55:1;;4261:2;4246:18;;4239:83;4338:18;;;4331:34;;;4396:2;4381:18;;4374:34;;;84522:15:0::1;4439:3:1::0;4424:19;;4417:35;84473:65:0::1;::::0;4192:3:1;4177:19;84473:65:0::1;;;;;;;84242:308;;84206:835;;;84672:22;::::0;;84619:34:::1;84656:39:::0;;;:15:::1;:39;::::0;;;;;84672:22;84729:24:::1;84672:22:::0;84729:24:::1;:::i;:::-;::::0;;;-1:-1:-1;84712:41:0;;84768:16:::1;::::0;::::1;:23:::0;;;::::1;-1:-1:-1::0;;;;;84768:23:0;::::1;;::::0;;84806:27:::1;::::0;::::1;:36:::0;;;84885:15:::1;84857:25;::::0;::::1;:43:::0;84917:22:::1;:32:::0;;84806:36;;84917:22;-1:-1:-1;;84917:32:0::1;::::0;84806:36;;84917:32:::1;:::i;:::-;::::0;;;-1:-1:-1;;84988:14:0;;84969:60:::1;::::0;;11890:25:1;;;85004:10:0::1;12007:2:1::0;11992:18;;11985:43;-1:-1:-1;;;;;12064:15:1;;12044:18;;;12037:43;12111:2;12096:18;;12089:34;;;84969:60:0;::::1;::::0;;;;11877:3:1;84969:60:0;;::::1;84556:485;84206:835;85053:36;::::0;;;;85070:10:::1;85053:36;::::0;::::1;10136:74:1::0;10226:18;;;10219:34;;;85053:11:0::1;-1:-1:-1::0;;;;;85053:16:0::1;::::0;::::1;::::0;10109:18:1;;85053:36:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;18615:1:0;18606:6;:10;-1:-1:-1;;;;83995:1102:0:o;95682:188::-;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;95793:21:::1;::::0;95765:57:::1;::::0;;8123:25:1;;;8179:2;8164:18;;8157:34;;;95765:57:0::1;::::0;8096:18:1;95765:57:0::1;;;;;;;95833:21;:29:::0;95682:188::o;82385:1232::-;18530:6;;18540:1;18530:11;18522:34;;;;-1:-1:-1;;;18522:34:0;;8404:2:1;18522:34:0;;;8386:21:1;8443:2;8423:18;;;8416:30;8482:12;8462:18;;;8455:40;8512:18;;18522:34:0;8202:334:1;18522:34:0;18578:1;18569:10;;25019:15;;;;;;;25333:71:::1;;;25376:16;;;;;;;;;;;;;;25333:71;-1:-1:-1::0;;;;;82499:20:0;::::2;82495:77;;82543:17;;;;;;;;;;;;;;82495:77;82597:16;;82588:6;:25;82584:113;;;82660:16;::::0;;82637:48:::2;::::0;::::2;::::0;;;;::::2;8123:25:1::0;8164:18;;;8157:34;;;8096:18;;82637:48:0::2;7949:248:1::0;82584:113:0::2;82744:25:::0;;82740:801:::2;;82791:18;82812:15;:13;:15::i;:::-;82791:36:::0;-1:-1:-1;82842:20:0::2;82865:29;:6:::0;82791:36;82865:17:::2;:29::i;:::-;82909:36;::::0;;;;-1:-1:-1;;;;;10154:55:1;;;82909:36:0::2;::::0;::::2;10136:74:1::0;10226:18;;;10219:34;;;82842:52:0;;-1:-1:-1;82909:11:0::2;:16:::0;;::::2;::::0;::::2;::::0;10109:18:1;;82909:36:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;82974:6;82960:10;;:20;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;83000:62:0::2;::::0;;83015:1:::2;4205:25:1::0;;-1:-1:-1;;;;;4266:55:1;;4261:2;4246:18;;4239:83;4338:18;;;4331:34;;;4396:2;4381:18;;4374:34;;;83046:15:0::2;4439:3:1::0;4424:19;;4417:35;83000:62:0::2;::::0;4192:3:1;4177:19;83000:62:0::2;;;;;;;82776:298;;82740:801;;;83189:19;::::0;;83141:32:::2;83176:33:::0;;;:12:::2;:33;::::0;;;;;83189:19;83242:21:::2;83189:19:::0;83242:21:::2;:::i;:::-;::::0;;;-1:-1:-1;83226:37:0;;83278:15:::2;::::0;::::2;:22:::0;;;::::2;-1:-1:-1::0;;;;;83278:22:0;::::2;;::::0;;83315:26:::2;::::0;::::2;:35:::0;;;83392:15:::2;83365:24;::::0;::::2;:42:::0;83424:19:::2;:29:::0;;83315:35;;83424:19;-1:-1:-1;;83424:29:0::2;::::0;83315:35;;83424:29:::2;:::i;:::-;::::0;;;-1:-1:-1;;83489:13:0;;83473:56:::2;::::0;;11890:25:1;;;83504:10:0::2;12007:2:1::0;11992:18;;11985:43;-1:-1:-1;;;;;12064:15:1;;12044:18;;;12037:43;12111:2;12096:18;;12089:34;;;83473:56:0;::::2;::::0;;;;11877:3:1;83473:56:0;;::::2;83080:461;82740:801;83553:56;-1:-1:-1::0;;;;;83553:4:0::2;:21;83575:10;83595:4;83602:6:::0;83553:21:::2;:56::i;97442:165::-:0;1025:33;1038:10;1050:7;;;;1025:12;:33::i;:::-;1017:58;;;;-1:-1:-1;;;1017:58:0;;7414:2:1;1017:58:0;;;7396:21:1;7453:2;7433:18;;;7426:30;7492:14;7472:18;;;7465:42;7524:18;;1017:58:0;7212:336:1;1017:58:0;97544:9:::1;::::0;97520:51:::1;::::0;;-1:-1:-1;;;;;97544:9:0;;::::1;9428:34:1::0;;9498:15;;;9493:2;9478:18;;9471:43;97520:51:0::1;::::0;9340:18:1;97520:51:0::1;;;;;;;97582:9;:17:::0;;;::::1;-1:-1:-1::0;;;;;97582:17:0;;;::::1;::::0;;;::::1;::::0;;97442:165::o;1105:546::-;1226:9;;1192:4;;-1:-1:-1;;;;;1226:9:0;1548:27;;;;;:77;;-1:-1:-1;1579:46:0;;;;;-1:-1:-1;;;;;10543:15:1;;;1579:46:0;;;10525:34:1;1606:4:0;10575:18:1;;;10568:43;10659:66;10647:79;;10627:18;;;10620:107;1579:12:0;;;;;10437:18:1;;1579:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1547:96;;;-1:-1:-1;1638:5:0;;-1:-1:-1;;;;;1630:13:0;;;1638:5;;1630:13;1547:96;1540:103;1105:546;-1:-1:-1;;;;1105:546:0:o;25735:151::-;25019:15;;;;;;;25333:71;;;25376:16;;;;;;;;;;;;;;25333:71;25811:15:::1;:22:::0;;;::::1;;;::::0;;25849:29:::1;::::0;25867:10:::1;1340:74:1::0;;25849:29:0::1;::::0;1328:2:1;1313:18;25849:29:0::1;;;;;;;;25735:151::o:0;100834:4361::-;100917:23;;100913:85;;100969:17;;;;;;;;;;;;;;100913:85;101011:17;101030:14;101048;-1:-1:-1;;;;;101048:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;101010:65;;;;101092:9;101105:1;101092:14;:27;;;;101110:9;101092:27;101088:101;;;101143:34;;;;;;;;12555:25:1;;;12623:14;;12616:22;12596:18;;;12589:50;12528:18;;101143:34:0;12387:258:1;101088:101:0;101206:17;;;;101201:75;;101240:17;:24;;;;101260:4;101240:24;;;101201:75;101317:23;;101292:49;;;;;-1:-1:-1;;;;;101353:21:0;101292:83;;;:12;:24;;;;;;:49;;;;160:25:1;;;148:2;133:18;;14:177;101292:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;101292:83:0;;101288:193;;101445:23;;101392:77;;;;;-1:-1:-1;;;;;101392:12:0;:20;;;;:77;;101421:21;;101392:77;;-1:-1:-1;;;;;10154:55:1;;;;10136:74;;10241:2;10226:18;;10219:34;10124:2;10109:18;;9962:297;101392:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;101288:193;101505:25;;101497:33;;101493:3695;;101547:17;:25;;;;;;101589:64;;:::i;:::-;-1:-1:-1;;;;;101692:13:0;101670:35;;;101738:12;:21;101720:15;;;:39;101794:23;;101774:17;;;:43;101852:1;101832:17;;;:21;-1:-1:-1;101958:17:0;;;:31;102020:25;;102004:13;;;:41;;;102077:37;;:11;;:22;:37::i;:::-;102060:14;;;:54;102146:17;102129:14;;;:34;-1:-1:-1;;;;;102238:4:0;102218:24;;:17;;;:24;102326:43;;;;;-1:-1:-1;;102326:21:0;:35;;;;:43;;102060:6;;102326:43;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;102435:24;;102462:21;;102386:98;;;;;102435:24;102386:98;;8123:25:1;;;;8164:18;;;8157:34;102259:110:0;;-1:-1:-1;102386:14:0;-1:-1:-1;;;;;102386:41:0;;;;8096:18:1;;102386:98:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;102597:45:0;;;;;102636:4;102597:45;;;1340:74:1;102572:19:0;;-1:-1:-1;102597:14:0;-1:-1:-1;;;;;102597:30:0;;-1:-1:-1;102597:30:0;;1313:18:1;;102597:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;102571:71;;;102659:14;-1:-1:-1;;;;;102659:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102710:21;102748:13;:23;;;102734:11;:37;;;;:::i;:::-;102710:61;;102808:9;;102792:13;:25;102788:381;;;102838:14;102871:9;;102855:13;:25;;;;:::i;:::-;102838:42;;102899:16;102918:33;102936:14;;102918:6;:17;;:33;;;;:::i;:::-;102995:13;;102899:52;;-1:-1:-1;102970:49:0;;-1:-1:-1;;;;;102976:4:0;102970:24;;;102995:13;102899:52;102970:24;:49::i;:::-;103053:17;103062:8;103053:6;:17;:::i;:::-;103038:10;;:33;;;;;;;:::i;:::-;;;;-1:-1:-1;102788:381:0;;-1:-1:-1;;;102788:381:0;;103139:13;103127:9;;:25;;;;:::i;:::-;103112:10;;:41;;;;;;;:::i;:::-;;;;-1:-1:-1;;102788:381:0;103222:12;:21;103262:23;;103304:25;;103348:23;;;;;103390:24;;103190:269;;;2388:25:1;;;2444:2;2429:18;;2422:34;;;;2472:18;;;2465:34;;;;2530:2;2515:18;;2508:34;2558:19;;2551:35;2617:3;2602:19;;2595:35;;;103190:269:0;;;;;;2375:3:1;103190:269:0;;;-1:-1:-1;;103488:1:0;103476:9;:13;;;103504:25;:29;;;103548:23;:27;;;103504:12;103590:25;;;103630:24;:28;;;103673:24;:28;;;103716:24;:28;-1:-1:-1;101493:3695:0;;-1:-1:-1;101493:3695:0;;103777:64;;:::i;:::-;-1:-1:-1;;;;;103880:13:0;103858:35;;;103926:12;:21;103908:15;;;:39;103982:23;;103962:17;;;:43;104040:1;104020:17;;;:21;-1:-1:-1;104146:17:0;;;:31;104192:13;;;:20;;;104244:28;:11;104192:20;104244:22;:28::i;:::-;104227:14;;;:45;104304:17;104287:14;;;:34;-1:-1:-1;;;;;104396:4:0;104376:24;;:17;;;:24;104484:43;;;;;-1:-1:-1;;104484:21:0;:35;;;;:43;;104227:6;;104484:43;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;104591:24;;104617:25;;104417:110;;-1:-1:-1;104544:28:0;;104575:68;;:4;;:15;:68::i;:::-;104732:21;;104660:94;;;;;;;;8123:25:1;;;8164:18;;;8157:34;;;;104544:99:0;;-1:-1:-1;104660:14:0;-1:-1:-1;;;;;104660:41:0;;;;8096:18:1;;104660:94:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;104808:12:0;:21;104848:23;;104913;;;;;104776:234;;;2388:25:1;;;2444:2;2429:18;;2422:34;;;;2472:18;;;2465:34;;;2530:2;2515:18;;2508:34;2558:19;;2551:35;;;-1:-1:-1;2617:3:1;2602:19;;2595:35;104776:234:0;;;-1:-1:-1;104776:234:0;;;;2375:3:1;104776:234:0;;-1:-1:-1;104776:234:0;105040:13;:23;;;105027:9;;:36;;;;;;;:::i;:::-;;;;-1:-1:-1;;105080:25:0;:33;;105109:4;;105080:25;;;:33;;105109:4;;105080:33;:::i;:::-;;;;-1:-1:-1;;105128:24:0;:48;;105156:20;;105128:24;;;:48;;105156:20;;105128:48;:::i;:::-;;;;-1:-1:-1;;;;;100902:4293:0;;100834:4361;;:::o;10525:166::-;10590:7;10617:21;10628:1;10631;10474:4;10617:10;:21::i;:::-;10610:28;10525:166;-1:-1:-1;;;10525:166:0:o;11041:160::-;11104:7;11131:19;11140:1;10474:4;11148:1;11131:8;:19::i;21576:1485::-;21693:12;21824:4;21818:11;21969:66;21950:17;21943:93;22084:2;22080:1;22061:17;22057:25;22050:37;22165:6;22160:2;22141:17;22137:26;22130:42;22977:2;22974:1;22970:2;22951:17;22948:1;22941:5;22934;22929:51;22493:16;22486:24;22480:2;22462:16;22459:24;22455:1;22451;22445:8;22442:15;22438:46;22435:76;22232:763;22221:774;;;23026:7;23018:35;;;;-1:-1:-1;;;23018:35:0;;18040:2:1;23018:35:0;;;18022:21:1;18079:2;18059:18;;;18052:30;18118:17;18098:18;;;18091:45;18153:18;;23018:35:0;17838:339:1;25894:155:0;24917:7;;;;25202:60;;25239:11;;;;;;;;;;;;;;25202:60;25953:7:::1;:15:::0;;25979:23;;;;26018::::1;::::0;26030:10:::1;1340:74:1::0;;26018:23:0::1;::::0;1328:2:1;1313:18;26018:23:0::1;1181:239:1::0;10867:166:0;10932:7;10959:21;10970:1;10474:4;10978:1;10959:10;:21::i;90221:1556::-;90292:19;90313:18;90359:34;90408:38;90460:13;-1:-1:-1;;;;;90460:31:0;;90492:9;90460:42;;;;;;;;;;;;;160:25:1;;148:2;133:18;;14:177;90460:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90561;;;;;90582:20;90561:42;;;160:25:1;90344:158:0;;-1:-1:-1;90344:158:0;-1:-1:-1;90524:17:0;;;;-1:-1:-1;;;;;90561:5:0;:20;;;;133:18:1;;90561:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90523:80;;;;90620:9;90633:1;90620:14;:27;;;;90638:9;90620:27;90616:68;;;90664:8;;;90616:68;90718:5;:12;;;90700:15;:30;90696:1074;;;90844:48;;;;;;;;160:25:1;;;90766:19:0;;;;-1:-1:-1;;;;;90844:13:0;:37;;;;133:18:1;;90844:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90747:145;;;;;90913:13;90930:1;90913:18;90909:83;;;90959:17;;;;;;;;;;;;;;90909:83;91038:11;91022:13;:27;:61;;91082:1;91022:61;;;91052:27;91068:11;91052:13;:27;:::i;:::-;91008:75;;90732:363;;90696:1074;;;91151:8;;91161:10;;91134:38;;;;;;;;8123:25:1;;;;8164:18;;;8157:34;91116:15:0;;91134:6;-1:-1:-1;;;;;91134:16:0;;;;8096:18:1;;91134:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91238:10;;91208:41;;;;;91116:56;;-1:-1:-1;91187:18:0;;-1:-1:-1;;;;;91208:6:0;:18;;;;:41;;91227:9;;91208:41;;8123:25:1;;;8179:2;8164:18;;8157:34;8111:2;8096:18;;7949:248;91208:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91187:62;;91264:49;91316:356;;;;;;;;91402:15;91387:5;:12;;;:30;;;;:::i;:::-;91316:356;;;;91455:30;:7;91474:10;91455:18;:30::i;:::-;91316:356;;;;91517:9;91316:356;;;;91565:6;:18;;;91316:356;;;;91615:6;-1:-1:-1;;;;;91615:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;91316:356;;91721:37;;;;;;21929:13:1;;91721:37:0;;;21911:32:1;21999:4;21987:17;;21981:24;21959:20;;;21952:54;22050:17;;;22044:24;22022:20;;;22015:54;22125:4;22113:17;;22107:24;22085:20;;;22078:54;22188:4;22176:17;;22170:24;22148:20;;;22141:54;91264:408:0;;-1:-1:-1;91721:15:0;;:28;;21883:19:1;;91721:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91693:65;;-1:-1:-1;91693:65:0;-1:-1:-1;;;;90696:1074:0;90333:1444;;;;90221:1556;;;:::o;98198:2628::-;98300:23;;:28;;;;:66;;-1:-1:-1;98332:12:0;:21;:34;;;98300:66;98299:89;;;-1:-1:-1;98371:17:0;;;;98299:89;98295:145;;;98412:16;;;;;;;;;;;;;;98295:145;98452:16;98471:23;98484:9;98471:12;:23::i;:::-;98452:42;;98523:4;98511:9;:16;:36;;;;98543:4;98531:9;:16;98511:36;98507:120;;;98571:44;;;;;;;;8123:25:1;;;8164:18;;;8157:34;;;8096:18;;98571:44:0;7949:248:1;98507:120:0;98640:17;98659:14;98677;-1:-1:-1;;;;;98677:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;98639:65;;;;98721:9;98734:1;98721:14;:27;;;;98739:9;98721:27;98717:101;;;98772:34;;;;;;;;12555:25:1;;;12623:14;;12616:22;12596:18;;;12589:50;12528:18;;98772:34:0;12387:258:1;98717:101:0;98830:22;98855:35;:4;98879:9;98855:15;:35::i;:::-;98830:60;;98901:22;98926:46;98952:9;98963:8;;98926:14;:25;;:46;;;;;:::i;:::-;98901:71;-1:-1:-1;98983:20:0;99006:23;99014:14;99006:23;:::i;:::-;98983:46;;99089:10;;99072:14;99058:11;99046:9;;:23;;;;:::i;:::-;:40;;;;:::i;:::-;:53;99042:163;;;99141:10;;99153:9;;99164:28;99178:14;99164:11;:28;:::i;:::-;99123:70;;;;;;;;22854:25:1;;;;22895:18;;;22888:34;;;;22938:18;;;22931:34;22827:18;;99123:70:0;22652:319:1;99042:163:0;99217:68;-1:-1:-1;;;;;99223:4:0;99217:23;99249:21;99273:11;99217:23;:68::i;:::-;99298:64;;:::i;:::-;99397:13;-1:-1:-1;;;;;99375:35:0;;;99421:15;;;:27;;;99479:23;;99459:17;;;:43;99533:1;99513:17;;;:21;-1:-1:-1;99627:17:0;;;-1:-1:-1;99627:31:0;;-1:-1:-1;99669:13:0;;;:20;;;99732:14;;;:28;;;99771:18;;;:32;;;-1:-1:-1;;;;;99834:4:0;99814:24;;:17;;;:24;99918:42;;;;;-1:-1:-1;;99918:21:0;:34;;;;:42;;99669:6;;99918:42;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;99973:53;;;;;;;;160:25:1;;;99851:109:0;;-1:-1:-1;99973:14:0;-1:-1:-1;;;;;99973:29:0;;;;133:18:1;;99973:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;100094:21:0;;100037:79;;;;;-1:-1:-1;;;;;100037:14:0;:41;;-1:-1:-1;100037:41:0;;-1:-1:-1;100037:79:0;;100079:13;;100037:79;;8123:25:1;;;8179:2;8164:18;;8157:34;8111:2;8096:18;;7949:248;100037:79:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;100133:23:0;;:28;100129:159;;-1:-1:-1;100129:159:0;;-1:-1:-1;100129:159:0;100204:24;;;;100178:23;:50;:12;100243:33;;;100129:159;100329:4;100300:12;:25;;;:33;;;;;;;:::i;:::-;;;;-1:-1:-1;;100372:23:0;;;;100344:24;:51;;:24;;:51;;100372:23;;100344:51;:::i;:::-;;;;-1:-1:-1;;100406:24:0;:42;;100434:14;;100406:24;;;:42;;100434:14;;100406:42;:::i;:::-;;;;-1:-1:-1;;100459:24:0;:42;;100487:14;;100459:24;;;:42;;100487:14;;100459:42;:::i;:::-;;;;-1:-1:-1;;100544:23:0;;;;100527:40;;:14;:40;:::i;:::-;100514:9;;:53;;;;;;;:::i;:::-;;;;-1:-1:-1;;100636:23:0;;100693;;;;;100585:233;;;23471:25:1;;;23527:2;23512:18;;23505:34;;;;23555:18;;23548:34;;;23613:2;23598:18;;23591:34;23641:19;;23634:35;;;23700:3;23685:19;;23678:35;;;23744:3;23729:19;;23722:35;;;100585:233:0;;23458:3:1;23443:19;100585:233:0;;;;;;;98284:2542;;;;;;;;98198:2628;;;:::o;26057:153::-;25019:15;;;;;;;25472:76;;25517:19;;;;;;;;;;;;;;25472:76;26132:15:::1;:23:::0;;;::::1;::::0;;26171:31:::1;::::0;26191:10:::1;1340:74:1::0;;26171:31:0::1;::::0;1328:2:1;1313:18;26171:31:0::1;1181:239:1::0;25575:152:0;24917:7;;;;25086:56;;;25122:8;;;;;;;;;;;;;;25086:56;25635:7:::1;:14:::0;;25660:22;;;;;;25698:21:::1;::::0;25708:10:::1;1340:74:1::0;;25698:21:0::1;::::0;1328:2:1;1313:18;25698:21:0::1;1181:239:1::0;19964:1604:0;20108:12;20239:4;20233:11;20384:66;20365:17;20358:93;20499:4;20495:1;20476:17;20472:25;20465:39;20584:2;20579;20560:17;20556:26;20549:38;20665:6;20660:2;20641:17;20637:26;20630:42;21479:2;21476:1;21471:3;21452:17;21449:1;21442:5;21435;21430:52;20993:16;20986:24;20980:2;20962:16;20959:24;20955:1;20951;20945:8;20942:15;20938:46;20935:76;20732:765;20721:776;;;21528:7;21520:40;;;;-1:-1:-1;;;21520:40:0;;23970:2:1;21520:40:0;;;23952:21:1;24009:2;23989:18;;;23982:30;24048:22;24028:18;;;24021:50;24088:18;;21520:40:0;23768:344:1;21520:40:0;20097:1471;19964:1604;;;;:::o;11405:552::-;11618:9;;;11752:19;;11745:27;11777:9;;11791;;;11788:16;;11774:31;11741:65;11731:123;;11837:1;11834;11827:12;11731:123;11920:19;;11405:552;-1:-1:-1;;11405:552:0:o;11965:771::-;12176:9;;;12310:19;;12303:27;12335:9;;12349;;;12346:16;;12332:31;12299:65;12289:123;;12395:1;12392;12385:12;12289:123;12715:1;12701:11;12697:1;12694;12690:9;12686:27;12682:35;12677:1;12670:9;12663:17;12659:59;12654:64;;11965:771;;;;;:::o;91900:923::-;91964:16;92008:34;92057:38;92109:13;-1:-1:-1;;;;;92109:31:0;;92141:9;92109:42;;;;;;;;;;;;;160:25:1;;148:2;133:18;;14:177;92109:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;92202;;;;;92223:20;92202:42;;;160:25:1;91993:158:0;;-1:-1:-1;91993:158:0;-1:-1:-1;92165:17:0;;;;-1:-1:-1;;;;;92202:5:0;:20;;;;133:18:1;;92202:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;92164:80;;;;92261:9;92274:1;92261:14;:27;;;;92279:9;92261:27;92257:101;;;92312:34;;;;;;;;12555:25:1;;;12623:14;;12616:22;12596:18;;;12589:50;12528:18;;92312:34:0;12387:258:1;92257:101:0;92370:49;92422:334;;;;;;;;92504:15;92489:5;:12;;;:30;;;;:::i;:::-;92422:334;;;;92553:32;92573:6;:11;;;92553:5;:8;;;:19;;:32;;;;:::i;:::-;92422:334;;;;92613:9;92422:334;;;;92657:6;:18;;;92422:334;;;;92703:6;-1:-1:-1;;;;;92703:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;92422:334;;92785:30;;;;;;21929:13:1;;92785:30:0;;;21911:32:1;21999:4;21987:17;;21981:24;21959:20;;;21952:54;22050:17;;;22044:24;22022:20;;;22015:54;22125:4;22113:17;;22107:24;22085:20;;;22078:54;22188:4;22176:17;;22170:24;22148:20;;;22141:54;92370:386:0;;-1:-1:-1;92785:15:0;;:21;;21883:19:1;;92785:30:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;92769:46:0;91900:923;-1:-1:-1;;;;;;;91900:923:0:o;23069:1483::-;23185:12;23316:4;23310:11;23461:66;23442:17;23435:93;23576:2;23572:1;23553:17;23549:25;23542:37;23657:6;23652:2;23633:17;23629:26;23622:42;24469:2;24466:1;24462:2;24443:17;24440:1;24433:5;24426;24421:51;23985:16;23978:24;23972:2;23954:16;23951:24;23947:1;23943;23937:8;23934:15;23930:46;23927:76;23724:763;23713:774;;;24518:7;24510:34;;;;-1:-1:-1;;;24510:34:0;;24567:2:1;24510:34:0;;;24549:21:1;24606:2;24586:18;;;24579:30;24645:16;24625:18;;;24618:44;24679:18;;24510:34:0;24365:338:1;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;378:248:1:-;446:6;454;507:2;495:9;486:7;482:23;478:32;475:52;;;523:1;520;513:12;475:52;-1:-1:-1;;546:23:1;;;616:2;601:18;;;588:32;;-1:-1:-1;378:248:1:o;631:154::-;-1:-1:-1;;;;;710:5:1;706:54;699:5;696:65;686:93;;775:1;772;765:12;686:93;631:154;:::o;790:247::-;849:6;902:2;890:9;881:7;877:23;873:32;870:52;;;918:1;915;908:12;870:52;957:9;944:23;976:31;1001:5;976:31;:::i;1425:180::-;1484:6;1537:2;1525:9;1516:7;1512:23;1508:32;1505:52;;;1553:1;1550;1543:12;1505:52;-1:-1:-1;1576:23:1;;1425:180;-1:-1:-1;1425:180:1:o;2833:316::-;2910:6;2918;2926;2979:2;2967:9;2958:7;2954:23;2950:32;2947:52;;;2995:1;2992;2985:12;2947:52;-1:-1:-1;;3018:23:1;;;3088:2;3073:18;;3060:32;;-1:-1:-1;3139:2:1;3124:18;;;3111:32;;2833:316;-1:-1:-1;2833:316:1:o;4712:456::-;4789:6;4797;4805;4858:2;4846:9;4837:7;4833:23;4829:32;4826:52;;;4874:1;4871;4864:12;4826:52;4913:9;4900:23;4932:31;4957:5;4932:31;:::i;:::-;4982:5;-1:-1:-1;5039:2:1;5024:18;;5011:32;5052:33;5011:32;5052:33;:::i;:::-;4712:456;;5104:7;;-1:-1:-1;;;5158:2:1;5143:18;;;;5130:32;;4712:456::o;5674:315::-;5742:6;5750;5803:2;5791:9;5782:7;5778:23;5774:32;5771:52;;;5819:1;5816;5809:12;5771:52;5858:9;5845:23;5877:31;5902:5;5877:31;:::i;:::-;5927:5;5979:2;5964:18;;;;5951:32;;-1:-1:-1;;;5674:315:1:o;8541:184::-;8593:77;8590:1;8583:88;8690:4;8687:1;8680:15;8714:4;8711:1;8704:15;8730:128;8770:3;8801:1;8797:6;8794:1;8791:13;8788:39;;;8807:18;;:::i;:::-;-1:-1:-1;8843:9:1;;8730:128::o;8863:125::-;8903:4;8931:1;8928;8925:8;8922:34;;;8936:18;;:::i;:::-;-1:-1:-1;8973:9:1;;8863:125::o;8993:195::-;9032:3;9063:66;9056:5;9053:77;9050:103;;;9133:18;;:::i;:::-;-1:-1:-1;9180:1:1;9169:13;;8993:195::o;9525:164::-;9601:13;;9650;;9643:21;9633:32;;9623:60;;9679:1;9676;9669:12;9623:60;9525:164;;;:::o;9694:263::-;9770:6;9778;9831:2;9819:9;9810:7;9806:23;9802:32;9799:52;;;9847:1;9844;9837:12;9799:52;9876:9;9870:16;9860:26;;9905:46;9947:2;9936:9;9932:18;9905:46;:::i;:::-;9895:56;;9694:263;;;;;:::o;10738:202::-;10805:6;10858:2;10846:9;10837:7;10833:23;10829:32;10826:52;;;10874:1;10871;10864:12;10826:52;10897:37;10924:9;10897:37;:::i;10945:184::-;11015:6;11068:2;11056:9;11047:7;11043:23;11039:32;11036:52;;;11084:1;11081;11074:12;11036:52;-1:-1:-1;11107:16:1;;10945:184;-1:-1:-1;10945:184:1:o;12650:138::-;12729:13;;12751:31;12729:13;12751:31;:::i;12793:251::-;12863:6;12916:2;12904:9;12895:7;12891:23;12887:32;12884:52;;;12932:1;12929;12922:12;12884:52;12964:9;12958:16;12983:31;13008:5;12983:31;:::i;13049:184::-;13101:77;13098:1;13091:88;13198:4;13195:1;13188:15;13222:4;13219:1;13212:15;13238:295;13320:1;13313:5;13310:12;13300:200;;13356:77;13353:1;13346:88;13457:4;13454:1;13447:15;13485:4;13482:1;13475:15;13300:200;13509:18;;13238:295::o;13538:1182::-;13787:13;;-1:-1:-1;;;;;1115:54:1;1103:67;;13748:3;13733:19;;13868:4;13860:6;13856:17;13850:24;13843:4;13832:9;13828:20;13821:54;13931:4;13923:6;13919:17;13913:24;13906:4;13895:9;13891:20;13884:54;13994:4;13986:6;13982:17;13976:24;13969:4;13958:9;13954:20;13947:54;14057:4;14049:6;14045:17;14039:24;14032:4;14021:9;14017:20;14010:54;14120:4;14112:6;14108:17;14102:24;14095:4;14084:9;14080:20;14073:54;14174:4;14166:6;14162:17;14156:24;14189:62;14245:4;14234:9;14230:20;14216:12;14189:62;:::i;:::-;-1:-1:-1;14307:4:1;14295:17;;;14289:24;14267:20;;;14260:54;14333:6;14381:15;;;14375:22;14355:18;;;14348:50;14417:6;14465:15;;;14459:22;14439:18;;;14432:50;14501:6;14549:15;;;14543:22;14523:18;;;14516:50;14585:6;14628:15;;;14622:22;-1:-1:-1;;;;;1115:54:1;14695:18;;;;1103:67;;;;13538:1182;:::o;14725:184::-;14777:77;14774:1;14767:88;14874:4;14871:1;14864:15;14898:4;14895:1;14888:15;14914:253;14986:2;14980:9;15028:4;15016:17;;15063:18;15048:34;;15084:22;;;15045:62;15042:88;;;15110:18;;:::i;:::-;15146:2;15139:22;14914:253;:::o;15172:255::-;15244:2;15238:9;15286:6;15274:19;;15323:18;15308:34;;15344:22;;;15305:62;15302:88;;;15370:18;;:::i;15432:252::-;15504:2;15498:9;15546:3;15534:16;;15580:18;15565:34;;15601:22;;;15562:62;15559:88;;;15627:18;;:::i;15689:334::-;15760:2;15754:9;15816:2;15806:13;;15821:66;15802:86;15790:99;;15919:18;15904:34;;15940:22;;;15901:62;15898:88;;;15966:18;;:::i;:::-;16002:2;15995:22;15689:334;;-1:-1:-1;15689:334:1:o;16028:1006::-;16129:6;16160:3;16204:2;16192:9;16183:7;16179:23;16175:32;16172:52;;;16220:1;16217;16210:12;16172:52;16253:2;16247:9;16283:15;;;;16328:18;16313:34;;16349:22;;;16310:62;16307:88;;;16375:18;;:::i;:::-;16415:10;16411:2;16404:22;16454:9;16448:16;16435:29;;16473:31;16498:5;16473:31;:::i;:::-;16528:5;16520:6;16513:21;16588:2;16577:9;16573:18;16567:25;16562:2;16554:6;16550:15;16543:50;16626:49;16671:2;16660:9;16656:18;16626:49;:::i;:::-;16621:2;16613:6;16609:15;16602:74;16730:2;16719:9;16715:18;16709:25;16704:2;16696:6;16692:15;16685:50;16790:3;16779:9;16775:19;16769:26;16763:3;16755:6;16751:16;16744:52;16851:3;16840:9;16836:19;16830:26;16824:3;16816:6;16812:16;16805:52;16912:3;16901:9;16897:19;16891:26;16885:3;16877:6;16873:16;16866:52;16952:50;16997:3;16986:9;16982:19;16952:50;:::i;:::-;16946:3;16934:16;;16927:76;16938:6;16028:1006;-1:-1:-1;;;;16028:1006:1:o;18182:1199::-;18251:5;18299:4;18287:9;18282:3;18278:19;18274:30;18271:50;;;18317:1;18314;18307:12;18271:50;18339:22;;:::i;:::-;18330:31;;18390:9;18384:16;18377:5;18370:31;18420:2;18475;18464:9;18460:18;18454:25;18449:2;18442:5;18438:14;18431:49;18533:2;18522:9;18518:18;18512:25;18507:2;18500:5;18496:14;18489:49;18570:46;18612:2;18601:9;18597:18;18570:46;:::i;:::-;18565:2;18558:5;18554:14;18547:70;18661:3;18650:9;18646:19;18640:26;18685:18;18726:2;18718:6;18715:14;18712:34;;;18742:1;18739;18732:12;18712:34;18780:6;18769:9;18765:22;18755:32;;18825:3;18818:4;18814:2;18810:13;18806:23;18796:51;;18843:1;18840;18833:12;18796:51;18872:2;18866:9;18894:2;18890;18887:10;18884:36;;;18900:18;;:::i;:::-;18946:2;18943:1;18939:10;18929:20;;18969:28;18993:2;18989;18985:11;18969:28;:::i;:::-;19031:15;;;19101:11;;;19097:20;;;19062:12;;;;19129:15;;;19126:35;;;19157:1;19154;19147:12;19126:35;19181:11;;;;19201:135;19217:6;19212:3;19209:15;19201:135;;;19283:10;;19271:23;;19234:12;;;;19314;;;;19201:135;;;19363:3;19352:15;;19345:30;-1:-1:-1;19356:5:1;;18182:1199;-1:-1:-1;;;;;;18182:1199:1:o;19386:1107::-;19518:6;19526;19570:9;19561:7;19557:23;19600:3;19596:2;19592:12;19589:32;;;19617:1;19614;19607:12;19589:32;19640:6;19666:2;19662;19658:11;19655:31;;;19682:1;19679;19672:12;19655:31;19708:22;;:::i;:::-;19695:35;;19759:9;19753:16;19746:5;19739:31;19823:2;19812:9;19808:18;19802:25;19797:2;19790:5;19786:14;19779:49;19881:2;19870:9;19866:18;19860:25;19855:2;19848:5;19844:14;19837:49;19939:2;19928:9;19924:18;19918:25;19913:2;19906:5;19902:14;19895:49;19998:3;19987:9;19983:19;19977:26;19971:3;19964:5;19960:15;19953:51;20058:3;20047:9;20043:19;20037:26;20031:3;20024:5;20020:15;20013:51;20118:3;20107:9;20103:19;20097:26;20091:3;20084:5;20080:15;20073:51;20178:3;20167:9;20163:19;20157:26;20151:3;20144:5;20140:15;20133:51;20203:3;20259:2;20248:9;20244:18;20238:25;20233:2;20226:5;20222:14;20215:49;;20283:5;20273:15;;20332:2;20321:9;20317:18;20311:25;20297:39;;;20359:18;20351:6;20348:30;20345:50;;;20391:1;20388;20381:12;20345:50;20414:73;20479:7;20470:6;20459:9;20455:22;20414:73;:::i;:::-;20404:83;;;19386:1107;;;;;:::o;20498:306::-;20586:6;20594;20602;20655:2;20643:9;20634:7;20630:23;20626:32;20623:52;;;20671:1;20668;20661:12;20623:52;20700:9;20694:16;20684:26;;20750:2;20739:9;20735:18;20729:25;20719:35;;20794:2;20783:9;20779:18;20773:25;20763:35;;20498:306;;;;;:::o;20809:870::-;20917:6;20970:3;20958:9;20949:7;20945:23;20941:33;20938:53;;;20987:1;20984;20977:12;20938:53;21013:22;;:::i;:::-;21064:9;21058:16;21051:5;21044:31;21128:2;21117:9;21113:18;21107:25;21102:2;21095:5;21091:14;21084:49;21186:2;21175:9;21171:18;21165:25;21160:2;21153:5;21149:14;21142:49;21244:2;21233:9;21229:18;21223:25;21218:2;21211:5;21207:14;21200:49;21303:3;21292:9;21288:19;21282:26;21276:3;21269:5;21265:15;21258:51;21363:3;21352:9;21348:19;21342:26;21336:3;21329:5;21325:15;21318:51;21423:3;21412:9;21408:19;21402:26;21396:3;21389:5;21385:15;21378:51;21483:3;21472:9;21468:19;21462:26;21456:3;21449:5;21445:15;21438:51;21508:3;21564:2;21553:9;21549:18;21543:25;21538:2;21531:5;21527:14;21520:49;;21588:3;21644:2;21633:9;21629:18;21623:25;21618:2;21611:5;21607:14;21600:49;;21668:5;21658:15;;;20809:870;;;;:::o;22206:245::-;22285:6;22293;22346:2;22334:9;22325:7;22321:23;22317:32;22314:52;;;22362:1;22359;22352:12;22314:52;-1:-1:-1;;22385:16:1;;22441:2;22426:18;;;22420:25;22385:16;;22420:25;;-1:-1:-1;22206:245:1:o;22456:191::-;22491:3;22522:66;22515:5;22512:77;22509:103;;;22592:18;;:::i;:::-;-1:-1:-1;22632:1:1;22628:13;;22456:191::o
Swarm Source
ipfs://9d64b807adb35d317264c56167137a0c4c4c88d5a7bba2cbef2295c46501ced1
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.