false
true
0

Contract Address Details

0x5C2598630691E3C51Bc17D94119EA990603f4561

Contract Name
TwapOracle
Creator
0x8feb03–b6f785 at 0xfa3505–9cfbcc
Balance
0 tPLS
Tokens
Fetching tokens...
Transactions
3 Transactions
Transfers
0 Transfers
Gas Used
137,753
Last Balance Update
25692668
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
TwapOracle




Optimization enabled
false
Compiler version
v0.8.26+commit.8a97fa7a




EVM Version




Verified at
2026-10-11T05:40:34.739063Z

Constructor Arguments

0000000000000000000000008feb03a1590c041a5ae7d09ff326919129b6f785

Arg [0] (address) : 0x8feb03a1590c041a5ae7d09ff326919129b6f785

              

contracts/oracle/TwapOracle.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {IPulseXPair} from "../interfaces/IProtocol.sol";

/// @title TwapOracle
/// @notice Time-weighted average price oracle over PulseX (Uniswap V2) cumulative prices.
/// @dev Bond pricing and router allocation both read TWAP, never spot. Spot is used
///      only as a sanity bound: if spot deviates from TWAP by more than
///      `maxDeviationBps`, consumers can reject the quote. That combination resists
///      both flash-loan manipulation (which moves spot, not a long TWAP) and stale
///      oracles (which `maxStaleness` rejects).
contract TwapOracle is AccessControl {
    bytes32 public constant UPDATER_ROLE = keccak256("UPDATER_ROLE");

    uint16 public constant BPS_DENOMINATOR = 10_000;

    struct Observation {
        uint256 price0Cumulative;
        uint256 price1Cumulative;
        uint32 timestamp;
        bool initialized;
    }

    /// @notice The newest observation for a pair. May be immature immediately after an
    ///         `update()`, in which case reads fall back to `previousObservations`.
    mapping(address => Observation) public observations;

    /// @notice The observation `update()` displaced. Always at least `minPeriod` older than
    ///         `observations[pair]`, because `update()` refuses to run any sooner.
    ///
    /// @dev THIS SLOT IS THE FIX. With one slot, `update()` reset the averaging window to
    ///      zero and the feed went dark for `minPeriod` - and since `update()`'s own rate
    ///      limit is also `minPeriod`, any caller could hold it dark indefinitely for the
    ///      price of one transaction per window.
    ///
    ///      Keeping the displaced observation means a fresh one never blanks the feed: it
    ///      queues behind a mature one. Availability then depends only on elapsed time,
    ///      which is the property `test/OracleAvailabilityInvariant.t.sol` pins.
    mapping(address => Observation) public previousObservations;

    /// @notice Minimum seconds between observations. Shorter windows are easier to manipulate.
    uint32 public minPeriod = 30 minutes;
    /// @notice An observation older than this is considered unusable.
    /// @notice Oldest observation `consult` will answer from.
    ///
    /// @dev WAS 24 HOURS, AND THAT IS UNUSABLE ONCE THE TWAP IS A TRADING FLOOR.
    ///
    ///      `consult` averages over the whole elapsed window, so a stale observation does
    ///      not merely risk being out of date - it produces a LONGER average, which lags
    ///      spot further in any trend. The router's floor budget is 2%, of which the
    ///      trade's own impact (1% cap) and the pool fee (0.29%) consume 1.29%, leaving
    ///      0.71% for the gap between spot and the average:
    ///
    ///        window   0.5%/h trend   1%/h    2%/h
    ///          30m        0.1%       0.2%    0.5%   <- inside budget
    ///           1h        0.2%       0.5%    1.0%
    ///           2h        0.5%       1.0%    2.0%
    ///          24h        6.0%      12.0%   24.0%   <- 3x the entire floor
    ///
    ///      Both directions hurt, differently. A falling market pushes spot below the
    ///      average and the legs stand down - safe, but the protocol stops buying exactly
    ///      when it is cheapest. A rising market leaves the floor BELOW spot by the lag,
    ///      and that gap is room a sandwicher can take while still clearing the floor.
    ///
    ///      Two hours is the backstop, not the operating point: with `update()` called
    ///      every `minPeriod` the window in use stays at 30-60 minutes, and this only
    ///      binds after three consecutive missed refreshes.
    uint32 public maxStaleness = 2 hours;
    /// @notice Maximum tolerated spot-vs-TWAP divergence before a quote is unsafe.
    uint16 public maxDeviationBps = 1_000; // 10%

    event ObservationUpdated(address indexed pair, uint256 price0Cumulative, uint256 price1Cumulative, uint32 timestamp);
    event OracleParamsUpdated(uint32 minPeriod, uint32 maxStaleness, uint16 maxDeviationBps);

    error PairNotInitialized(address pair);
    error PeriodNotElapsed(address pair, uint32 elapsed, uint32 required);
    error ObservationStale(address pair, uint32 age, uint32 maxAge);
    error NoLiquidity(address pair);
    error TokenNotInPair(address pair, address token);
    error InvalidParams();

    constructor(address admin) {
        if (admin == address(0)) revert InvalidParams();
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
    }

    // --- Observation maintenance --------------------------------------------

    /// @notice Seed the first observation for a pair. Callable once per pair.
    function initialize(address pair) external {
        Observation storage obs = observations[pair];
        if (obs.initialized) return;

        (uint256 price0Cumulative, uint256 price1Cumulative, uint32 timestamp) = currentCumulativePrices(pair);
        obs.price0Cumulative = price0Cumulative;
        obs.price1Cumulative = price1Cumulative;
        obs.timestamp = timestamp;
        obs.initialized = true;

        emit ObservationUpdated(pair, price0Cumulative, price1Cumulative, timestamp);
    }

    /// @notice Roll the observation forward. Permissionless: anyone may keep the
    ///         oracle fresh, but `minPeriod` bounds how often it can be moved.
    function update(address pair) external {
        Observation storage obs = observations[pair];
        if (!obs.initialized) revert PairNotInitialized(pair);

        (uint256 price0Cumulative, uint256 price1Cumulative, uint32 timestamp) = currentCumulativePrices(pair);
        uint32 elapsed;
        unchecked {
            elapsed = timestamp - obs.timestamp; // wraps correctly on uint32 overflow
        }
        if (elapsed < minPeriod) revert PeriodNotElapsed(pair, elapsed, minPeriod);

        // Rotate, do not overwrite. The displaced observation is what keeps the feed
        // answering during the `minPeriod` the new one needs to mature.
        previousObservations[pair] = obs;

        obs.price0Cumulative = price0Cumulative;
        obs.price1Cumulative = price1Cumulative;
        obs.timestamp = timestamp;

        emit ObservationUpdated(pair, price0Cumulative, price1Cumulative, timestamp);
    }

    /// @notice The newest observation that has matured, which is what every read uses.
    ///
    /// @dev Prefers `observations[pair]` once it is at least `minPeriod` old, because a
    ///      more recent window is a tighter average. Falls back to the displaced one while
    ///      the newest is still maturing.
    ///
    ///      The fallback is guaranteed usable rather than merely likely: `update()` reverts
    ///      unless `minPeriod` has elapsed, so anything it displaces is by construction at
    ///      least that old. There is no state in which both slots are immature except
    ///      during the first `minPeriod` after `initialize()`, which is honest - nothing
    ///      has been observed for long enough to average yet.
    function _readable(address pair)
        private
        view
        returns (Observation storage obs, uint32 elapsed)
    {
        (,, uint32 timestamp) = currentCumulativePrices(pair);

        obs = observations[pair];
        unchecked {
            elapsed = timestamp - obs.timestamp;
        }
        if (elapsed >= minPeriod) return (obs, elapsed);

        Observation storage prev = previousObservations[pair];
        if (prev.initialized) {
            uint32 prevElapsed;
            unchecked {
                prevElapsed = timestamp - prev.timestamp;
            }
            if (prevElapsed >= minPeriod) return (prev, prevElapsed);
        }

        // Neither has matured. Return the newest so the caller's own floor/staleness
        // checks produce the accurate error rather than a misleading one.
        return (obs, elapsed);
    }

    // --- Quotes -------------------------------------------------------------

    /// @notice TWAP quote: how much of the other token `amountIn` of `tokenIn` is worth.
    /// @dev Reverts if the observation is missing or stale.
    function consult(address pair, address tokenIn, uint256 amountIn) public view returns (uint256 amountOut) {
        if (!observations[pair].initialized) revert PairNotInitialized(pair);

        (uint256 price0Cumulative, uint256 price1Cumulative,) = currentCumulativePrices(pair);

        // The newest MATURE observation, not simply the newest. See `_readable`.
        (Observation storage obs, uint32 elapsed) = _readable(pair);
        // The averaging window must be at least minPeriod, not merely non-zero.
        //
        // A TWAP is only manipulation-resistant in proportion to the time it averages
        // over. An earlier revision rejected only elapsed == 0, so a one-second-old
        // observation produced a one-second average - spot price wearing a TWAP label.
        // Worse, isQuoteSafe compares spot against that same near-spot average, so the
        // deviation guard endorsed the manipulated number instead of rejecting it.
        //
        // This is NOT specific to initialize(). The exposure recurred after every
        // update(), which is permissionless, so any caller could reset the window and
        // read a manipulated price one block later. Enforcing the floor here fixes both
        // at the read side, where the actual decision is made.
        if (elapsed < minPeriod) revert PeriodNotElapsed(pair, elapsed, minPeriod);
        if (elapsed > maxStaleness) revert ObservationStale(pair, elapsed, maxStaleness);

        address token0 = IPulseXPair(pair).token0();
        address token1 = IPulseXPair(pair).token1();

        uint256 priceAverage;
        if (tokenIn == token0) {
            unchecked {
                priceAverage = (price0Cumulative - obs.price0Cumulative) / elapsed;
            }
        } else if (tokenIn == token1) {
            unchecked {
                priceAverage = (price1Cumulative - obs.price1Cumulative) / elapsed;
            }
        } else {
            revert TokenNotInPair(pair, tokenIn);
        }

        // priceAverage is UQ112x112; shift back down after multiplying.
        amountOut = (priceAverage * amountIn) >> 112;
    }

    /// @notice Current spot quote straight from reserves, for the deviation guard only.
    function spotQuote(address pair, address tokenIn, uint256 amountIn) public view returns (uint256) {
        (uint112 reserve0, uint112 reserve1,) = IPulseXPair(pair).getReserves();
        if (reserve0 == 0 || reserve1 == 0) revert NoLiquidity(pair);

        address token0 = IPulseXPair(pair).token0();
        address token1 = IPulseXPair(pair).token1();

        if (tokenIn == token0) {
            return (amountIn * reserve1) / reserve0;
        } else if (tokenIn == token1) {
            return (amountIn * reserve0) / reserve1;
        }
        revert TokenNotInPair(pair, tokenIn);
    }

    /// @notice True when spot sits within `maxDeviationBps` of the TWAP.
    /// @dev Consumers should treat `false` as "do not trade right now".
    function isQuoteSafe(address pair, address tokenIn, uint256 amountIn) external view returns (bool) {
        uint256 twap = consult(pair, tokenIn, amountIn);
        if (twap == 0) return false;

        uint256 spot = spotQuote(pair, tokenIn, amountIn);
        uint256 diff = spot > twap ? spot - twap : twap - spot;
        return (diff * BPS_DENOMINATOR) / twap <= maxDeviationBps;
    }

    /// @notice Seconds until the observation `consult` reads is `minPeriod` old, or 0 once
    ///         it is. Reverts only if the pair was never initialized.
    ///
    ///         0 does not mean `consult` answers - `isQuotable` says that. Past
    ///         `maxStaleness` this reads 0 too: while nobody refreshes, and for up to
    ///         `minPeriod` after a refresh that came too late, when the observation it
    ///         displaced is the readable one. In the second case the wait is what remains
    ///         of `minPeriod` on `observations(pair)`; in the first, only `update()` starts it.
    /// @dev A quote refusal during an immature window is a safety behaviour, but it
    ///      reaches a user as a revert, which is indistinguishable from a broken
    ///      contract. This lets a caller render "try again in N seconds" instead, so
    ///      nobody is tempted to "fix" the safety behaviour later. Read it together with
    ///      `isQuotable`, as `scripts/lib/oracle-state.js` does.
    function secondsUntilQuotable(address pair) external view returns (uint256) {
        if (!observations[pair].initialized) revert PairNotInitialized(pair);

        // Must agree with `consult`, which reads the newest MATURE observation. Reading
        // the raw newest slot here would report a wait that consult does not actually
        // impose - the reporting bug that hides the fix rather than the defect.
        (, uint32 elapsed) = _readable(pair);
        return elapsed >= minPeriod ? 0 : minPeriod - elapsed;
    }

    /// @notice True when `consult` would answer for this pair right now.
    function isQuotable(address pair) external view returns (bool) {
        if (!observations[pair].initialized) return false;

        // Same source of truth as `consult`. These two disagreeing is how a monitor
        // reports a healthy feed that cannot answer, or a dark feed that can.
        (, uint32 elapsed) = _readable(pair);
        return elapsed >= minPeriod && elapsed <= maxStaleness;
    }

    // --- Cumulative price reader --------------------------------------------

    /// @notice Cumulative prices brought forward to `block.timestamp`.
    /// @dev Mirrors UniswapV2OracleLibrary: the pair only writes cumulatives on sync,
    ///      so the elapsed-since-sync portion must be added in by the reader.
    function currentCumulativePrices(address pair)
        public
        view
        returns (uint256 price0Cumulative, uint256 price1Cumulative, uint32 blockTimestamp)
    {
        blockTimestamp = uint32(block.timestamp % 2 ** 32);
        price0Cumulative = IPulseXPair(pair).price0CumulativeLast();
        price1Cumulative = IPulseXPair(pair).price1CumulativeLast();

        (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IPulseXPair(pair).getReserves();
        if (reserve0 == 0 || reserve1 == 0) revert NoLiquidity(pair);

        if (blockTimestampLast != blockTimestamp) {
            uint32 timeElapsed;
            unchecked {
                timeElapsed = blockTimestamp - blockTimestampLast;
                price0Cumulative += uint256(_encodeDiv(reserve1, reserve0)) * timeElapsed;
                price1Cumulative += uint256(_encodeDiv(reserve0, reserve1)) * timeElapsed;
            }
        }
    }

    /// @dev UQ112x112 encode-then-divide: (numerator << 112) / denominator.
    function _encodeDiv(uint112 numerator, uint112 denominator) private pure returns (uint224) {
        return uint224((uint224(numerator) << 112) / denominator);
    }

    // --- Governance ---------------------------------------------------------

    function setParams(uint32 minPeriod_, uint32 maxStaleness_, uint16 maxDeviationBps_)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        if (minPeriod_ == 0 || maxStaleness_ < minPeriod_ || maxDeviationBps_ > BPS_DENOMINATOR) {
            revert InvalidParams();
        }
        minPeriod = minPeriod_;
        maxStaleness = maxStaleness_;
        maxDeviationBps = maxDeviationBps_;
        emit OracleParamsUpdated(minPeriod_, maxStaleness_, maxDeviationBps_);
    }
}
        

contracts/interfaces/IProtocol.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

/// @notice Minimal PulseX (Uniswap V2) surface used across the protocol.
interface IPulseXFactory {
    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function createPair(address tokenA, address tokenB) external returns (address pair);
}

interface IPulseXPair {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint256);
    function price1CumulativeLast() external view returns (uint256);
    function totalSupply() external view returns (uint256);
    /// @dev A V2 pair is itself the LP ERC-20, so holdings are read from the pair.
    function balanceOf(address account) external view returns (uint256);
}

interface IPulseXRouter {
    function factory() external view returns (address);
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
    function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);
}

/// @notice Burnable subset of PBURN used by the router and the credit ledger.
interface IBurnable {
    function burn(uint256 amount) external;
    function totalSupply() external view returns (uint256);
}

/// @notice Credit accrual hook. Only protocol contracts may call the granting functions.
interface IBurnCreditLedger {
    function creditsOf(address account) external view returns (uint256);
    function feeDiscountBps(address account) external view returns (uint16);
    function grantForBurn(address account, uint256 burnedAmount) external;
    function grantForBond(address account, uint256 lpValue) external;
    function grantForGovernance(address account, uint256 weight) external;
}

/// @notice Read-only composite treasury health score consumed by the router.
interface ITSI {
    /// @return score Composite score in basis points (0..10000).
    function score() external view returns (uint256);
    function components()
        external
        view
        returns (uint256 treasuryValue, uint256 polValue, uint256 burnRate, uint256 liquidityDepth, uint256 supplyTrend);
}

/// @notice Treasury deposit surface used by the router and bonding vault.
interface ITreasury {
    function recordDeposit(address asset, uint256 amount) external;
    function recordLpDeposit(address pair, uint256 amount) external;
}

/// @notice Epoch parameter presets consumed by the router.
interface IEpoch {
    enum Phase {
        Bootstrapping,
        AcceleratedBurn,
        GovernanceAndGrowth,
        Sustainability
    }

    function currentPhase() external view returns (Phase);
    function allocation() external view returns (uint16 pburnBurnBps, uint16 pflyBurnBps, uint16 polBps, uint16 treasuryBps);
}
          

lib/openzeppelin-contracts/contracts/access/IAccessControl.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}
          

lib/openzeppelin-contracts/contracts/utils/Context.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
          

lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
          

lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
          

lib/openzeppelin-contracts/contracts/access/AccessControl.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
          

Compiler Settings

{"viaIR":false,"remappings":["@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","forge-std/=lib/forge-std/src/","ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/"],"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{},"evmVersion":"paris"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"admin","internalType":"address"}]},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bytes32","name":"neededRole","internalType":"bytes32"}]},{"type":"error","name":"InvalidParams","inputs":[]},{"type":"error","name":"NoLiquidity","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"error","name":"ObservationStale","inputs":[{"type":"address","name":"pair","internalType":"address"},{"type":"uint32","name":"age","internalType":"uint32"},{"type":"uint32","name":"maxAge","internalType":"uint32"}]},{"type":"error","name":"PairNotInitialized","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"error","name":"PeriodNotElapsed","inputs":[{"type":"address","name":"pair","internalType":"address"},{"type":"uint32","name":"elapsed","internalType":"uint32"},{"type":"uint32","name":"required","internalType":"uint32"}]},{"type":"error","name":"TokenNotInPair","inputs":[{"type":"address","name":"pair","internalType":"address"},{"type":"address","name":"token","internalType":"address"}]},{"type":"event","name":"ObservationUpdated","inputs":[{"type":"address","name":"pair","internalType":"address","indexed":true},{"type":"uint256","name":"price0Cumulative","internalType":"uint256","indexed":false},{"type":"uint256","name":"price1Cumulative","internalType":"uint256","indexed":false},{"type":"uint32","name":"timestamp","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"OracleParamsUpdated","inputs":[{"type":"uint32","name":"minPeriod","internalType":"uint32","indexed":false},{"type":"uint32","name":"maxStaleness","internalType":"uint32","indexed":false},{"type":"uint16","name":"maxDeviationBps","internalType":"uint16","indexed":false}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"BPS_DENOMINATOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"UPDATER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"}],"name":"consult","inputs":[{"type":"address","name":"pair","internalType":"address"},{"type":"address","name":"tokenIn","internalType":"address"},{"type":"uint256","name":"amountIn","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price0Cumulative","internalType":"uint256"},{"type":"uint256","name":"price1Cumulative","internalType":"uint256"},{"type":"uint32","name":"blockTimestamp","internalType":"uint32"}],"name":"currentCumulativePrices","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isQuotable","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isQuoteSafe","inputs":[{"type":"address","name":"pair","internalType":"address"},{"type":"address","name":"tokenIn","internalType":"address"},{"type":"uint256","name":"amountIn","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"maxDeviationBps","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"maxStaleness","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"minPeriod","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price0Cumulative","internalType":"uint256"},{"type":"uint256","name":"price1Cumulative","internalType":"uint256"},{"type":"uint32","name":"timestamp","internalType":"uint32"},{"type":"bool","name":"initialized","internalType":"bool"}],"name":"observations","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price0Cumulative","internalType":"uint256"},{"type":"uint256","name":"price1Cumulative","internalType":"uint256"},{"type":"uint32","name":"timestamp","internalType":"uint32"},{"type":"bool","name":"initialized","internalType":"bool"}],"name":"previousObservations","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"callerConfirmation","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"secondsUntilQuotable","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setParams","inputs":[{"type":"uint32","name":"minPeriod_","internalType":"uint32"},{"type":"uint32","name":"maxStaleness_","internalType":"uint32"},{"type":"uint16","name":"maxDeviationBps_","internalType":"uint16"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"spotQuote","inputs":[{"type":"address","name":"pair","internalType":"address"},{"type":"address","name":"tokenIn","internalType":"address"},{"type":"uint256","name":"amountIn","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"update","inputs":[{"type":"address","name":"pair","internalType":"address"}]}]
              

Contract Creation Code

0x6080604052600380546001600160501b0319166903e800001c200000070817905534801561002c57600080fd5b506040516116e33803806116e383398101604081905261004b91610130565b6001600160a01b03811661007257604051635435b28960e11b815260040160405180910390fd5b61007d600082610084565b5050610160565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16610126576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556100de3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161012a565b5060005b92915050565b60006020828403121561014257600080fd5b81516001600160a01b038116811461015957600080fd5b9392505050565b6115748061016f6000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c806347e63380116100c3578063ad599b971161007c578063ad599b971461037d578063c4d66de8146103bd578063d547741f146103d0578063d69a9a99146103e3578063e1a45218146103f6578063ffd49c84146103ff57600080fd5b806347e633801461028e578063636cfa0c146102b557806387cf4696146102c85780638a04ff3c146102f457806391d1485414610362578063a217fddf1461037557600080fd5b8063248a9ca311610115578063248a9ca3146101c85780632f2ff15d146101f957806336568abe1461020c57806339ced6d41461021f5780633ee7a701146102325780633f14dccd1461025a57600080fd5b806301ffc9a71461015257806308b8dbf11461017a5780631886685e1461018d57806318caeb9d146101a25780631c1b8772146101b5575b600080fd5b610165610160366004611276565b61040f565b60405190151581526020015b60405180910390f35b6101656101883660046112b5565b610446565b6101a061019b366004611308565b6104d0565b005b6101656101b036600461135a565b6105b7565b6101a06101c336600461135a565b61062b565b6101eb6101d6366004611377565b60009081526020819052604090206001015490565b604051908152602001610171565b6101a0610207366004611390565b6107a3565b6101a061021a366004611390565b6107ce565b6101eb61022d36600461135a565b610806565b60035461024790600160401b900461ffff1681565b60405161ffff9091168152602001610171565b61026d61026836600461135a565b6108a1565b60408051938452602084019290925263ffffffff1690820152606001610171565b6101eb7f73e573f9566d61418a34d5de3ff49360f9c51fec37f7486551670290f6285dab81565b6101eb6102c33660046112b5565b610a92565b6003546102df90600160201b900463ffffffff1681565b60405163ffffffff9091168152602001610171565b61033461030236600461135a565b600160208190526000918252604090912080549181015460029091015463ffffffff811690600160201b900460ff1684565b6040516101719493929190938452602084019290925263ffffffff1660408301521515606082015260800190565b610165610370366004611390565b610d0b565b6101eb600081565b61033461038b36600461135a565b600260208190526000918252604090912080546001820154919092015463ffffffff811690600160201b900460ff1684565b6101a06103cb36600461135a565b610d34565b6101a06103de366004611390565b610df9565b6101eb6103f13660046112b5565b610e1e565b61024761271081565b6003546102df9063ffffffff1681565b60006001600160e01b03198216637965db0b60e01b148061044057506301ffc9a760e01b6001600160e01b03198316145b92915050565b600080610454858585610a92565b9050806000036104685760009150506104c9565b6000610475868686610e1e565b9050600082821161048f5761048a82846113d6565b610499565b61049983836113d6565b600354909150600160401b900461ffff16836104b7612710846113e9565b6104c19190611416565b111593505050505b9392505050565b60006104db8161104f565b63ffffffff841615806104f957508363ffffffff168363ffffffff16105b80610509575061271061ffff8316115b1561052757604051635435b28960e11b815260040160405180910390fd5b6003805463ffffffff86811667ffffffffffffffff199092168217600160201b9187169182021769ffff00000000000000001916600160401b61ffff8716908102919091179093556040805192835260208301919091528101919091527f0e3491c6c73942722735153d2c156e7b452106adf2573cbaafb4c6be4f18c4a69060600160405180910390a150505050565b6001600160a01b038116600090815260016020526040812060020154600160201b900460ff166105e957506000919050565b60006105f48361105c565b60035490925063ffffffff90811690831610801591506104c95750600354600160201b900463ffffffff9081169116111592915050565b6001600160a01b03811660009081526001602052604090206002810154600160201b900460ff1661067f5760405163069c508d60e31b81526001600160a01b03831660048201526024015b60405180910390fd5b600080600061068d856108a1565b6002870154600354939650919450925063ffffffff908116830391811690821610156106da5760035460405163386734dd60e21b8152610676918891849163ffffffff169060040161142a565b6001600160a01b038616600081815260026020818152604092839020895481556001808b018054918301919091558a8401805492909401805463ffffffff1980821663ffffffff9586169081178455875460ff600160201b918290041615150264ffffffffff1990931617919091179091558a8c55908990558354918816911681179092558251888152908101879052918201527f8c65b5cef7be4417296e3570bac50029e7ff1a1f0d68ded2170f9808d5bb02809060600160405180910390a2505050505050565b6000828152602081905260409020600101546107be8161104f565b6107c88383611110565b50505050565b6001600160a01b03811633146107f75760405163334bd91960e11b815260040160405180910390fd5b61080182826111a2565b505050565b6001600160a01b038116600090815260016020526040812060020154600160201b900460ff166108545760405163069c508d60e31b81526001600160a01b0383166004820152602401610676565b600061085f8361105c565b60035490925063ffffffff908116908316101590506108915760035461088c90829063ffffffff16611451565b610894565b60005b63ffffffff169392505050565b600080806108b3600160201b4261146d565b9050836001600160a01b0316635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109179190611481565b9250836001600160a01b0316635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa158015610957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097b9190611481565b91506000806000866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156109c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e491906114b6565b925092509250826001600160701b031660001480610a0957506001600160701b038216155b15610a32576040516324ae9bb960e21b81526001600160a01b0388166004820152602401610676565b8363ffffffff168163ffffffff1614610a885780840363ffffffff8116610a59848661120d565b6001600160e01b031602870196508063ffffffff16610a78858561120d565b6001600160e01b03160286019550505b5050509193909250565b6001600160a01b038316600090815260016020526040812060020154600160201b900460ff16610ae05760405163069c508d60e31b81526001600160a01b0385166004820152602401610676565b600080610aec866108a1565b5091509150600080610afd8861105c565b600354919350915063ffffffff9081169082161015610b3d5760035460405163386734dd60e21b8152610676918a91849163ffffffff169060040161142a565b60035463ffffffff600160201b90910481169082161115610b865760035460405163194eb19b60e31b8152610676918a918491600160201b900463ffffffff169060040161142a565b6000886001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bea91906114f2565b90506000896001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5091906114f2565b90506000826001600160a01b03168a6001600160a01b031603610c8e57845463ffffffff851690880381610c8657610c86611400565b049050610cee565b816001600160a01b03168a6001600160a01b031603610cc2578363ffffffff168560010154870381610c8657610c86611400565b604051638a9bb81760e01b81526001600160a01b03808d1660048301528b166024820152604401610676565b6070610cfa8a836113e9565b901c9b9a5050505050505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6001600160a01b03811660009081526001602052604090206002810154600160201b900460ff1615610d64575050565b6000806000610d72856108a1565b8287556001870182905560028701805464ffffffffff191663ffffffff8316908117600160201b1790915560408051858152602081018590529081019190915292955090935091506001600160a01b038616907f8c65b5cef7be4417296e3570bac50029e7ff1a1f0d68ded2170f9808d5bb02809060600160405180910390a25050505050565b600082815260208190526040902060010154610e148161104f565b6107c883836111a2565b6000806000856001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610e61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8591906114b6565b5091509150816001600160701b031660001480610ea957506001600160701b038116155b15610ed2576040516324ae9bb960e21b81526001600160a01b0387166004820152602401610676565b6000866001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3691906114f2565b90506000876001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9c91906114f2565b9050816001600160a01b0316876001600160a01b031603610feb57836001600160701b0316836001600160701b031687610fd691906113e9565b610fe09190611416565b9450505050506104c9565b806001600160a01b0316876001600160a01b03160361102357826001600160701b0316846001600160701b031687610fd691906113e9565b604051638a9bb81760e01b81526001600160a01b03808a16600483015288166024820152604401610676565b6110598133611239565b50565b600080600061106a846108a1565b6001600160a01b0387166000908152600160205260409020600281015460035491975063ffffffff9081168303965091945081169085161091506110b090505750915091565b6001600160a01b038416600090815260026020819052604090912090810154600160201b900460ff161561110957600281015460035463ffffffff9182168403919081169082161061110757909590945092505050565b505b5050915091565b600061111c8383610d0b565b61119a576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556111523390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610440565b506000610440565b60006111ae8383610d0b565b1561119a576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610440565b60006104c96001600160701b0383166dffffffffffffffffffffffffffff60701b607086901b1661150f565b6112438282610d0b565b6112725760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610676565b5050565b60006020828403121561128857600080fd5b81356001600160e01b0319811681146104c957600080fd5b6001600160a01b038116811461105957600080fd5b6000806000606084860312156112ca57600080fd5b83356112d5816112a0565b925060208401356112e5816112a0565b929592945050506040919091013590565b63ffffffff8116811461105957600080fd5b60008060006060848603121561131d57600080fd5b8335611328816112f6565b92506020840135611338816112f6565b9150604084013561ffff8116811461134f57600080fd5b809150509250925092565b60006020828403121561136c57600080fd5b81356104c9816112a0565b60006020828403121561138957600080fd5b5035919050565b600080604083850312156113a357600080fd5b8235915060208301356113b5816112a0565b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610440576104406113c0565b8082028115828204841417610440576104406113c0565b634e487b7160e01b600052601260045260246000fd5b60008261142557611425611400565b500490565b6001600160a01b0393909316835263ffffffff918216602084015216604082015260600190565b63ffffffff8281168282160390811115610440576104406113c0565b60008261147c5761147c611400565b500690565b60006020828403121561149357600080fd5b5051919050565b80516001600160701b03811681146114b157600080fd5b919050565b6000806000606084860312156114cb57600080fd5b6114d48461149a565b92506114e26020850161149a565b9150604084015161134f816112f6565b60006020828403121561150457600080fd5b81516104c9816112a0565b60006001600160e01b0383168061152857611528611400565b6001600160e01b0392909216919091049291505056fea26469706673582212202371edba5d38050412cfdde2c96f21192f6be4ec60c8859d7fb9510e62d76ab764736f6c634300081a00330000000000000000000000008feb03a1590c041a5ae7d09ff326919129b6f785

Deployed ByteCode

0x608060405234801561001057600080fd5b506004361061014d5760003560e01c806347e63380116100c3578063ad599b971161007c578063ad599b971461037d578063c4d66de8146103bd578063d547741f146103d0578063d69a9a99146103e3578063e1a45218146103f6578063ffd49c84146103ff57600080fd5b806347e633801461028e578063636cfa0c146102b557806387cf4696146102c85780638a04ff3c146102f457806391d1485414610362578063a217fddf1461037557600080fd5b8063248a9ca311610115578063248a9ca3146101c85780632f2ff15d146101f957806336568abe1461020c57806339ced6d41461021f5780633ee7a701146102325780633f14dccd1461025a57600080fd5b806301ffc9a71461015257806308b8dbf11461017a5780631886685e1461018d57806318caeb9d146101a25780631c1b8772146101b5575b600080fd5b610165610160366004611276565b61040f565b60405190151581526020015b60405180910390f35b6101656101883660046112b5565b610446565b6101a061019b366004611308565b6104d0565b005b6101656101b036600461135a565b6105b7565b6101a06101c336600461135a565b61062b565b6101eb6101d6366004611377565b60009081526020819052604090206001015490565b604051908152602001610171565b6101a0610207366004611390565b6107a3565b6101a061021a366004611390565b6107ce565b6101eb61022d36600461135a565b610806565b60035461024790600160401b900461ffff1681565b60405161ffff9091168152602001610171565b61026d61026836600461135a565b6108a1565b60408051938452602084019290925263ffffffff1690820152606001610171565b6101eb7f73e573f9566d61418a34d5de3ff49360f9c51fec37f7486551670290f6285dab81565b6101eb6102c33660046112b5565b610a92565b6003546102df90600160201b900463ffffffff1681565b60405163ffffffff9091168152602001610171565b61033461030236600461135a565b600160208190526000918252604090912080549181015460029091015463ffffffff811690600160201b900460ff1684565b6040516101719493929190938452602084019290925263ffffffff1660408301521515606082015260800190565b610165610370366004611390565b610d0b565b6101eb600081565b61033461038b36600461135a565b600260208190526000918252604090912080546001820154919092015463ffffffff811690600160201b900460ff1684565b6101a06103cb36600461135a565b610d34565b6101a06103de366004611390565b610df9565b6101eb6103f13660046112b5565b610e1e565b61024761271081565b6003546102df9063ffffffff1681565b60006001600160e01b03198216637965db0b60e01b148061044057506301ffc9a760e01b6001600160e01b03198316145b92915050565b600080610454858585610a92565b9050806000036104685760009150506104c9565b6000610475868686610e1e565b9050600082821161048f5761048a82846113d6565b610499565b61049983836113d6565b600354909150600160401b900461ffff16836104b7612710846113e9565b6104c19190611416565b111593505050505b9392505050565b60006104db8161104f565b63ffffffff841615806104f957508363ffffffff168363ffffffff16105b80610509575061271061ffff8316115b1561052757604051635435b28960e11b815260040160405180910390fd5b6003805463ffffffff86811667ffffffffffffffff199092168217600160201b9187169182021769ffff00000000000000001916600160401b61ffff8716908102919091179093556040805192835260208301919091528101919091527f0e3491c6c73942722735153d2c156e7b452106adf2573cbaafb4c6be4f18c4a69060600160405180910390a150505050565b6001600160a01b038116600090815260016020526040812060020154600160201b900460ff166105e957506000919050565b60006105f48361105c565b60035490925063ffffffff90811690831610801591506104c95750600354600160201b900463ffffffff9081169116111592915050565b6001600160a01b03811660009081526001602052604090206002810154600160201b900460ff1661067f5760405163069c508d60e31b81526001600160a01b03831660048201526024015b60405180910390fd5b600080600061068d856108a1565b6002870154600354939650919450925063ffffffff908116830391811690821610156106da5760035460405163386734dd60e21b8152610676918891849163ffffffff169060040161142a565b6001600160a01b038616600081815260026020818152604092839020895481556001808b018054918301919091558a8401805492909401805463ffffffff1980821663ffffffff9586169081178455875460ff600160201b918290041615150264ffffffffff1990931617919091179091558a8c55908990558354918816911681179092558251888152908101879052918201527f8c65b5cef7be4417296e3570bac50029e7ff1a1f0d68ded2170f9808d5bb02809060600160405180910390a2505050505050565b6000828152602081905260409020600101546107be8161104f565b6107c88383611110565b50505050565b6001600160a01b03811633146107f75760405163334bd91960e11b815260040160405180910390fd5b61080182826111a2565b505050565b6001600160a01b038116600090815260016020526040812060020154600160201b900460ff166108545760405163069c508d60e31b81526001600160a01b0383166004820152602401610676565b600061085f8361105c565b60035490925063ffffffff908116908316101590506108915760035461088c90829063ffffffff16611451565b610894565b60005b63ffffffff169392505050565b600080806108b3600160201b4261146d565b9050836001600160a01b0316635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109179190611481565b9250836001600160a01b0316635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa158015610957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097b9190611481565b91506000806000866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156109c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e491906114b6565b925092509250826001600160701b031660001480610a0957506001600160701b038216155b15610a32576040516324ae9bb960e21b81526001600160a01b0388166004820152602401610676565b8363ffffffff168163ffffffff1614610a885780840363ffffffff8116610a59848661120d565b6001600160e01b031602870196508063ffffffff16610a78858561120d565b6001600160e01b03160286019550505b5050509193909250565b6001600160a01b038316600090815260016020526040812060020154600160201b900460ff16610ae05760405163069c508d60e31b81526001600160a01b0385166004820152602401610676565b600080610aec866108a1565b5091509150600080610afd8861105c565b600354919350915063ffffffff9081169082161015610b3d5760035460405163386734dd60e21b8152610676918a91849163ffffffff169060040161142a565b60035463ffffffff600160201b90910481169082161115610b865760035460405163194eb19b60e31b8152610676918a918491600160201b900463ffffffff169060040161142a565b6000886001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bea91906114f2565b90506000896001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5091906114f2565b90506000826001600160a01b03168a6001600160a01b031603610c8e57845463ffffffff851690880381610c8657610c86611400565b049050610cee565b816001600160a01b03168a6001600160a01b031603610cc2578363ffffffff168560010154870381610c8657610c86611400565b604051638a9bb81760e01b81526001600160a01b03808d1660048301528b166024820152604401610676565b6070610cfa8a836113e9565b901c9b9a5050505050505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6001600160a01b03811660009081526001602052604090206002810154600160201b900460ff1615610d64575050565b6000806000610d72856108a1565b8287556001870182905560028701805464ffffffffff191663ffffffff8316908117600160201b1790915560408051858152602081018590529081019190915292955090935091506001600160a01b038616907f8c65b5cef7be4417296e3570bac50029e7ff1a1f0d68ded2170f9808d5bb02809060600160405180910390a25050505050565b600082815260208190526040902060010154610e148161104f565b6107c883836111a2565b6000806000856001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610e61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8591906114b6565b5091509150816001600160701b031660001480610ea957506001600160701b038116155b15610ed2576040516324ae9bb960e21b81526001600160a01b0387166004820152602401610676565b6000866001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3691906114f2565b90506000876001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9c91906114f2565b9050816001600160a01b0316876001600160a01b031603610feb57836001600160701b0316836001600160701b031687610fd691906113e9565b610fe09190611416565b9450505050506104c9565b806001600160a01b0316876001600160a01b03160361102357826001600160701b0316846001600160701b031687610fd691906113e9565b604051638a9bb81760e01b81526001600160a01b03808a16600483015288166024820152604401610676565b6110598133611239565b50565b600080600061106a846108a1565b6001600160a01b0387166000908152600160205260409020600281015460035491975063ffffffff9081168303965091945081169085161091506110b090505750915091565b6001600160a01b038416600090815260026020819052604090912090810154600160201b900460ff161561110957600281015460035463ffffffff9182168403919081169082161061110757909590945092505050565b505b5050915091565b600061111c8383610d0b565b61119a576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556111523390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610440565b506000610440565b60006111ae8383610d0b565b1561119a576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610440565b60006104c96001600160701b0383166dffffffffffffffffffffffffffff60701b607086901b1661150f565b6112438282610d0b565b6112725760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610676565b5050565b60006020828403121561128857600080fd5b81356001600160e01b0319811681146104c957600080fd5b6001600160a01b038116811461105957600080fd5b6000806000606084860312156112ca57600080fd5b83356112d5816112a0565b925060208401356112e5816112a0565b929592945050506040919091013590565b63ffffffff8116811461105957600080fd5b60008060006060848603121561131d57600080fd5b8335611328816112f6565b92506020840135611338816112f6565b9150604084013561ffff8116811461134f57600080fd5b809150509250925092565b60006020828403121561136c57600080fd5b81356104c9816112a0565b60006020828403121561138957600080fd5b5035919050565b600080604083850312156113a357600080fd5b8235915060208301356113b5816112a0565b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610440576104406113c0565b8082028115828204841417610440576104406113c0565b634e487b7160e01b600052601260045260246000fd5b60008261142557611425611400565b500490565b6001600160a01b0393909316835263ffffffff918216602084015216604082015260600190565b63ffffffff8281168282160390811115610440576104406113c0565b60008261147c5761147c611400565b500690565b60006020828403121561149357600080fd5b5051919050565b80516001600160701b03811681146114b157600080fd5b919050565b6000806000606084860312156114cb57600080fd5b6114d48461149a565b92506114e26020850161149a565b9150604084015161134f816112f6565b60006020828403121561150457600080fd5b81516104c9816112a0565b60006001600160e01b0383168061152857611528611400565b6001600160e01b0392909216919091049291505056fea26469706673582212202371edba5d38050412cfdde2c96f21192f6be4ec60c8859d7fb9510e62d76ab764736f6c634300081a0033