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