Contract 0xf92b8ad7a62437142c4bf87d91e2be0fe1f44e9f 2

Premia 
 

Contract Overview

Premia: IVOL Oracle Implementation
Balance:
0 ETH

ETH Value:
$0.00
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xaa5ac9fb1cb72ca4fb5ac4af320586ac5d3c9d103b95f383069c81111ea62cc00x6080604030076632021-11-13 4:06:35380 days 18 hrs ago0xc7f8d87734ab2cbf70030ac8aa82abfe3e8126cb IN  Create: VolatilitySurfaceOracle0 ETH0.119978582181 ETH
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x510baed61fbc34c70d1d9c3a3b61e356ac73cd19dea926f2935ddc4db41ea57846196942022-01-13 19:05:25319 days 3 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x2532455c37eb5b271592c379bd496c3280434d96eb01a3ca2ef69f471aba7cc246191152022-01-13 18:35:08319 days 4 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0xb10d13990290105287ddadf7ef19ba0c63904afb0b3a7309459e7917506be8c646185712022-01-13 18:04:36319 days 4 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x06d619f05dde0a59457d8cb01fd39bbeaf3080a048ae8050ecba5d00b0b3046946180822022-01-13 17:36:35319 days 5 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0xacb5416590e44bc7b84c0c4a4b191cdf85dad13448e5cb91b07e1179a4e3368046171162022-01-13 17:05:27319 days 5 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x4cd471bca1e81a1c06d824a3d97d555d9ff85c5cca253f6a1ac836a409e7ca8f46164522022-01-13 16:35:07319 days 6 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x2e1d2952b0d75bfe5d875ccbe019ba29ae2f06304117e1f5539dba9e5c1c2a1b46158072022-01-13 16:05:32319 days 6 hrs ago Premia: LINK Pool Premia: IVOL Oracle Implementation0 ETH
0x21731fad3390d3806f26e1cc618c0a067d8be7514e914b409acf2feb37e6d95946150322022-01-13 15:37:50319 days 7 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x7a5fbc4a844a71ec282cdafdc9447a2d576420df01c4b23e57f9ab8b0604415846139272022-01-13 15:05:40319 days 7 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x5c6406e5076231fb62fc73afaec14a9cff468a038c1021dd6b6bb8fbcd5aa63346132152022-01-13 14:35:31319 days 8 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0xaf3bd36efc141e4ef7e62a03ec0090c5ee164634c159ba614c5d6ade58969a2646129702022-01-13 14:24:46319 days 8 hrs ago Premia: LINK Pool Premia: IVOL Oracle Implementation0 ETH
0x4f372b1479fed9a726a9bb4b7562cafeb3c41fd7ff8d77d110d2a11c2bd9e4e846125922022-01-13 14:05:44319 days 8 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0xd23686374ee3d4ddb2d6696fbd4eb5e6297070f2a076197ca59a6adae7f9b24146120892022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x80fac9b9aa91fd90b960ff0bb335e23b759b7663ebd6f94d6d5288bd0bcb725146120882022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x274f3027dc18f109b821e6ce473331b0dcd43f58f84124f74e7d8ca467a8526746120872022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0xafe31b1b0bb5c462dfab8f1bac4fe5a5cd8c73b4a7af51a5e712b29e5f72554e46120862022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x2548b6056590ff7a20f9d12914f8dc080e6ea6b8cffa95299717dc18b91755a846120852022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x27662cdf7bd37658b33634c80d753364b1f8094fdbccb5066aeb95dce2446fb846120842022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0xf09d44e09f6599b033ca0e94c6aa99e5463a1a3af23a6190a354ab7b9f104c8d46120832022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0xe32788812efe07abb184744c81fad7c090400fefd0dc6b4776a27b667f4342b746120822022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x846e6a26bda6c3f8aa302366d6fefaee4b1db0181b6b5977bbcccfc2a1705a7546120812022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x0632c801cc5ff9a0cd408cd47d5f362f1e37bf5392258bcc104e2211ee99ec4046120802022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x04fe41b00f7b153805b7a255c8c2d65f0a0da1c25f029858770ce724034ac5cd46120792022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x7ec4a5d541bc8b20a6619225ab9335a106469d7ebead919a4cbe0c062c9a1ffb46120782022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
0x557166b3a136ccd09e7dbe7bf9a97bcb763018d6e15e34c19cca3c2b5f2db42846120772022-01-13 13:38:56319 days 9 hrs ago 0x52cca9613bc3f771dd58a3bd5627efb1a750d55a Premia: IVOL Oracle Implementation0 ETH
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VolatilitySurfaceOracle

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 8 : VolatilitySurfaceOracle.sol
// SPDX-License-Identifier: BUSL-1.1
// For further clarification please see https://license.premia.legal

pragma solidity ^0.8.0;

import {OwnableInternal, OwnableStorage} from "@solidstate/contracts/access/OwnableInternal.sol";
import {EnumerableSet} from "@solidstate/contracts/utils/EnumerableSet.sol";
import {ABDKMath64x64} from "abdk-libraries-solidity/ABDKMath64x64.sol";

import {OptionMath} from "../libraries/OptionMath.sol";
import {VolatilitySurfaceOracleStorage} from "./VolatilitySurfaceOracleStorage.sol";
import {IVolatilitySurfaceOracle} from "./IVolatilitySurfaceOracle.sol";

/**
 * @title Premia volatility surface oracle contract
 */
contract VolatilitySurfaceOracle is IVolatilitySurfaceOracle, OwnableInternal {
    using VolatilitySurfaceOracleStorage for VolatilitySurfaceOracleStorage.Layout;
    using EnumerableSet for EnumerableSet.AddressSet;
    using ABDKMath64x64 for int128;

    uint256 internal constant DECIMALS = 12;

    event UpdateCoefficients(
        address indexed baseToken,
        address indexed underlyingToken,
        bytes32 callCoefficients, // Coefficients must be packed using formatVolatilitySurfaceCoefficients
        bytes32 putCoefficients // Coefficients must be packed using formatVolatilitySurfaceCoefficients
    );

    /**
     * @notice Add relayer to the whitelist so that they can add oracle surfaces.
     * @param _addr The addresses to add to the whitelist
     */
    function addWhitelistedRelayer(address[] memory _addr) external onlyOwner {
        VolatilitySurfaceOracleStorage.Layout
            storage l = VolatilitySurfaceOracleStorage.layout();

        for (uint256 i = 0; i < _addr.length; i++) {
            l.whitelistedRelayers.add(_addr[i]);
        }
    }

    /**
     * @notice Remove relayer from the whitelist so that they cannot add oracle surfaces.
     * @param _addr The addresses to remove the whitelist
     */
    function removeWhitelistedRelayer(address[] memory _addr)
        external
        onlyOwner
    {
        VolatilitySurfaceOracleStorage.Layout
            storage l = VolatilitySurfaceOracleStorage.layout();

        for (uint256 i = 0; i < _addr.length; i++) {
            l.whitelistedRelayers.remove(_addr[i]);
        }
    }

    /**
     * @notice Get the list of whitelisted relayers
     * @return The list of whitelisted relayers
     */
    function getWhitelistedRelayers()
        external
        view
        override
        returns (address[] memory)
    {
        VolatilitySurfaceOracleStorage.Layout
            storage l = VolatilitySurfaceOracleStorage.layout();

        uint256 length = l.whitelistedRelayers.length();
        address[] memory result = new address[](length);

        for (uint256 i = 0; i < length; i++) {
            result[i] = l.whitelistedRelayers.at(i);
        }

        return result;
    }

    /**
     * @notice Get the volatility surface data of a token pair
     * @param baseToken The base token of the pair
     * @param underlyingToken The underlying token of the pair
     * @return The volatility surface data
     */
    function getVolatilitySurface(address baseToken, address underlyingToken)
        external
        view
        override
        returns (VolatilitySurfaceOracleStorage.Update memory)
    {
        VolatilitySurfaceOracleStorage.Layout
            storage l = VolatilitySurfaceOracleStorage.layout();
        return l.volatilitySurfaces[baseToken][underlyingToken];
    }

    /**
     * @notice Get unpacked volatility surface coefficients
     * @param baseToken The base token of the pair
     * @param underlyingToken The underlying token of the pair
     * @param isCall whether it is for call or put
     * @return The unpacked coefficients of the volatility surface
     */
    function getVolatilitySurfaceCoefficientsUnpacked(
        address baseToken,
        address underlyingToken,
        bool isCall
    ) external view override returns (int256[] memory) {
        VolatilitySurfaceOracleStorage.Layout
            storage l = VolatilitySurfaceOracleStorage.layout();

        bytes32 valuePacked = l.getCoefficients(
            baseToken,
            underlyingToken,
            isCall
        );

        return
            VolatilitySurfaceOracleStorage.parseVolatilitySurfaceCoefficients(
                valuePacked
            );
    }

    /**
     * @notice Get time to maturity in years, as a 64x64 fixed point representation
     * @param maturity Maturity timestamp
     * @return Time to maturity (in years), as a 64x64 fixed point representation
     */
    function getTimeToMaturity64x64(uint64 maturity)
        external
        view
        override
        returns (int128)
    {
        return ABDKMath64x64.divu(maturity - block.timestamp, 365 days);
    }

    /**
     * @notice Get annualized volatility as a 64x64 fixed point representation
     * @param baseToken The base token of the pair
     * @param underlyingToken The underlying token of the pair
     * @param spot64x64 The spot, as a 64x64 fixed point representation
     * @param strike64x64 The strike, as a 64x64 fixed point representation
     * @param timeToMaturity64x64 Time to maturity (in years), as a 64x64 fixed point representation
     * @param isCall whether it is for call or put
     * @return Annualized volatility, as a 64x64 fixed point representation. 1 = 100%
     */
    function getAnnualizedVolatility64x64(
        address baseToken,
        address underlyingToken,
        int128 spot64x64,
        int128 strike64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) public view override returns (int128) {
        VolatilitySurfaceOracleStorage.Layout
            storage l = VolatilitySurfaceOracleStorage.layout();
        int256[] memory volatilitySurface = VolatilitySurfaceOracleStorage
            .parseVolatilitySurfaceCoefficients(
                l.getCoefficients(baseToken, underlyingToken, isCall)
            );

        return
            _getAnnualizedVolatility64x64(
                spot64x64,
                strike64x64,
                timeToMaturity64x64,
                volatilitySurface
            );
    }

    function _getAnnualizedVolatility64x64(
        int128 spot64x64,
        int128 strike64x64,
        int128 timeToMaturity64x64,
        int256[] memory volatilitySurface
    ) internal pure returns (int128) {
        require(volatilitySurface.length == 5, "Invalid vol surface");

        // Time adjusted log moneyness
        int128 adjustedLogMoneyness64x64 = spot64x64.div(strike64x64).ln().div(
            timeToMaturity64x64.sqrt()
        );

        return
            _toCoefficient64x64(volatilitySurface[0]) +
            _toCoefficient64x64(volatilitySurface[1]).mul(
                adjustedLogMoneyness64x64
            ) +
            _toCoefficient64x64(volatilitySurface[2]).mul(
                adjustedLogMoneyness64x64.mul(adjustedLogMoneyness64x64)
            ) +
            _toCoefficient64x64(volatilitySurface[3]).mul(timeToMaturity64x64) +
            _toCoefficient64x64(volatilitySurface[4])
                .mul(adjustedLogMoneyness64x64)
                .mul(timeToMaturity64x64);
    }

    function _toCoefficient64x64(int256 value) internal pure returns (int128) {
        return ABDKMath64x64.divi(value, int256(10**DECIMALS));
    }

    function _getBlackScholesPrice64x64(
        address baseToken,
        address underlyingToken,
        int128 strike64x64,
        int128 spot64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) internal view returns (int128) {
        int128 annualizedVolatility = getAnnualizedVolatility64x64(
            baseToken,
            underlyingToken,
            strike64x64,
            spot64x64,
            timeToMaturity64x64,
            isCall
        );
        int128 annualizedVariance = annualizedVolatility.mul(
            annualizedVolatility
        );

        return
            OptionMath._blackScholesPrice(
                annualizedVariance,
                strike64x64,
                spot64x64,
                timeToMaturity64x64,
                isCall
            );
    }

    /**
     * @notice Get Black Scholes price as a 64x64 fixed point representation
     * @param baseToken The base token of the pair
     * @param underlyingToken The underlying token of the pair
     * @param strike64x64 Strike, as a64x64 fixed point representation
     * @param spot64x64 Spot price, as a 64x64 fixed point representation
     * @param timeToMaturity64x64 Time to maturity (in years), as a 64x64 fixed point representation
     * @param isCall Whether it is for call or put
     * @return Black scholes price, as a 64x64 fixed point representation
     */
    function getBlackScholesPrice64x64(
        address baseToken,
        address underlyingToken,
        int128 strike64x64,
        int128 spot64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) external view override returns (int128) {
        return
            _getBlackScholesPrice64x64(
                baseToken,
                underlyingToken,
                strike64x64,
                spot64x64,
                timeToMaturity64x64,
                isCall
            );
    }

    /**
     * @notice Get Black Scholes price as an uint256 with 18 decimals
     * @param baseToken The base token of the pair
     * @param underlyingToken The underlying token of the pair
     * @param strike64x64 Strike, as a64x64 fixed point representation
     * @param spot64x64 Spot price, as a 64x64 fixed point representation
     * @param timeToMaturity64x64 Time to maturity (in years), as a 64x64 fixed point representation
     * @param isCall Whether it is for call or put
     * @return Black scholes price, as an uint256 with 18 decimals
     */
    function getBlackScholesPrice(
        address baseToken,
        address underlyingToken,
        int128 strike64x64,
        int128 spot64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) external view override returns (uint256) {
        return
            _getBlackScholesPrice64x64(
                baseToken,
                underlyingToken,
                strike64x64,
                spot64x64,
                timeToMaturity64x64,
                isCall
            ).mulu(10**18);
    }

    /**
     * @notice Update a list of volatility surfaces
     * @param baseTokens List of base tokens
     * @param underlyingTokens List of underlying tokens
     * @param callCoefficients List of call coefficients
     * @param putCoefficients List of put coefficients
     */
    function updateVolatilitySurfaces(
        address[] memory baseTokens,
        address[] memory underlyingTokens,
        bytes32[] memory callCoefficients,
        bytes32[] memory putCoefficients
    ) external {
        uint256 length = baseTokens.length;
        require(
            length == underlyingTokens.length &&
                length == callCoefficients.length &&
                length == putCoefficients.length,
            "Wrong array length"
        );

        VolatilitySurfaceOracleStorage.Layout
            storage l = VolatilitySurfaceOracleStorage.layout();

        require(
            l.whitelistedRelayers.contains(msg.sender),
            "Relayer not whitelisted"
        );

        for (uint256 i = 0; i < length; i++) {
            l.volatilitySurfaces[baseTokens[i]][
                    underlyingTokens[i]
                ] = VolatilitySurfaceOracleStorage.Update({
                updatedAt: block.timestamp,
                callCoefficients: callCoefficients[i],
                putCoefficients: putCoefficients[i]
            });

            emit UpdateCoefficients(
                baseTokens[i],
                underlyingTokens[i],
                callCoefficients[i],
                putCoefficients[i]
            );
        }
    }

    /**
     * @notice Unpack volatility surface coefficients from a bytes43
     * @param input Packed volatility surface coefficients to unpack
     * @return coefficients The unpacked coefficients of the volatility surface
     */
    function parseVolatilitySurfaceCoefficients(bytes32 input)
        external
        pure
        returns (int256[] memory coefficients)
    {
        return
            VolatilitySurfaceOracleStorage.parseVolatilitySurfaceCoefficients(
                input
            );
    }

    /**
     * @notice Pack volatility surface coefficients into a single bytes32
     * @dev This function is used to pack the coefficients into a single variable, which is then used as input in `updateVolatilitySurfaces`
     * @param coefficients Coefficients of the volatility surface to pack
     * @return result The packed coefficients of the volatility surface
     */
    function formatVolatilitySurfaceCoefficients(int256[5] memory coefficients)
        external
        pure
        returns (bytes32 result)
    {
        return
            VolatilitySurfaceOracleStorage.formatVolatilitySurfaceCoefficients(
                coefficients
            );
    }
}

File 2 of 8 : OwnableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { OwnableStorage } from './OwnableStorage.sol';

abstract contract OwnableInternal {
    using OwnableStorage for OwnableStorage.Layout;

    modifier onlyOwner() {
        require(
            msg.sender == OwnableStorage.layout().owner,
            'Ownable: sender must be owner'
        );
        _;
    }
}

File 3 of 8 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Set implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableSet {
    struct Set {
        bytes32[] _values;
        // 1-indexed to allow 0 to signify nonexistence
        mapping(bytes32 => uint256) _indexes;
    }

    struct Bytes32Set {
        Set _inner;
    }

    struct AddressSet {
        Set _inner;
    }

    struct UintSet {
        Set _inner;
    }

    function at(Bytes32Set storage set, uint256 index)
        internal
        view
        returns (bytes32)
    {
        return _at(set._inner, index);
    }

    function at(AddressSet storage set, uint256 index)
        internal
        view
        returns (address)
    {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    function at(UintSet storage set, uint256 index)
        internal
        view
        returns (uint256)
    {
        return uint256(_at(set._inner, index));
    }

    function contains(Bytes32Set storage set, bytes32 value)
        internal
        view
        returns (bool)
    {
        return _contains(set._inner, value);
    }

    function contains(AddressSet storage set, address value)
        internal
        view
        returns (bool)
    {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    function contains(UintSet storage set, uint256 value)
        internal
        view
        returns (bool)
    {
        return _contains(set._inner, bytes32(value));
    }

    function indexOf(Bytes32Set storage set, bytes32 value)
        internal
        view
        returns (uint256)
    {
        return _indexOf(set._inner, value);
    }

    function indexOf(AddressSet storage set, address value)
        internal
        view
        returns (uint256)
    {
        return _indexOf(set._inner, bytes32(uint256(uint160(value))));
    }

    function indexOf(UintSet storage set, uint256 value)
        internal
        view
        returns (uint256)
    {
        return _indexOf(set._inner, bytes32(value));
    }

    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function add(Bytes32Set storage set, bytes32 value)
        internal
        returns (bool)
    {
        return _add(set._inner, value);
    }

    function add(AddressSet storage set, address value)
        internal
        returns (bool)
    {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    function remove(Bytes32Set storage set, bytes32 value)
        internal
        returns (bool)
    {
        return _remove(set._inner, value);
    }

    function remove(AddressSet storage set, address value)
        internal
        returns (bool)
    {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    function remove(UintSet storage set, uint256 value)
        internal
        returns (bool)
    {
        return _remove(set._inner, bytes32(value));
    }

    function _at(Set storage set, uint256 index)
        private
        view
        returns (bytes32)
    {
        require(
            set._values.length > index,
            'EnumerableSet: index out of bounds'
        );
        return set._values[index];
    }

    function _contains(Set storage set, bytes32 value)
        private
        view
        returns (bool)
    {
        return set._indexes[value] != 0;
    }

    function _indexOf(Set storage set, bytes32 value)
        private
        view
        returns (uint256)
    {
        unchecked {
            return set._indexes[value] - 1;
        }
    }

    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    function _remove(Set storage set, bytes32 value) private returns (bool) {
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            uint256 index = valueIndex - 1;
            bytes32 last = set._values[set._values.length - 1];

            // move last value to now-vacant index

            set._values[index] = last;
            set._indexes[last] = index + 1;

            // clear last index

            set._values.pop();
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }
}

File 4 of 8 : ABDKMath64x64.sol
// SPDX-License-Identifier: BSD-4-Clause
/*
 * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <[email protected]>
 */
pragma solidity ^0.8.0;

/**
 * Smart contract library of mathematical functions operating with signed
 * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is
 * basically a simple fraction whose numerator is signed 128-bit integer and
 * denominator is 2^64.  As long as denominator is always the same, there is no
 * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
 * represented by int128 type holding only the numerator.
 */
library ABDKMath64x64 {
  /*
   * Minimum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

  /*
   * Maximum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

  /**
   * Convert signed 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromInt (int256 x) internal pure returns (int128) {
    unchecked {
      require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
      return int128 (x << 64);
    }
  }

  /**
   * Convert signed 64.64 fixed point number into signed 64-bit integer number
   * rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64-bit integer number
   */
  function toInt (int128 x) internal pure returns (int64) {
    unchecked {
      return int64 (x >> 64);
    }
  }

  /**
   * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromUInt (uint256 x) internal pure returns (int128) {
    unchecked {
      require (x <= 0x7FFFFFFFFFFFFFFF);
      return int128 (int256 (x << 64));
    }
  }

  /**
   * Convert signed 64.64 fixed point number into unsigned 64-bit integer
   * number rounding down.  Revert on underflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return unsigned 64-bit integer number
   */
  function toUInt (int128 x) internal pure returns (uint64) {
    unchecked {
      require (x >= 0);
      return uint64 (uint128 (x >> 64));
    }
  }

  /**
   * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
   * number rounding down.  Revert on overflow.
   *
   * @param x signed 128.128-bin fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function from128x128 (int256 x) internal pure returns (int128) {
    unchecked {
      int256 result = x >> 64;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Convert signed 64.64 fixed point number into signed 128.128 fixed point
   * number.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 128.128 fixed point number
   */
  function to128x128 (int128 x) internal pure returns (int256) {
    unchecked {
      return int256 (x) << 64;
    }
  }

  /**
   * Calculate x + y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function add (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) + y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x - y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sub (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) - y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x * y rounding down.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function mul (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) * y >> 64;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
   * number and y is signed 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y signed 256-bit integer number
   * @return signed 256-bit integer number
   */
  function muli (int128 x, int256 y) internal pure returns (int256) {
    unchecked {
      if (x == MIN_64x64) {
        require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&
          y <= 0x1000000000000000000000000000000000000000000000000);
        return -y << 63;
      } else {
        bool negativeResult = false;
        if (x < 0) {
          x = -x;
          negativeResult = true;
        }
        if (y < 0) {
          y = -y; // We rely on overflow behavior here
          negativeResult = !negativeResult;
        }
        uint256 absoluteResult = mulu (x, uint256 (y));
        if (negativeResult) {
          require (absoluteResult <=
            0x8000000000000000000000000000000000000000000000000000000000000000);
          return -int256 (absoluteResult); // We rely on overflow behavior here
        } else {
          require (absoluteResult <=
            0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
          return int256 (absoluteResult);
        }
      }
    }
  }

  /**
   * Calculate x * y rounding down, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y unsigned 256-bit integer number
   * @return unsigned 256-bit integer number
   */
  function mulu (int128 x, uint256 y) internal pure returns (uint256) {
    unchecked {
      if (y == 0) return 0;

      require (x >= 0);

      uint256 lo = (uint256 (int256 (x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
      uint256 hi = uint256 (int256 (x)) * (y >> 128);

      require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      hi <<= 64;

      require (hi <=
        0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);
      return hi + lo;
    }
  }

  /**
   * Calculate x / y rounding towards zero.  Revert on overflow or when y is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function div (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);
      int256 result = (int256 (x) << 64) / y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are signed 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x signed 256-bit integer number
   * @param y signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divi (int256 x, int256 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);

      bool negativeResult = false;
      if (x < 0) {
        x = -x; // We rely on overflow behavior here
        negativeResult = true;
      }
      if (y < 0) {
        y = -y; // We rely on overflow behavior here
        negativeResult = !negativeResult;
      }
      uint128 absoluteResult = divuu (uint256 (x), uint256 (y));
      if (negativeResult) {
        require (absoluteResult <= 0x80000000000000000000000000000000);
        return -int128 (absoluteResult); // We rely on overflow behavior here
      } else {
        require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        return int128 (absoluteResult); // We rely on overflow behavior here
      }
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divu (uint256 x, uint256 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);
      uint128 result = divuu (x, y);
      require (result <= uint128 (MAX_64x64));
      return int128 (result);
    }
  }

  /**
   * Calculate -x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function neg (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != MIN_64x64);
      return -x;
    }
  }

  /**
   * Calculate |x|.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function abs (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != MIN_64x64);
      return x < 0 ? -x : x;
    }
  }

  /**
   * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function inv (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != 0);
      int256 result = int256 (0x100000000000000000000000000000000) / x;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function avg (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      return int128 ((int256 (x) + int256 (y)) >> 1);
    }
  }

  /**
   * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
   * Revert on overflow or in case x * y is negative.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function gavg (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 m = int256 (x) * int256 (y);
      require (m >= 0);
      require (m <
          0x4000000000000000000000000000000000000000000000000000000000000000);
      return int128 (sqrtu (uint256 (m)));
    }
  }

  /**
   * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y uint256 value
   * @return signed 64.64-bit fixed point number
   */
  function pow (int128 x, uint256 y) internal pure returns (int128) {
    unchecked {
      bool negative = x < 0 && y & 1 == 1;

      uint256 absX = uint128 (x < 0 ? -x : x);
      uint256 absResult;
      absResult = 0x100000000000000000000000000000000;

      if (absX <= 0x10000000000000000) {
        absX <<= 63;
        while (y != 0) {
          if (y & 0x1 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x2 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x4 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x8 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          y >>= 4;
        }

        absResult >>= 64;
      } else {
        uint256 absXShift = 63;
        if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; }
        if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; }
        if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; }
        if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; }
        if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; }
        if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; }

        uint256 resultShift = 0;
        while (y != 0) {
          require (absXShift < 64);

          if (y & 0x1 != 0) {
            absResult = absResult * absX >> 127;
            resultShift += absXShift;
            if (absResult > 0x100000000000000000000000000000000) {
              absResult >>= 1;
              resultShift += 1;
            }
          }
          absX = absX * absX >> 127;
          absXShift <<= 1;
          if (absX >= 0x100000000000000000000000000000000) {
              absX >>= 1;
              absXShift += 1;
          }

          y >>= 1;
        }

        require (resultShift < 64);
        absResult >>= 64 - resultShift;
      }
      int256 result = negative ? -int256 (absResult) : int256 (absResult);
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate sqrt (x) rounding down.  Revert if x < 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sqrt (int128 x) internal pure returns (int128) {
    unchecked {
      require (x >= 0);
      return int128 (sqrtu (uint256 (int256 (x)) << 64));
    }
  }

  /**
   * Calculate binary logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function log_2 (int128 x) internal pure returns (int128) {
    unchecked {
      require (x > 0);

      int256 msb = 0;
      int256 xc = x;
      if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }
      if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
      if (xc >= 0x10000) { xc >>= 16; msb += 16; }
      if (xc >= 0x100) { xc >>= 8; msb += 8; }
      if (xc >= 0x10) { xc >>= 4; msb += 4; }
      if (xc >= 0x4) { xc >>= 2; msb += 2; }
      if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

      int256 result = msb - 64 << 64;
      uint256 ux = uint256 (int256 (x)) << uint256 (127 - msb);
      for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
        ux *= ux;
        uint256 b = ux >> 255;
        ux >>= 127 + b;
        result += bit * int256 (b);
      }

      return int128 (result);
    }
  }

  /**
   * Calculate natural logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function ln (int128 x) internal pure returns (int128) {
    unchecked {
      require (x > 0);

      return int128 (int256 (
          uint256 (int256 (log_2 (x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128));
    }
  }

  /**
   * Calculate binary exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp_2 (int128 x) internal pure returns (int128) {
    unchecked {
      require (x < 0x400000000000000000); // Overflow

      if (x < -0x400000000000000000) return 0; // Underflow

      uint256 result = 0x80000000000000000000000000000000;

      if (x & 0x8000000000000000 > 0)
        result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
      if (x & 0x4000000000000000 > 0)
        result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
      if (x & 0x2000000000000000 > 0)
        result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
      if (x & 0x1000000000000000 > 0)
        result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
      if (x & 0x800000000000000 > 0)
        result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
      if (x & 0x400000000000000 > 0)
        result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
      if (x & 0x200000000000000 > 0)
        result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
      if (x & 0x100000000000000 > 0)
        result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
      if (x & 0x80000000000000 > 0)
        result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
      if (x & 0x40000000000000 > 0)
        result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
      if (x & 0x20000000000000 > 0)
        result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
      if (x & 0x10000000000000 > 0)
        result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
      if (x & 0x8000000000000 > 0)
        result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
      if (x & 0x4000000000000 > 0)
        result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
      if (x & 0x2000000000000 > 0)
        result = result * 0x1000162E525EE054754457D5995292026 >> 128;
      if (x & 0x1000000000000 > 0)
        result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
      if (x & 0x800000000000 > 0)
        result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
      if (x & 0x400000000000 > 0)
        result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
      if (x & 0x200000000000 > 0)
        result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;
      if (x & 0x100000000000 > 0)
        result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
      if (x & 0x80000000000 > 0)
        result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
      if (x & 0x40000000000 > 0)
        result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
      if (x & 0x20000000000 > 0)
        result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
      if (x & 0x10000000000 > 0)
        result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
      if (x & 0x8000000000 > 0)
        result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
      if (x & 0x4000000000 > 0)
        result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
      if (x & 0x2000000000 > 0)
        result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
      if (x & 0x1000000000 > 0)
        result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
      if (x & 0x800000000 > 0)
        result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
      if (x & 0x400000000 > 0)
        result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
      if (x & 0x200000000 > 0)
        result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
      if (x & 0x100000000 > 0)
        result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
      if (x & 0x80000000 > 0)
        result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
      if (x & 0x40000000 > 0)
        result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
      if (x & 0x20000000 > 0)
        result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;
      if (x & 0x10000000 > 0)
        result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
      if (x & 0x8000000 > 0)
        result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
      if (x & 0x4000000 > 0)
        result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
      if (x & 0x2000000 > 0)
        result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
      if (x & 0x1000000 > 0)
        result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;
      if (x & 0x800000 > 0)
        result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
      if (x & 0x400000 > 0)
        result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;
      if (x & 0x200000 > 0)
        result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;
      if (x & 0x100000 > 0)
        result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;
      if (x & 0x80000 > 0)
        result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
      if (x & 0x40000 > 0)
        result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
      if (x & 0x20000 > 0)
        result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;
      if (x & 0x10000 > 0)
        result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
      if (x & 0x8000 > 0)
        result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
      if (x & 0x4000 > 0)
        result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;
      if (x & 0x2000 > 0)
        result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;
      if (x & 0x1000 > 0)
        result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
      if (x & 0x800 > 0)
        result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
      if (x & 0x400 > 0)
        result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;
      if (x & 0x200 > 0)
        result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;
      if (x & 0x100 > 0)
        result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;
      if (x & 0x80 > 0)
        result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
      if (x & 0x40 > 0)
        result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
      if (x & 0x20 > 0)
        result = result * 0x100000000000000162E42FEFA39EF366F >> 128;
      if (x & 0x10 > 0)
        result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;
      if (x & 0x8 > 0)
        result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
      if (x & 0x4 > 0)
        result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
      if (x & 0x2 > 0)
        result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;
      if (x & 0x1 > 0)
        result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;

      result >>= uint256 (int256 (63 - (x >> 64)));
      require (result <= uint256 (int256 (MAX_64x64)));

      return int128 (int256 (result));
    }
  }

  /**
   * Calculate natural exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp (int128 x) internal pure returns (int128) {
    unchecked {
      require (x < 0x400000000000000000); // Overflow

      if (x < -0x400000000000000000) return 0; // Underflow

      return exp_2 (
          int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return unsigned 64.64-bit fixed point number
   */
  function divuu (uint256 x, uint256 y) private pure returns (uint128) {
    unchecked {
      require (y != 0);

      uint256 result;

      if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
        result = (x << 64) / y;
      else {
        uint256 msb = 192;
        uint256 xc = x >> 192;
        if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
        if (xc >= 0x10000) { xc >>= 16; msb += 16; }
        if (xc >= 0x100) { xc >>= 8; msb += 8; }
        if (xc >= 0x10) { xc >>= 4; msb += 4; }
        if (xc >= 0x4) { xc >>= 2; msb += 2; }
        if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

        result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);
        require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

        uint256 hi = result * (y >> 128);
        uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

        uint256 xh = x >> 192;
        uint256 xl = x << 64;

        if (xl < lo) xh -= 1;
        xl -= lo; // We rely on overflow behavior here
        lo = hi << 128;
        if (xl < lo) xh -= 1;
        xl -= lo; // We rely on overflow behavior here

        assert (xh == hi >> 128);

        result += xl / y;
      }

      require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      return uint128 (result);
    }
  }

  /**
   * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
   * number.
   *
   * @param x unsigned 256-bit integer number
   * @return unsigned 128-bit integer number
   */
  function sqrtu (uint256 x) private pure returns (uint128) {
    unchecked {
      if (x == 0) return 0;
      else {
        uint256 xx = x;
        uint256 r = 1;
        if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; }
        if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; }
        if (xx >= 0x100000000) { xx >>= 32; r <<= 16; }
        if (xx >= 0x10000) { xx >>= 16; r <<= 8; }
        if (xx >= 0x100) { xx >>= 8; r <<= 4; }
        if (xx >= 0x10) { xx >>= 4; r <<= 2; }
        if (xx >= 0x8) { r <<= 1; }
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1; // Seven iterations should be enough
        uint256 r1 = x / r;
        return uint128 (r < r1 ? r : r1);
      }
    }
  }
}

File 5 of 8 : OptionMath.sol
// SPDX-License-Identifier: BUSL-1.1
// For further clarification please see https://license.premia.legal

pragma solidity ^0.8.0;

import {ABDKMath64x64} from "abdk-libraries-solidity/ABDKMath64x64.sol";

library OptionMath {
    using ABDKMath64x64 for int128;

    struct QuoteArgs {
        int128 varianceAnnualized64x64; // 64x64 fixed point representation of annualized variance
        int128 strike64x64; // 64x64 fixed point representation of strike price
        int128 spot64x64; // 64x64 fixed point representation of spot price
        int128 timeToMaturity64x64; // 64x64 fixed point representation of duration of option contract (in years)
        int128 oldCLevel64x64; // 64x64 fixed point representation of C-Level of Pool before purchase
        int128 oldPoolState; // 64x64 fixed point representation of current state of the pool
        int128 newPoolState; // 64x64 fixed point representation of state of the pool after trade
        int128 steepness64x64; // 64x64 fixed point representation of Pool state delta multiplier
        int128 minAPY64x64; // 64x64 fixed point representation of minimum APY for capital locked up to underwrite options
        bool isCall; // whether to price "call" or "put" option
    }

    struct CalculateCLevelDecayArgs {
        int128 timeIntervalsElapsed64x64; // 64x64 fixed point representation of quantity of discrete arbitrary intervals elapsed since last update
        int128 oldCLevel64x64; // 64x64 fixed point representation of C-Level prior to accounting for decay
        int128 utilization64x64; // 64x64 fixed point representation of pool capital utilization rate
        int128 utilizationLowerBound64x64;
        int128 utilizationUpperBound64x64;
        int128 cLevelLowerBound64x64;
        int128 cLevelUpperBound64x64;
        int128 cConvergenceULowerBound64x64;
        int128 cConvergenceUUpperBound64x64;
    }

    // 64x64 fixed point integer constants
    int128 internal constant ONE_64x64 = 0x10000000000000000;
    int128 internal constant THREE_64x64 = 0x30000000000000000;

    // 64x64 fixed point constants used in Choudhury’s approximation of the Black-Scholes CDF
    int128 private constant CDF_CONST_0 = 0x09109f285df452394; // 2260 / 3989
    int128 private constant CDF_CONST_1 = 0x19abac0ea1da65036; // 6400 / 3989
    int128 private constant CDF_CONST_2 = 0x0d3c84b78b749bd6b; // 3300 / 3989

    /**
     * @notice recalculate C-Level based on change in liquidity
     * @param initialCLevel64x64 64x64 fixed point representation of C-Level of Pool before update
     * @param oldPoolState64x64 64x64 fixed point representation of liquidity in pool before update
     * @param newPoolState64x64 64x64 fixed point representation of liquidity in pool after update
     * @param steepness64x64 64x64 fixed point representation of steepness coefficient
     * @return 64x64 fixed point representation of new C-Level
     */
    function calculateCLevel(
        int128 initialCLevel64x64,
        int128 oldPoolState64x64,
        int128 newPoolState64x64,
        int128 steepness64x64
    ) external pure returns (int128) {
        return
            newPoolState64x64
                .sub(oldPoolState64x64)
                .div(
                    oldPoolState64x64 > newPoolState64x64
                        ? oldPoolState64x64
                        : newPoolState64x64
                )
                .mul(steepness64x64)
                .neg()
                .exp()
                .mul(initialCLevel64x64);
    }

    /**
     * @notice calculate the price of an option using the Premia Finance model
     * @param args arguments of quotePrice
     * @return premiaPrice64x64 64x64 fixed point representation of Premia option price
     * @return cLevel64x64 64x64 fixed point representation of C-Level of Pool after purchase
     */
    function quotePrice(QuoteArgs memory args)
        external
        pure
        returns (
            int128 premiaPrice64x64,
            int128 cLevel64x64,
            int128 slippageCoefficient64x64
        )
    {
        int128 deltaPoolState64x64 = args
            .newPoolState
            .sub(args.oldPoolState)
            .div(args.oldPoolState)
            .mul(args.steepness64x64);
        int128 tradingDelta64x64 = deltaPoolState64x64.neg().exp();

        int128 blackScholesPrice64x64 = _blackScholesPrice(
            args.varianceAnnualized64x64,
            args.strike64x64,
            args.spot64x64,
            args.timeToMaturity64x64,
            args.isCall
        );

        cLevel64x64 = tradingDelta64x64.mul(args.oldCLevel64x64);
        slippageCoefficient64x64 = ONE_64x64.sub(tradingDelta64x64).div(
            deltaPoolState64x64
        );

        premiaPrice64x64 = blackScholesPrice64x64.mul(cLevel64x64).mul(
            slippageCoefficient64x64
        );

        int128 intrinsicValue64x64;

        if (args.isCall && args.strike64x64 < args.spot64x64) {
            intrinsicValue64x64 = args.spot64x64.sub(args.strike64x64);
        } else if (!args.isCall && args.strike64x64 > args.spot64x64) {
            intrinsicValue64x64 = args.strike64x64.sub(args.spot64x64);
        }

        int128 collateralValue64x64 = args.isCall
            ? args.spot64x64
            : args.strike64x64;

        int128 minPrice64x64 = intrinsicValue64x64.add(
            collateralValue64x64.mul(args.minAPY64x64).mul(
                args.timeToMaturity64x64
            )
        );

        if (minPrice64x64 > premiaPrice64x64) {
            premiaPrice64x64 = minPrice64x64;
        }
    }

    /**
     * @notice calculate the decay of C-Level based on heat diffusion function
     * @param args structured CalculateCLevelDecayArgs
     * @return cLevelDecayed64x64 C-Level after accounting for decay
     */
    function calculateCLevelDecay(CalculateCLevelDecayArgs memory args)
        external
        pure
        returns (int128 cLevelDecayed64x64)
    {
        int128 convFHighU64x64 = (args.utilization64x64 >=
            args.utilizationUpperBound64x64 &&
            args.oldCLevel64x64 <= args.cLevelLowerBound64x64)
            ? ONE_64x64
            : int128(0);

        int128 convFLowU64x64 = (args.utilization64x64 <=
            args.utilizationLowerBound64x64 &&
            args.oldCLevel64x64 >= args.cLevelUpperBound64x64)
            ? ONE_64x64
            : int128(0);

        cLevelDecayed64x64 = args
            .oldCLevel64x64
            .sub(args.cConvergenceULowerBound64x64.mul(convFLowU64x64))
            .sub(args.cConvergenceUUpperBound64x64.mul(convFHighU64x64))
            .mul(
                convFLowU64x64
                    .mul(ONE_64x64.sub(args.utilization64x64))
                    .add(convFHighU64x64.mul(args.utilization64x64))
                    .mul(args.timeIntervalsElapsed64x64)
                    .neg()
                    .exp()
            )
            .add(
                args.cConvergenceULowerBound64x64.mul(convFLowU64x64).add(
                    args.cConvergenceUUpperBound64x64.mul(convFHighU64x64)
                )
            );
    }

    /**
     * @notice calculate the exponential decay coefficient for a given interval
     * @param oldTimestamp timestamp of previous update
     * @param newTimestamp current timestamp
     * @return 64x64 fixed point representation of exponential decay coefficient
     */
    function _decay(uint256 oldTimestamp, uint256 newTimestamp)
        internal
        pure
        returns (int128)
    {
        return
            ONE_64x64.sub(
                (-ABDKMath64x64.divu(newTimestamp - oldTimestamp, 7 days)).exp()
            );
    }

    /**
     * @notice calculate Choudhury’s approximation of the Black-Scholes CDF
     * @param input64x64 64x64 fixed point representation of random variable
     * @return 64x64 fixed point representation of the approximated CDF of x
     */
    function _N(int128 input64x64) internal pure returns (int128) {
        // squaring via mul is cheaper than via pow
        int128 inputSquared64x64 = input64x64.mul(input64x64);

        int128 value64x64 = (-inputSquared64x64 >> 1).exp().div(
            CDF_CONST_0.add(CDF_CONST_1.mul(input64x64.abs())).add(
                CDF_CONST_2.mul(inputSquared64x64.add(THREE_64x64).sqrt())
            )
        );

        return input64x64 > 0 ? ONE_64x64.sub(value64x64) : value64x64;
    }

    /**
     * @notice calculate the price of an option using the Black-Scholes model
     * @param varianceAnnualized64x64 64x64 fixed point representation of annualized variance
     * @param strike64x64 64x64 fixed point representation of strike price
     * @param spot64x64 64x64 fixed point representation of spot price
     * @param timeToMaturity64x64 64x64 fixed point representation of duration of option contract (in years)
     * @param isCall whether to price "call" or "put" option
     * @return 64x64 fixed point representation of Black-Scholes option price
     */
    function _blackScholesPrice(
        int128 varianceAnnualized64x64,
        int128 strike64x64,
        int128 spot64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) internal pure returns (int128) {
        int128 cumulativeVariance64x64 = timeToMaturity64x64.mul(
            varianceAnnualized64x64
        );
        int128 cumulativeVarianceSqrt64x64 = cumulativeVariance64x64.sqrt();

        int128 d1_64x64 = spot64x64
            .div(strike64x64)
            .ln()
            .add(cumulativeVariance64x64 >> 1)
            .div(cumulativeVarianceSqrt64x64);
        int128 d2_64x64 = d1_64x64.sub(cumulativeVarianceSqrt64x64);

        if (isCall) {
            return
                spot64x64.mul(_N(d1_64x64)).sub(strike64x64.mul(_N(d2_64x64)));
        } else {
            return
                -spot64x64.mul(_N(-d1_64x64)).sub(
                    strike64x64.mul(_N(-d2_64x64))
                );
        }
    }
}

File 6 of 8 : VolatilitySurfaceOracleStorage.sol
// SPDX-License-Identifier: BUSL-1.1
// For further clarification please see https://license.premia.legal

pragma solidity ^0.8.0;

import {EnumerableSet} from "@solidstate/contracts/utils/EnumerableSet.sol";

library VolatilitySurfaceOracleStorage {
    bytes32 internal constant STORAGE_SLOT =
        keccak256("premia.contracts.storage.VolatilitySurfaceOracle");

    uint256 internal constant COEFF_BITS = 51;
    uint256 internal constant COEFF_BITS_MINUS_ONE = 50;
    uint256 internal constant COEFF_AMOUNT = 5;
    // START_BIT = COEFF_BITS * (COEFF_AMOUNT - 1)
    uint256 internal constant START_BIT = 204;

    struct Update {
        uint256 updatedAt;
        bytes32 callCoefficients;
        bytes32 putCoefficients;
    }

    struct Layout {
        // Base token -> Underlying token -> Update
        mapping(address => mapping(address => Update)) volatilitySurfaces;
        // Relayer addresses which can be trusted to provide accurate option trades
        EnumerableSet.AddressSet whitelistedRelayers;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }

    function getCoefficients(
        Layout storage l,
        address baseToken,
        address underlyingToken,
        bool isCall
    ) internal view returns (bytes32) {
        Update storage u = l.volatilitySurfaces[baseToken][underlyingToken];
        return isCall ? u.callCoefficients : u.putCoefficients;
    }

    function parseVolatilitySurfaceCoefficients(bytes32 input)
        internal
        pure
        returns (int256[] memory coefficients)
    {
        coefficients = new int256[](COEFF_AMOUNT);

        // Value to add to negative numbers to cast them to int256
        int256 toAdd = (int256(-1) >> COEFF_BITS) << COEFF_BITS;

        assembly {
            let i := 0
            // Value equal to -1
            let mid := shl(COEFF_BITS_MINUS_ONE, 1)

            for {

            } lt(i, COEFF_AMOUNT) {

            } {
                let offset := sub(START_BIT, mul(COEFF_BITS, i))
                let coeff := shr(
                    offset,
                    sub(
                        input,
                        shl(
                            add(offset, COEFF_BITS),
                            shr(add(offset, COEFF_BITS), input)
                        )
                    )
                )

                // Check if value is a negative number and needs casting
                if or(eq(coeff, mid), gt(coeff, mid)) {
                    coeff := add(coeff, toAdd)
                }

                // Store result in the coefficients array
                mstore(add(coefficients, add(0x20, mul(0x20, i))), coeff)

                i := add(i, 1)
            }
        }
    }

    function formatVolatilitySurfaceCoefficients(int256[5] memory coefficients)
        internal
        pure
        returns (bytes32 result)
    {
        for (uint256 i = 0; i < COEFF_AMOUNT; i++) {
            int256 max = int256(1 << COEFF_BITS_MINUS_ONE);
            require(
                coefficients[i] < max && coefficients[i] > -max,
                "Out of bounds"
            );
        }

        assembly {
            let i := 0

            for {

            } lt(i, COEFF_AMOUNT) {

            } {
                let offset := sub(START_BIT, mul(COEFF_BITS, i))
                let coeff := mload(add(coefficients, mul(0x20, i)))

                result := add(
                    result,
                    shl(
                        offset,
                        sub(coeff, shl(COEFF_BITS, shr(COEFF_BITS, coeff)))
                    )
                )

                i := add(i, 1)
            }
        }
    }
}

File 7 of 8 : IVolatilitySurfaceOracle.sol
// SPDX-License-Identifier: LGPL-3.0-or-later

pragma solidity ^0.8.0;

import {VolatilitySurfaceOracleStorage} from "./VolatilitySurfaceOracleStorage.sol";

interface IVolatilitySurfaceOracle {
    function getWhitelistedRelayers() external view returns (address[] memory);

    function getVolatilitySurface(address baseToken, address underlyingToken)
        external
        view
        returns (VolatilitySurfaceOracleStorage.Update memory);

    function getVolatilitySurfaceCoefficientsUnpacked(
        address baseToken,
        address underlyingToken,
        bool isCall
    ) external view returns (int256[] memory);

    function getTimeToMaturity64x64(uint64 maturity)
        external
        view
        returns (int128);

    function getAnnualizedVolatility64x64(
        address baseToken,
        address underlyingToken,
        int128 spot64x64,
        int128 strike64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) external view returns (int128);

    function getBlackScholesPrice64x64(
        address baseToken,
        address underlyingToken,
        int128 strike64x64,
        int128 spot64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) external view returns (int128);

    function getBlackScholesPrice(
        address baseToken,
        address underlyingToken,
        int128 strike64x64,
        int128 spot64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) external view returns (uint256);
}

File 8 of 8 : OwnableStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library OwnableStorage {
    struct Layout {
        address owner;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.Ownable');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }

    function setOwner(Layout storage l, address owner) internal {
        l.owner = owner;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"bytes32","name":"callCoefficients","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"putCoefficients","type":"bytes32"}],"name":"UpdateCoefficients","type":"event"},{"inputs":[{"internalType":"address[]","name":"_addr","type":"address[]"}],"name":"addWhitelistedRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256[5]","name":"coefficients","type":"int256[5]"}],"name":"formatVolatilitySurfaceCoefficients","outputs":[{"internalType":"bytes32","name":"result","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"int128","name":"spot64x64","type":"int128"},{"internalType":"int128","name":"strike64x64","type":"int128"},{"internalType":"int128","name":"timeToMaturity64x64","type":"int128"},{"internalType":"bool","name":"isCall","type":"bool"}],"name":"getAnnualizedVolatility64x64","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"int128","name":"strike64x64","type":"int128"},{"internalType":"int128","name":"spot64x64","type":"int128"},{"internalType":"int128","name":"timeToMaturity64x64","type":"int128"},{"internalType":"bool","name":"isCall","type":"bool"}],"name":"getBlackScholesPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"int128","name":"strike64x64","type":"int128"},{"internalType":"int128","name":"spot64x64","type":"int128"},{"internalType":"int128","name":"timeToMaturity64x64","type":"int128"},{"internalType":"bool","name":"isCall","type":"bool"}],"name":"getBlackScholesPrice64x64","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"maturity","type":"uint64"}],"name":"getTimeToMaturity64x64","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"}],"name":"getVolatilitySurface","outputs":[{"components":[{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"bytes32","name":"callCoefficients","type":"bytes32"},{"internalType":"bytes32","name":"putCoefficients","type":"bytes32"}],"internalType":"struct VolatilitySurfaceOracleStorage.Update","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bool","name":"isCall","type":"bool"}],"name":"getVolatilitySurfaceCoefficientsUnpacked","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWhitelistedRelayers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"input","type":"bytes32"}],"name":"parseVolatilitySurfaceCoefficients","outputs":[{"internalType":"int256[]","name":"coefficients","type":"int256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addr","type":"address[]"}],"name":"removeWhitelistedRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"baseTokens","type":"address[]"},{"internalType":"address[]","name":"underlyingTokens","type":"address[]"},{"internalType":"bytes32[]","name":"callCoefficients","type":"bytes32[]"},{"internalType":"bytes32[]","name":"putCoefficients","type":"bytes32[]"}],"name":"updateVolatilitySurfaces","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b5061280a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806345d58d741161007157806345d58d74146101e25780638570bb08146101f7578063aee9dfa914610218578063b7bd8b6c1461022b578063c4afd30d1461023e578063e9d59ccc1461025157600080fd5b80631d94c9b3146100b957806325372cb7146100e45780632a695d8e146101045780632b26e5f21461011957806330955b3d1461012c5780633fd369341461013f575b600080fd5b6100cc6100c73660046120fd565b610264565b604051600f9190910b81526020015b60405180910390f35b6100f76100f2366004612127565b61028d565b6040516100db9190612140565b610117610112366004612278565b610298565b005b6100f76101273660046122bd565b610378565b6100cc61013a366004612312565b6103ac565b6101c061014d366004612386565b6040805160608082018352600080835260208084018290529284018190526001600160a01b0395861681526000805160206127b583398151915283528381209490951685529281529281902081519283018252805483526001810154938301939093526002909201549181019190915290565b60408051825181526020808401519082015291810151908201526060016100db565b6101ea6103c7565b6040516100db91906123b9565b61020a6102053660046123fa565b6104a8565b6040519081526020016100db565b61020a610226366004612312565b6104b3565b6101176102393660046124d3565b6104d8565b6100cc61024c366004612312565b610786565b61011761025f366004612278565b6107c7565b600061028761027d4267ffffffffffffffff8516612596565b6301e1338061089d565b92915050565b6060610287826108db565b7f8a22373512790c48b83a1fe2efdd2888d4a917bcdc24d0adf63e60f671680460546001600160a01b031633146103165760405162461bcd60e51b815260206004820152601d60248201527f4f776e61626c653a2073656e646572206d757374206265206f776e657200000060448201526064015b60405180910390fd5b6000805160206127b583398151915260005b825181101561037357610360838281518110610346576103466125ad565b60200260200101518360010161095890919063ffffffff16565b508061036b816125c3565b915050610328565b505050565b60606000805160206127b583398151915260006103978287878761096d565b90506103a2816108db565b9695505050505050565b60006103bc8787878787876109ae565b979650505050505050565b60606000805160206127b583398151915260006104037fe6a0172df1f6c41c4af4f1ef2705a2edb2309986a50d87bc4f984cc3cbccc3a66109e0565b905060008167ffffffffffffffff81111561042057610420612184565b604051908082528060200260200182016040528015610449578160200160208202803683370190505b50905060005b828110156104a05761046460018501826109ea565b828281518110610476576104766125ad565b6001600160a01b039092166020928302919091019091015280610498816125c3565b91505061044f565b509392505050565b6000610287826109f6565b60006103bc670de0b6b3a76400006104cf8989898989896109ae565b600f0b90610ad5565b83518351811480156104ea5750825181145b80156104f65750815181145b6105375760405162461bcd60e51b81526020600482015260126024820152710aee4dedcce40c2e4e4c2f240d8cadccee8d60731b604482015260640161030d565b6000805160206127b58339815191526105707fe6a0172df1f6c41c4af4f1ef2705a2edb2309986a50d87bc4f984cc3cbccc3a633610b3d565b6105bc5760405162461bcd60e51b815260206004820152601760248201527f52656c61796572206e6f742077686974656c6973746564000000000000000000604482015260640161030d565b60005b8281101561077d5760405180606001604052804281526020018683815181106105ea576105ea6125ad565b60200260200101518152602001858381518110610609576106096125ad565b602002602001015181525082600001600089848151811061062c5761062c6125ad565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000888481518110610668576106686125ad565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050508581815181106106c3576106c36125ad565b60200260200101516001600160a01b03168782815181106106e6576106e66125ad565b60200260200101516001600160a01b03167f8982234641cedc74d0a3b359c99133bc65c3e5caf6c5d20f6c22e471fdbb764987848151811061072a5761072a6125ad565b6020026020010151878581518110610744576107446125ad565b6020026020010151604051610763929190918252602082015260400190565b60405180910390a380610775816125c3565b9150506105bf565b50505050505050565b60006000805160206127b5833981519152816107ac6107a7838b8b8861096d565b6108db565b90506107ba87878784610b5f565b9998505050505050505050565b7f8a22373512790c48b83a1fe2efdd2888d4a917bcdc24d0adf63e60f671680460546001600160a01b031633146108405760405162461bcd60e51b815260206004820152601d60248201527f4f776e61626c653a2073656e646572206d757374206265206f776e6572000000604482015260640161030d565b6000805160206127b583398151915260005b82518110156103735761088a838281518110610870576108706125ad565b602002602001015183600101610caa90919063ffffffff16565b5080610895816125c3565b915050610852565b6000816108a957600080fd5b60006108b58484610cbf565b905060016001607f1b036001600160801b03821611156108d457600080fd5b9392505050565b60408051600580825260c082019092526060916020820160a080368337019050509050600019603390811d901b6000600160321b5b600582101561095057603380830260cc0390810186811c901b8603901c818114828211171561093c5783015b602080840286010152600190910190610910565b505050919050565b60006108d4836001600160a01b038416610e21565b6001600160a01b038084166000908152602086815260408083209386168352929052908120826109a15780600201546103a2565b6001015495945050505050565b6000806109bf888888888888610786565b905060006109d1600f83900b83610e70565b90506107ba8188888888610ea7565b6000610287825490565b60006108d48383610f89565b6000805b6005811015610a9957600160321b80848360058110610a1b57610a1b6125ad565b6020020151128015610a4a5750610a31816125de565b848360058110610a4357610a436125ad565b6020020151135b610a865760405162461bcd60e51b815260206004820152600d60248201526c4f7574206f6620626f756e647360981b604482015260640161030d565b5080610a91816125c3565b9150506109fa565b5060005b6005811015610acf57602081028301516607ffffffffffff19811690036033820260cc031b9190910190600101610a9d565b50919050565b600081610ae457506000610287565b600083600f0b1215610af557600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b03811115610b2457600080fd5b60401b8119811115610b3557600080fd5b019392505050565b6001600160a01b038116600090815260018301602052604081205415156108d4565b60008151600514610ba85760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420766f6c207375726661636560681b604482015260640161030d565b6000610bdb610bb985600f0b61100f565b610bd2610bca600f8a900b89611031565b600f0b611089565b600f0b90611031565b9050610c1184610c0883610c0887600481518110610bfb57610bfb6125ad565b60200260200101516110c3565b600f0b90610e70565b610c2b85610c0886600381518110610bfb57610bfb6125ad565b610c52610c3c600f85900b85610e70565b610c0887600281518110610bfb57610bfb6125ad565b610c6c84610c0888600181518110610bfb57610bfb6125ad565b610c8287600081518110610bfb57610bfb6125ad565b610c8c91906125f4565b610c9691906125f4565b610ca091906125f4565b6103a291906125f4565b60006108d4836001600160a01b0384166110da565b600081610ccb57600080fd5b60006001600160c01b038411610cf65782604085901b81610cee57610cee612643565b049050610e0d565b60c084811c6401000000008110610d0f576020918201911c5b620100008110610d21576010918201911c5b6101008110610d32576008918201911c5b60108110610d42576004918201911c5b60048110610d52576002918201911c5b60028110610d61576001820191505b60bf820360018603901c6001018260ff0387901b81610d8257610d82612643565b0492506001600160801b03831115610d9957600080fd5b608085901c83026001600160801b038616840260c088901c604089901b82811015610dc5576001820391505b608084901b92900382811015610ddc576001820391505b829003608084901c8214610df257610df2612659565b888181610e0157610e01612643565b04870196505050505050505b6001600160801b038111156108d457600080fd5b6000818152600183016020526040812054610e6857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610287565b506000610287565b6000600f83810b9083900b0260401d60016001607f1b03198112801590610e9e575060016001607f1b038113155b6108d457600080fd5b600080610eb8600f85900b88610e70565b90506000610ec882600f0b61100f565b90506000610efd82610bd2600186600f0b901d610ef4610bca8d8d600f0b61103190919063ffffffff16565b600f0b906111c5565b90506000610f0f600f83900b846111f8565b90508515610f5157610f46610f31610f268361122b565b600f8c900b90610e70565b610f3d610f268561122b565b600f0b906111f8565b945050505050610f80565b610f77610f68610f26610f638461266f565b61122b565b610f3d610f26610f638661266f565b610f469061266f565b95945050505050565b81546000908210610fe75760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b606482015260840161030d565b826000018281548110610ffc57610ffc6125ad565b9060005260206000200154905092915050565b60008082600f0b121561102157600080fd5b610287604083600f0b901b6112ef565b600081600f0b6000141561104457600080fd5b600082600f0b604085600f0b901b8161105f5761105f612643565b05905060016001607f1b03198112801590610e9e575060016001607f1b038113156108d457600080fd5b60008082600f0b1361109a57600080fd5b60806110a58361145a565b600f0b6fb17217f7d1cf79abc9e3b39803f2f6af02901c9050919050565b6000610287826110d5600c600a61277a565b611535565b600081815260018301602052604081205480156111bb5760006110fe600183612596565b8554909150600090869061111490600190612596565b81548110611124576111246125ad565b9060005260206000200154905080866000018381548110611147576111476125ad565b60009182526020909120015561115e826001612786565b600082815260018801602052604090205585548690806111805761118061279e565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610287565b6000915050610287565b6000600f83810b9083900b0160016001607f1b03198112801590610e9e575060016001607f1b038113156108d457600080fd5b6000600f82810b9084900b0360016001607f1b03198112801590610e9e575060016001607f1b038113156108d457600080fd5b60008061123c600f84900b84610e70565b905060006112c66112ab61127a61126b611263600f87900b680300000000000000006111c5565b600f0b61100f565b67d3c84b78b749bd6b90610e70565b610ef461129c61128c89600f0b6115c8565b68019abac0ea1da6503690610e70565b679109f285df452394906111c5565b610bd260016112b98661266f565b600f0b901d600f0b6115fb565b9050600084600f0b136112d957806112e7565b6112e7600160401b826111f8565b949350505050565b6000816112fe57506000919050565b816001600160801b82106113175760809190911c9060401b5b600160401b821061132d5760409190911c9060201b5b64010000000082106113445760209190911c9060101b5b6201000082106113595760109190911c9060081b5b610100821061136d5760089190911c9060041b5b601082106113805760049190911c9060021b5b6008821061138c5760011b5b600181858161139d5761139d612643565b048201901c905060018185816113b5576113b5612643565b048201901c905060018185816113cd576113cd612643565b048201901c905060018185816113e5576113e5612643565b048201901c905060018185816113fd576113fd612643565b048201901c9050600181858161141557611415612643565b048201901c9050600181858161142d5761142d612643565b048201901c9050600081858161144557611445612643565b0490508082106104a05780610f80565b919050565b60008082600f0b1361146b57600080fd5b6000600f83900b600160401b8112611485576040918201911d5b6401000000008112611499576020918201911d5b6201000081126114ab576010918201911d5b61010081126114bc576008918201911d5b601081126114cc576004918201911d5b600481126114dc576002918201911d5b600281126114eb576001820191505b603f19820160401b600f85900b607f8490031b6001603f1b5b600081131561152a5790800260ff81901c8281029390930192607f011c9060011d611504565b509095945050505050565b60008161154157600080fd5b60008084121561155657836000039350600190505b60008312156115685760009290920391155b60006115748585610cbf565b905081156115a2576001607f1b816001600160801b0316111561159657600080fd5b60000391506102879050565b60016001607f1b03816001600160801b031611156115bf57600080fd5b91506102879050565b6000600f82900b60016001607f1b031914156115e357600080fd5b600082600f0b126115f45781610287565b5060000390565b6000600160461b82600f0b1261161057600080fd5b683fffffffffffffffff1982600f0b121561162d57506000919050565b610287608083600f0b700171547652b82fe1777d0ffda0d23a7d1202901d6000600160461b82600f0b1261166057600080fd5b683fffffffffffffffff1982600f0b121561167d57506000919050565b6001607f1b60006001603f1b8416600f0b13156116ab5770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b60008367400000000000000016600f0b13156116d8577001306fe0a31b7152de8d5a46305c85edec0260801c5b60008367200000000000000016600f0b1315611705577001172b83c7d517adcdf7c8c50eb14a791f0260801c5b60008367100000000000000016600f0b13156117325770010b5586cf9890f6298b92b71842a983630260801c5b60008367080000000000000016600f0b131561175f577001059b0d31585743ae7c548eb68ca417fd0260801c5b60008367040000000000000016600f0b131561178c57700102c9a3e778060ee6f7caca4f7a29bde80260801c5b60008367020000000000000016600f0b13156117b95770010163da9fb33356d84a66ae336dcdfa3f0260801c5b60008367010000000000000016600f0b13156117e657700100b1afa5abcbed6129ab13ec11dc95430260801c5b600083668000000000000016600f0b13156118125770010058c86da1c09ea1ff19d294cf2f679b0260801c5b600083664000000000000016600f0b131561183e577001002c605e2e8cec506d21bfc89a23a00f0260801c5b600083662000000000000016600f0b131561186a57700100162f3904051fa128bca9c55c31e5df0260801c5b600083661000000000000016600f0b1315611896577001000b175effdc76ba38e31671ca9397250260801c5b600083660800000000000016600f0b13156118c257700100058ba01fb9f96d6cacd4b180917c3d0260801c5b600083600160321b16600f0b13156118eb5770010002c5cc37da9491d0985c348c68e7b30260801c5b600083660200000000000016600f0b1315611917577001000162e525ee054754457d59952920260260801c5b600083660100000000000016600f0b13156119435770010000b17255775c040618bf4a4ade83fc0260801c5b6000836580000000000016600f0b131561196e577001000058b91b5bc9ae2eed81e9b7d4cfab0260801c5b6000836540000000000016600f0b131561199957700100002c5c89d5ec6ca4d7c8acc017b7c90260801c5b6000836520000000000016600f0b13156119c45770010000162e43f4f831060e02d839a9d16d0260801c5b6000836510000000000016600f0b13156119ef57700100000b1721bcfc99d9f890ea069117630260801c5b6000836508000000000016600f0b1315611a1a5770010000058b90cf1e6d97f9ca14dbcc16280260801c5b6000836504000000000016600f0b1315611a45577001000002c5c863b73f016468f6bac5ca2b0260801c5b6000836502000000000016600f0b1315611a7057700100000162e430e5a18f6119e3c02282a50260801c5b6000836501000000000016600f0b1315611a9b577001000000b1721835514b86e6d96efd1bfe0260801c5b60008364800000000016600f0b1315611ac557700100000058b90c0b48c6be5df846c5b2ef0260801c5b60008364400000000016600f0b1315611aef5770010000002c5c8601cc6b9e94213c72737a0260801c5b60008364200000000016600f0b1315611b19577001000000162e42fff037df38aa2b219f060260801c5b60008364100000000016600f0b1315611b435770010000000b17217fba9c739aa5819f44f90260801c5b60008364080000000016600f0b1315611b6d577001000000058b90bfcdee5acd3c1cedc8230260801c5b60008364040000000016600f0b1315611b9757700100000002c5c85fe31f35a6a30da1be500260801c5b60008364020000000016600f0b1315611bc15770010000000162e42ff0999ce3541b9fffcf0260801c5b60008364010000000016600f0b1315611beb57700100000000b17217f80f4ef5aadda455540260801c5b600083638000000016600f0b1315611c145770010000000058b90bfbf8479bd5a81b51ad0260801c5b600083634000000016600f0b1315611c3d577001000000002c5c85fdf84bd62ae30a74cc0260801c5b600083632000000016600f0b1315611c6657700100000000162e42fefb2fed257559bdaa0260801c5b600083631000000016600f0b1315611c8f577001000000000b17217f7d5a7716bba4a9ae0260801c5b600083630800000016600f0b1315611cb857700100000000058b90bfbe9ddbac5e109cce0260801c5b600083630400000016600f0b1315611ce15770010000000002c5c85fdf4b15de6f17eb0d0260801c5b600083630200000016600f0b1315611d0a577001000000000162e42fefa494f1478fde050260801c5b600083630100000016600f0b1315611d335770010000000000b17217f7d20cf927c8e94c0260801c5b6000836280000016600f0b1315611d5b577001000000000058b90bfbe8f71cb4e4b33d0260801c5b6000836240000016600f0b1315611d8357700100000000002c5c85fdf477b662b269450260801c5b6000836220000016600f0b1315611dab5770010000000000162e42fefa3ae53369388c0260801c5b6000836210000016600f0b1315611dd357700100000000000b17217f7d1d351a389d400260801c5b6000836208000016600f0b1315611dfb5770010000000000058b90bfbe8e8b2d3d4ede0260801c5b6000836204000016600f0b1315611e23577001000000000002c5c85fdf4741bea6e77e0260801c5b6000836202000016600f0b1315611e4b57700100000000000162e42fefa39fe95583c20260801c5b6000836201000016600f0b1315611e73577001000000000000b17217f7d1cfb72b45e10260801c5b60008361800016600f0b1315611e9a57700100000000000058b90bfbe8e7cc35c3f00260801c5b60008361400016600f0b1315611ec15770010000000000002c5c85fdf473e242ea380260801c5b60008361200016600f0b1315611ee8577001000000000000162e42fefa39f02b772c0260801c5b60008361100016600f0b1315611f0f5770010000000000000b17217f7d1cf7d83c1a0260801c5b60008361080016600f0b1315611f36577001000000000000058b90bfbe8e7bdcbe2e0260801c5b60008361040016600f0b1315611f5d57700100000000000002c5c85fdf473dea871f0260801c5b60008361020016600f0b1315611f845770010000000000000162e42fefa39ef44d910260801c5b60008361010016600f0b1315611fab57700100000000000000b17217f7d1cf79e9490260801c5b600083608016600f0b1315611fd15770010000000000000058b90bfbe8e7bce5440260801c5b600083604016600f0b1315611ff7577001000000000000002c5c85fdf473de6eca0260801c5b600083602016600f0b131561201d57700100000000000000162e42fefa39ef366f0260801c5b600083601016600f0b1315612043577001000000000000000b17217f7d1cf79afa0260801c5b600083600816600f0b131561206957700100000000000000058b90bfbe8e7bcd6d0260801c5b600083600416600f0b131561208f5770010000000000000002c5c85fdf473de6b20260801c5b600083600216600f0b13156120b5577001000000000000000162e42fefa39ef3580260801c5b600083600116600f0b13156120db5770010000000000000000b17217f7d1cf79ab0260801c5b600f83810b60401d603f03900b1c60016001607f1b0381111561028757600080fd5b60006020828403121561210f57600080fd5b813567ffffffffffffffff811681146108d457600080fd5b60006020828403121561213957600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156121785783518352928401929184019160010161215c565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156121c3576121c3612184565b604052919050565b600067ffffffffffffffff8211156121e5576121e5612184565b5060051b60200190565b80356001600160a01b038116811461145557600080fd5b600082601f83011261221757600080fd5b8135602061222c612227836121cb565b61219a565b82815260059290921b8401810191818101908684111561224b57600080fd5b8286015b8481101561226d57612260816121ef565b835291830191830161224f565b509695505050505050565b60006020828403121561228a57600080fd5b813567ffffffffffffffff8111156122a157600080fd5b6112e784828501612206565b8035801515811461145557600080fd5b6000806000606084860312156122d257600080fd5b6122db846121ef565b92506122e9602085016121ef565b91506122f7604085016122ad565b90509250925092565b8035600f81900b811461145557600080fd5b60008060008060008060c0878903121561232b57600080fd5b612334876121ef565b9550612342602088016121ef565b945061235060408801612300565b935061235e60608801612300565b925061236c60808801612300565b915061237a60a088016122ad565b90509295509295509295565b6000806040838503121561239957600080fd5b6123a2836121ef565b91506123b0602084016121ef565b90509250929050565b6020808252825182820181905260009190848201906040850190845b818110156121785783516001600160a01b0316835292840192918401916001016123d5565b600060a0828403121561240c57600080fd5b82601f83011261241b57600080fd5b60405160a0810181811067ffffffffffffffff8211171561243e5761243e612184565b6040528060a084018581111561245357600080fd5b845b8181101561246d578035835260209283019201612455565b509195945050505050565b600082601f83011261248957600080fd5b81356020612499612227836121cb565b82815260059290921b840181019181810190868411156124b857600080fd5b8286015b8481101561226d57803583529183019183016124bc565b600080600080608085870312156124e957600080fd5b843567ffffffffffffffff8082111561250157600080fd5b61250d88838901612206565b9550602087013591508082111561252357600080fd5b61252f88838901612206565b9450604087013591508082111561254557600080fd5b61255188838901612478565b9350606087013591508082111561256757600080fd5b5061257487828801612478565b91505092959194509250565b634e487b7160e01b600052601160045260246000fd5b6000828210156125a8576125a8612580565b500390565b634e487b7160e01b600052603260045260246000fd5b60006000198214156125d7576125d7612580565b5060010190565b6000600160ff1b8214156115f4576115f4612580565b600081600f0b83600f0b600082128260016001607f1b030382138115161561261e5761261e612580565b8260016001607f1b031903821281161561263a5761263a612580565b50019392505050565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600081600f0b60016001607f1b031981141561268d5761268d612580565b60000392915050565b600181815b808511156126d15781600019048211156126b7576126b7612580565b808516156126c457918102915b93841c939080029061269b565b509250929050565b6000826126e857506001610287565b816126f557506000610287565b816001811461270b576002811461271557612731565b6001915050610287565b60ff84111561272657612726612580565b50506001821b610287565b5060208310610133831016604e8410600b8410161715612754575081810a610287565b61275e8383612696565b806000190482111561277257612772612580565b029392505050565b60006108d483836126d9565b6000821982111561279957612799612580565b500190565b634e487b7160e01b600052603160045260246000fdfee6a0172df1f6c41c4af4f1ef2705a2edb2309986a50d87bc4f984cc3cbccc3a5a2646970667358221220aefc0a5a230a3eb4e3d302c6f97de31c2bd657a3fc60b09641ea2691f4e3050e64736f6c63430008090033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.