Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
TokenRateOracle
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 100000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; import {ITokenRateUpdatable} from "./interfaces/ITokenRateUpdatable.sol"; import {IChainlinkAggregatorInterface} from "./interfaces/IChainlinkAggregatorInterface.sol"; import {CrossDomainEnabled} from "./CrossDomainEnabled.sol"; import {Versioned} from "../utils/Versioned.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {UnstructuredStorage} from "../lib/UnstructuredStorage.sol"; interface ITokenRateOracle is ITokenRateUpdatable, IChainlinkAggregatorInterface {} /// @author kovalgek /// @notice Oracle for storing and providing token rate. /// NB: Cross-chain apps and CEXes should fetch the token rate specific to the chain for deposits/withdrawals /// and compare against the token rate on L1 being an ultimate source of truth; /// If the L1 rate differs, it can be pushed permissionlessly via OpStackTokenRatePusher. /// @dev Token rate updates can be delivered from two sources: L1 token rate pusher and L2 bridge. contract TokenRateOracle is ITokenRateOracle, CrossDomainEnabled, AccessControl, Versioned { using UnstructuredStorage for bytes32; /// @dev Used to store historical data of rate and times. struct TokenRateData { /// @notice wstETH/stETH token rate. uint128 tokenRate; /// @notice last time when token rate was updated on L1. uint64 rateUpdatedL1Timestamp; /// @notice last time when token rate was received on L2. uint64 rateReceivedL2Timestamp; } // occupies a single slot /// @notice A bridge which can update oracle. address public immutable L2_ERC20_TOKEN_BRIDGE; /// @notice An address of account on L1 that can update token rate. address public immutable L1_TOKEN_RATE_PUSHER; /// @notice A time period when token rate can be considered outdated. uint256 public immutable TOKEN_RATE_OUTDATED_DELAY; /// @notice A time difference between received l1Timestamp and L2 block.timestamp /// when token rate can be considered outdated. uint256 public immutable MAX_ALLOWED_L2_TO_L1_CLOCK_LAG; /// @notice Allowed token rate deviation per day in basic points. uint256 public immutable MAX_ALLOWED_TOKEN_RATE_DEVIATION_PER_DAY_BP; /// @notice The maximum allowed time difference between the current time and the last received /// token rate update that can be set during a pause. This is required to limit the pause role /// and mitigate potential economic attacks. /// See the 'pauseTokenRateUpdates()' method uint256 public immutable OLDEST_RATE_ALLOWED_IN_PAUSE_TIME_SPAN; /// @notice The minimum delta time between two L1 timestamps of token rate updates. uint256 public immutable MIN_TIME_BETWEEN_TOKEN_RATE_UPDATES; /// @notice Decimals of the oracle response. uint8 public constant DECIMALS = 27; /// @notice Max sane token rate value. uint256 public constant MAX_SANE_TOKEN_RATE = 10 ** (DECIMALS + 2); /// @notice Min sane token rate value. uint256 public constant MIN_SANE_TOKEN_RATE = 10 ** (DECIMALS - 2); /// @dev Role granting the permission to pause updating rate. bytes32 public constant RATE_UPDATE_DISABLER_ROLE = keccak256("TokenRateOracle.RATE_UPDATE_DISABLER_ROLE"); /// @dev Role granting the permission to resume updating rate. bytes32 public constant RATE_UPDATE_ENABLER_ROLE = keccak256("TokenRafteOracle.RATE_UPDATE_ENABLER_ROLE"); /// @notice Basic point scale. uint256 private constant BASIS_POINT_SCALE = 1e4; /// @notice Number of seconds in one day. uint256 private constant ONE_DAY_SECONDS = 86400; /// @notice Flag to pause token rate updates slot position. bytes32 private constant PAUSE_TOKEN_RATE_UPDATES_SLOT = keccak256("TokenRateOracle.PAUSE_TOKEN_RATE_UPDATES_SLOT"); /// @notice Token rates array slot position. bytes32 private constant TOKEN_RATES_DATA_SLOT = keccak256("TokenRateOracle.TOKEN_RATES_DATA_SLOT"); /// @param messenger_ L2 messenger address being used for cross-chain communications /// @param l2ERC20TokenBridge_ the bridge address that has a right to updates oracle. /// @param l1TokenRatePusher_ An address of account on L1 that can update token rate. /// @param tokenRateOutdatedDelay_ time period when token rate can be considered outdated. /// @param maxAllowedL2ToL1ClockLag_ A time difference between received l1Timestamp and L2 block.timestamp /// when token rate can be considered outdated. /// @param maxAllowedTokenRateDeviationPerDayBp_ Allowed token rate deviation per day in basic points. /// Can't be bigger than BASIS_POINT_SCALE. /// @param oldestRateAllowedInPauseTimeSpan_ Maximum allowed time difference between the current time /// and the last received token rate update that can be set during a pause. /// @param minTimeBetweenTokenRateUpdates_ Minimum delta time between two /// L1 timestamps of token rate updates. constructor( address messenger_, address l2ERC20TokenBridge_, address l1TokenRatePusher_, uint256 tokenRateOutdatedDelay_, uint256 maxAllowedL2ToL1ClockLag_, uint256 maxAllowedTokenRateDeviationPerDayBp_, uint256 oldestRateAllowedInPauseTimeSpan_, uint256 minTimeBetweenTokenRateUpdates_ ) CrossDomainEnabled(messenger_) { if (l2ERC20TokenBridge_ == address(0)) { revert ErrorZeroAddressL2ERC20TokenBridge(); } if (l1TokenRatePusher_ == address(0)) { revert ErrorZeroAddressL1TokenRatePusher(); } if (maxAllowedTokenRateDeviationPerDayBp_ == 0 || maxAllowedTokenRateDeviationPerDayBp_ > BASIS_POINT_SCALE) { revert ErrorMaxTokenRateDeviationIsOutOfRange(); } L2_ERC20_TOKEN_BRIDGE = l2ERC20TokenBridge_; L1_TOKEN_RATE_PUSHER = l1TokenRatePusher_; TOKEN_RATE_OUTDATED_DELAY = tokenRateOutdatedDelay_; MAX_ALLOWED_L2_TO_L1_CLOCK_LAG = maxAllowedL2ToL1ClockLag_; MAX_ALLOWED_TOKEN_RATE_DEVIATION_PER_DAY_BP = maxAllowedTokenRateDeviationPerDayBp_; OLDEST_RATE_ALLOWED_IN_PAUSE_TIME_SPAN = oldestRateAllowedInPauseTimeSpan_; MIN_TIME_BETWEEN_TOKEN_RATE_UPDATES = minTimeBetweenTokenRateUpdates_; } /// @notice Initializes the contract from scratch. /// @param admin_ Address of the account to grant the DEFAULT_ADMIN_ROLE /// @param tokenRate_ wstETH/stETH token rate, uses 10**DECIMALS precision. /// @param rateUpdatedL1Timestamp_ L1 time when rate was updated on L1 side. function initialize(address admin_, uint256 tokenRate_, uint256 rateUpdatedL1Timestamp_) external { _initializeContractVersionTo(1); if (admin_ == address(0)) { revert ErrorZeroAddressAdmin(); } if (tokenRate_ < MIN_SANE_TOKEN_RATE || tokenRate_ > MAX_SANE_TOKEN_RATE) { revert ErrorTokenRateIsOutOfSaneRange(tokenRate_); } if (rateUpdatedL1Timestamp_ > block.timestamp + MAX_ALLOWED_L2_TO_L1_CLOCK_LAG) { revert ErrorL1TimestampExceededMaxAllowedClockLag(rateUpdatedL1Timestamp_); } _grantRole(DEFAULT_ADMIN_ROLE, admin_); _addTokenRate(tokenRate_, rateUpdatedL1Timestamp_, block.timestamp); } /// @notice Pauses token rate updates and sets the old rate provided by tokenRateIndex_. /// Should be called by DAO or emergency brakes only. /// @param tokenRateIndex_ The index of the token rate that applies after the pause. /// Token Rate can't be received older then OLDEST_RATE_ALLOWED_IN_PAUSE_TIME_SPAN /// except only if the passed index is the latest one. function pauseTokenRateUpdates(uint256 tokenRateIndex_) external onlyRole(RATE_UPDATE_DISABLER_ROLE) { if (_isPaused()) { revert ErrorAlreadyPaused(); } TokenRateData memory tokenRateData = _getTokenRateByIndex(tokenRateIndex_); if (tokenRateIndex_ != _getStorageTokenRates().length - 1 && tokenRateData.rateReceivedL2Timestamp < block.timestamp - OLDEST_RATE_ALLOWED_IN_PAUSE_TIME_SPAN) { revert ErrorTokenRateUpdateTooOld(); } _removeElementsAfterIndex(tokenRateIndex_); _setPause(true); emit TokenRateUpdatesPaused(tokenRateData.tokenRate, tokenRateData.rateUpdatedL1Timestamp); emit RateUpdated(tokenRateData.tokenRate, tokenRateData.rateUpdatedL1Timestamp); } /// @notice Resume token rate updates applying provided token rate. /// @param tokenRate_ a new token rate that applies after resuming. /// @param rateUpdatedL1Timestamp_ L1 time when rate was updated on L1 side. function resumeTokenRateUpdates( uint256 tokenRate_, uint256 rateUpdatedL1Timestamp_ ) external onlyRole(RATE_UPDATE_ENABLER_ROLE) { if (!_isPaused()) { revert ErrorAlreadyResumed(); } if (tokenRate_ < MIN_SANE_TOKEN_RATE || tokenRate_ > MAX_SANE_TOKEN_RATE) { revert ErrorTokenRateIsOutOfSaneRange(tokenRate_); } if (rateUpdatedL1Timestamp_ > block.timestamp + MAX_ALLOWED_L2_TO_L1_CLOCK_LAG) { revert ErrorL1TimestampExceededMaxAllowedClockLag(rateUpdatedL1Timestamp_); } if (rateUpdatedL1Timestamp_ < _getLastTokenRate().rateUpdatedL1Timestamp) { revert ErrorL1TimestampOlderThanPrevious(rateUpdatedL1Timestamp_); } _addTokenRate(tokenRate_, rateUpdatedL1Timestamp_, block.timestamp); _setPause(false); emit TokenRateUpdatesResumed(tokenRate_, rateUpdatedL1Timestamp_); emit RateUpdated(tokenRate_, rateUpdatedL1Timestamp_); } /// @notice Shows that token rate updates are paused or not. function isTokenRateUpdatesPaused() external view returns (bool) { return _isPaused(); } /// @notice Returns token rate data by index. /// @param tokenRateIndex_ an index of token rate data. function getTokenRateByIndex(uint256 tokenRateIndex_) external view returns (TokenRateData memory) { return _getTokenRateByIndex(tokenRateIndex_); } /// @notice Returns token rates data length. function getTokenRatesLength() external view returns (uint256) { return _getStorageTokenRates().length; } /// @inheritdoc IChainlinkAggregatorInterface function latestRoundData() external view returns ( uint80 roundId_, int256 answer_, uint256 startedAt_, uint256 updatedAt_, uint80 answeredInRound_ ) { TokenRateData memory tokenRateData = _getLastTokenRate(); return ( uint80(tokenRateData.rateUpdatedL1Timestamp), int256(uint256(tokenRateData.tokenRate)), tokenRateData.rateUpdatedL1Timestamp, tokenRateData.rateReceivedL2Timestamp, uint80(tokenRateData.rateUpdatedL1Timestamp) ); } /// @inheritdoc IChainlinkAggregatorInterface function latestAnswer() external view returns (int256) { TokenRateData memory tokenRateData = _getLastTokenRate(); return int256(uint256(tokenRateData.tokenRate)); } /// @inheritdoc IChainlinkAggregatorInterface function decimals() external pure returns (uint8) { return DECIMALS; } /// @inheritdoc ITokenRateUpdatable function updateRate( uint256 tokenRate_, uint256 rateUpdatedL1Timestamp_ ) external onlyBridgeOrTokenRatePusher { if (_isPaused()) { emit TokenRateUpdateAttemptDuringPause(); return; } TokenRateData storage tokenRateData = _getLastTokenRate(); /// @dev checks if the clock lag (i.e, time difference) between L1 and L2 exceeds the configurable threshold if (rateUpdatedL1Timestamp_ > block.timestamp + MAX_ALLOWED_L2_TO_L1_CLOCK_LAG) { revert ErrorL1TimestampExceededAllowedClockLag(tokenRate_, rateUpdatedL1Timestamp_); } /// @dev Use only the most up-to-date token rate. Reverting should be avoided as it may occur occasionally. if (rateUpdatedL1Timestamp_ < tokenRateData.rateUpdatedL1Timestamp) { emit DormantTokenRateUpdateIgnored(rateUpdatedL1Timestamp_, tokenRateData.rateUpdatedL1Timestamp); return; } /// @dev Bump L2 receipt time, don't touch the rate othwerwise /// NB: Here we assume that the rate can only be changed together with the token rebase induced /// by the AccountingOracle report if (rateUpdatedL1Timestamp_ == tokenRateData.rateUpdatedL1Timestamp) { tokenRateData.rateReceivedL2Timestamp = uint64(block.timestamp); emit RateReceivedTimestampUpdated(block.timestamp); return; } /// @dev This condition was made under the assumption that the L1 timestamps can be manipulated. if (rateUpdatedL1Timestamp_ < tokenRateData.rateUpdatedL1Timestamp + MIN_TIME_BETWEEN_TOKEN_RATE_UPDATES) { emit UpdateRateIsTooOften(rateUpdatedL1Timestamp_, tokenRateData.rateUpdatedL1Timestamp); return; } /// @dev allow token rate to be within some configurable range that depens on time it wasn't updated. if (!_isTokenRateWithinAllowedRange( tokenRateData.tokenRate, tokenRate_, tokenRateData.rateUpdatedL1Timestamp, rateUpdatedL1Timestamp_) ) { revert ErrorTokenRateIsOutOfRange(tokenRate_, rateUpdatedL1Timestamp_); } /// @dev notify that there is a differnce L1 and L2 time. if (rateUpdatedL1Timestamp_ > block.timestamp) { emit TokenRateL1TimestampIsInFuture(tokenRate_, rateUpdatedL1Timestamp_); } _addTokenRate(tokenRate_, rateUpdatedL1Timestamp_, block.timestamp); emit RateUpdated(tokenRate_, rateUpdatedL1Timestamp_); } /// @notice Returns flag that shows that token rate can be considered outdated. function isLikelyOutdated() external view returns (bool) { return (block.timestamp > _getLastTokenRate().rateReceivedL2Timestamp + TOKEN_RATE_OUTDATED_DELAY) || _isPaused(); } /// @notice Allow tokenRate deviation from the previous value to be /// ±`MAX_ALLOWED_TOKEN_RATE_DEVIATION_PER_DAY` BP per day. function _isTokenRateWithinAllowedRange( uint256 currentTokenRate_, uint256 newTokenRate_, uint256 currentRateL1Timestamp_, uint256 newRateL1Timestamp_ ) internal view returns (bool) { uint256 allowedTokenRateDeviation = _allowedTokenRateDeviation(newRateL1Timestamp_, currentRateL1Timestamp_); return newTokenRate_ <= _maxTokenRateLimit(currentTokenRate_, allowedTokenRateDeviation) && newTokenRate_ >= _minTokenRateLimit(currentTokenRate_, allowedTokenRateDeviation); } /// @dev Returns the allowed token deviation depending on the number of days passed since the last update. function _allowedTokenRateDeviation( uint256 newRateL1Timestamp_, uint256 currentRateL1Timestamp_ ) internal view returns (uint256) { uint256 rateL1TimestampDiff = newRateL1Timestamp_ - currentRateL1Timestamp_; uint256 roundedUpNumberOfDays = (rateL1TimestampDiff + ONE_DAY_SECONDS - 1) / ONE_DAY_SECONDS; return roundedUpNumberOfDays * MAX_ALLOWED_TOKEN_RATE_DEVIATION_PER_DAY_BP; } /// @dev Returns the maximum allowable value for the token rate. function _maxTokenRateLimit( uint256 currentTokenRate, uint256 allowedTokenRateDeviation ) internal pure returns (uint256) { uint256 maxTokenRateLimit = currentTokenRate * (BASIS_POINT_SCALE + allowedTokenRateDeviation) / BASIS_POINT_SCALE; return Math.min(maxTokenRateLimit, MAX_SANE_TOKEN_RATE); } /// @dev Returns the minimum allowable value for the token rate. function _minTokenRateLimit( uint256 currentTokenRate, uint256 allowedTokenRateDeviation ) internal pure returns (uint256) { uint256 minTokenRateLimit = MIN_SANE_TOKEN_RATE; if (allowedTokenRateDeviation <= BASIS_POINT_SCALE) { minTokenRateLimit = (currentTokenRate * (BASIS_POINT_SCALE - allowedTokenRateDeviation) / BASIS_POINT_SCALE); } return Math.max(minTokenRateLimit, MIN_SANE_TOKEN_RATE); } function _isCallerBridgeOrMessengerWithTokenRatePusher(address caller_) internal view returns (bool) { if (caller_ == L2_ERC20_TOKEN_BRIDGE) { return true; } if (caller_ == address(MESSENGER) && MESSENGER.xDomainMessageSender() == L1_TOKEN_RATE_PUSHER) { return true; } return false; } function _addTokenRate( uint256 tokenRate_, uint256 rateUpdatedL1Timestamp_, uint256 rateReceivedL2Timestamp_ ) internal { _getStorageTokenRates().push(TokenRateData({ tokenRate: uint128(tokenRate_), rateUpdatedL1Timestamp: uint64(rateUpdatedL1Timestamp_), rateReceivedL2Timestamp: uint64(rateReceivedL2Timestamp_) })); } function _getLastTokenRate() internal view returns (TokenRateData storage) { return _getTokenRateByIndex(_getStorageTokenRates().length - 1); } function _getTokenRateByIndex(uint256 tokenRateIndex_) internal view returns (TokenRateData storage) { if (tokenRateIndex_ >= _getStorageTokenRates().length) { revert ErrorWrongTokenRateIndex(); } return _getStorageTokenRates()[tokenRateIndex_]; } function _getStorageTokenRates() internal pure returns (TokenRateData [] storage result) { bytes32 position = TOKEN_RATES_DATA_SLOT; assembly { result.slot := position } } /// @dev tokenRateIndex_ is limited by time in the past and the number of elements also has restrictions. /// Therefore, this loop can't consume a lot of gas. function _removeElementsAfterIndex(uint256 tokenRateIndex_) internal { uint256 tokenRatesLength = _getStorageTokenRates().length; if (tokenRateIndex_ >= tokenRatesLength) { return; } uint256 numberOfElementsToRemove = tokenRatesLength - tokenRateIndex_ - 1; for (uint256 i = 0; i < numberOfElementsToRemove; i++) { _getStorageTokenRates().pop(); } } function _setPause(bool pause) internal { PAUSE_TOKEN_RATE_UPDATES_SLOT.setStorageBool(pause); } function _isPaused() internal view returns (bool) { return PAUSE_TOKEN_RATE_UPDATES_SLOT.getStorageBool(); } modifier onlyBridgeOrTokenRatePusher() { if (!_isCallerBridgeOrMessengerWithTokenRatePusher(msg.sender)) { revert ErrorNotBridgeOrTokenRatePusher(); } _; } event RateUpdated(uint256 tokenRate_, uint256 indexed rateL1Timestamp_); event RateReceivedTimestampUpdated(uint256 indexed rateReceivedL2Timestamp); event DormantTokenRateUpdateIgnored(uint256 indexed newRateL1Timestamp_, uint256 indexed currentRateL1Timestamp_); event TokenRateL1TimestampIsInFuture(uint256 tokenRate_, uint256 indexed rateL1Timestamp_); event TokenRateUpdatesPaused(uint256 tokenRate_, uint256 indexed rateL1Timestamp_); event TokenRateUpdatesResumed(uint256 tokenRate_, uint256 indexed rateL1Timestamp_); event TokenRateUpdateAttemptDuringPause(); event UpdateRateIsTooOften(uint256 indexed newRateL1Timestamp_, uint256 indexed currentRateL1Timestamp_); error ErrorZeroAddressAdmin(); error ErrorWrongTokenRateIndex(); error ErrorTokenRateUpdateTooOld(); error ErrorAlreadyPaused(); error ErrorAlreadyResumed(); error ErrorZeroAddressL2ERC20TokenBridge(); error ErrorZeroAddressL1TokenRatePusher(); error ErrorNotBridgeOrTokenRatePusher(); error ErrorL1TimestampExceededAllowedClockLag(uint256 tokenRate_, uint256 rateL1Timestamp_); error ErrorTokenRateIsOutOfRange(uint256 tokenRate_, uint256 rateL1Timestamp_); error ErrorMaxTokenRateDeviationIsOutOfRange(); error ErrorTokenRateIsOutOfSaneRange(uint256 tokenRate_); error ErrorL1TimestampExceededMaxAllowedClockLag(uint256 rateL1Timestamp_); error ErrorL1TimestampOlderThanPrevious(uint256 rateL1Timestamp_); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../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: * * ``` * 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}: * * ``` * 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. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ 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 override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @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 override 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. */ function grantRole(bytes32 role, address account) public virtual override 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. */ function revokeRole(bytes32 role, address account) public virtual override 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 `account`. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @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 Grants `role` to `account`. * * Internal function without access restriction. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @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. * * _Available since v3.1._ */ 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, an admin role * bearer except when using {AccessControl-_setupRole}. */ 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 `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 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); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * 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[EIP 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a / b + (a % b == 0 ? 0 : 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; /// @dev A copy of UnstructuredStorage.sol library from Lido on Ethereum protocol. /// https://github.com/lidofinance/lido-dao/blob/master/contracts/0.8.9/lib/UnstructuredStorage.sol library UnstructuredStorage { function getStorageBool(bytes32 position) internal view returns (bool data) { assembly { data := sload(position) } } function getStorageUint256(bytes32 position) internal view returns (uint256 data) { assembly { data := sload(position) } } function setStorageBool(bytes32 position, bool data) internal { assembly { sstore(position, data) } } function setStorageUint256(bytes32 position, uint256 data) internal { assembly { sstore(position, data) } } }
// SPDX-FileCopyrightText: 2022 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; import {ICrossDomainMessenger} from "./interfaces/ICrossDomainMessenger.sol"; /// @dev Helper contract for contracts performing cross-domain communications contract CrossDomainEnabled { /// @notice Messenger contract used to send and receive messages from the other domain ICrossDomainMessenger public immutable MESSENGER; /// @param messenger_ Address of the CrossDomainMessenger on the current layer constructor(address messenger_) { if (messenger_ == address(0)) { revert ErrorZeroAddressMessenger(); } MESSENGER = ICrossDomainMessenger(messenger_); } /// @dev Sends a message to an account on another domain /// @param crossDomainTarget_ Intended recipient on the destination domain /// @param message_ Data to send to the target (usually calldata to a function with /// `onlyFromCrossDomainAccount()`) /// @param gasLimit_ gasLimit for the receipt of the message on the target domain. function sendCrossDomainMessage( address crossDomainTarget_, uint32 gasLimit_, bytes memory message_ ) internal { MESSENGER.sendMessage(crossDomainTarget_, message_, gasLimit_); } /// @dev Enforces that the modified function is only callable by a specific cross-domain account /// @param sourceDomainAccount_ The only account on the originating domain which is /// authenticated to call this function modifier onlyFromCrossDomainAccount(address sourceDomainAccount_) { if (msg.sender != address(MESSENGER)) { revert ErrorUnauthorizedMessenger(); } if (MESSENGER.xDomainMessageSender() != sourceDomainAccount_) { revert ErrorWrongCrossDomainSender(); } _; } error ErrorZeroAddressMessenger(); error ErrorUnauthorizedMessenger(); error ErrorWrongCrossDomainSender(); }
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; /// @author kovalgek /// @notice A subset of chainlink data feed interface for token rate oracle. interface IChainlinkAggregatorInterface { /// @notice get the latest token rate data. /// @return roundId_ is a unique id for each answer. The value is based on timestamp. /// @return answer_ is wstETH/stETH token rate. It is a chainlink convention to return int256. /// @return startedAt_ is time when rate was pushed on L1 side. /// @return updatedAt_ is the same as startedAt_. /// @return answeredInRound_ is the same as roundId_. function latestRoundData() external view returns ( uint80 roundId_, int256 answer_, uint256 startedAt_, uint256 updatedAt_, uint80 answeredInRound_ ); /// @notice get the lastest token rate. /// @return wstETH/stETH token rate. It is a chainlink convention to return int256. function latestAnswer() external view returns (int256); /// @notice represents the number of decimals the oracle responses represent. /// @return decimals of the oracle response. function decimals() external view returns (uint8); }
// SPDX-FileCopyrightText: 2022 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; interface ICrossDomainMessenger { function xDomainMessageSender() external view returns (address); /// Sends a cross domain message to the target messenger. /// @param _target Target contract address. /// @param _message Message to send to the target. /// @param _gasLimit Gas limit for the provided message. function sendMessage( address _target, bytes calldata _message, uint32 _gasLimit ) external; }
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; /// @author kovalgek /// @notice An interface for updating token rate of token rate oracle. interface ITokenRateUpdatable { /// @notice Updates token rate. /// @param tokenRate_ wstETH/stETH token rate. /// @param rateUpdatedL1Timestamp_ L1 time when rate was updated on L1 side. function updateRate(uint256 tokenRate_, uint256 rateUpdatedL1Timestamp_) external; }
// SPDX-FileCopyrightText: 2022 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; import {UnstructuredStorage} from "../lib/UnstructuredStorage.sol"; /// @dev A copy of Versioned.sol contract from Lido on Ethereum protocol /// https://github.com/lidofinance/lido-dao/blob/master/contracts/0.8.9/utils/Versioned.sol contract Versioned { using UnstructuredStorage for bytes32; event ContractVersionSet(uint256 version); error NonZeroContractVersionOnInit(); error InvalidContractVersionIncrement(); error UnexpectedContractVersion(uint256 expected, uint256 received); /// @dev Storage slot: uint256 version /// Version of the initialized contract storage. /// The version stored in CONTRACT_VERSION_POSITION equals to: /// - 0 right after the deployment, before an initializer is invoked (and only at that moment); /// - N after calling initialize(), where N is the initially deployed contract version; /// - N after upgrading contract by calling finalizeUpgrade_vN(). bytes32 internal constant CONTRACT_VERSION_POSITION = keccak256("lido.Versioned.contractVersion"); uint256 internal constant PETRIFIED_VERSION_MARK = type(uint256).max; constructor() { // lock version in the implementation's storage to prevent initialization CONTRACT_VERSION_POSITION.setStorageUint256(PETRIFIED_VERSION_MARK); } /// @notice Returns the current contract version. function getContractVersion() public view returns (uint256) { return CONTRACT_VERSION_POSITION.getStorageUint256(); } function _checkContractVersion(uint256 version) internal view { uint256 expectedVersion = getContractVersion(); if (version != expectedVersion) { revert UnexpectedContractVersion(expectedVersion, version); } } /// @dev Sets the contract version to N. Should be called from the initialize() function. function _initializeContractVersionTo(uint256 version) internal { if (getContractVersion() != 0) revert NonZeroContractVersionOnInit(); _setContractVersion(version); } /// @dev Updates the contract version. Should be called from a finalizeUpgrade_vN() function. function _updateContractVersion(uint256 newVersion) internal { if (newVersion != getContractVersion() + 1) revert InvalidContractVersionIncrement(); _setContractVersion(newVersion); } function _setContractVersion(uint256 version) private { CONTRACT_VERSION_POSITION.setStorageUint256(version); emit ContractVersionSet(version); } }
{ "optimizer": { "enabled": true, "runs": 100000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"messenger_","type":"address"},{"internalType":"address","name":"l2ERC20TokenBridge_","type":"address"},{"internalType":"address","name":"l1TokenRatePusher_","type":"address"},{"internalType":"uint256","name":"tokenRateOutdatedDelay_","type":"uint256"},{"internalType":"uint256","name":"maxAllowedL2ToL1ClockLag_","type":"uint256"},{"internalType":"uint256","name":"maxAllowedTokenRateDeviationPerDayBp_","type":"uint256"},{"internalType":"uint256","name":"oldestRateAllowedInPauseTimeSpan_","type":"uint256"},{"internalType":"uint256","name":"minTimeBetweenTokenRateUpdates_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ErrorAlreadyPaused","type":"error"},{"inputs":[],"name":"ErrorAlreadyResumed","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"internalType":"uint256","name":"rateL1Timestamp_","type":"uint256"}],"name":"ErrorL1TimestampExceededAllowedClockLag","type":"error"},{"inputs":[{"internalType":"uint256","name":"rateL1Timestamp_","type":"uint256"}],"name":"ErrorL1TimestampExceededMaxAllowedClockLag","type":"error"},{"inputs":[{"internalType":"uint256","name":"rateL1Timestamp_","type":"uint256"}],"name":"ErrorL1TimestampOlderThanPrevious","type":"error"},{"inputs":[],"name":"ErrorMaxTokenRateDeviationIsOutOfRange","type":"error"},{"inputs":[],"name":"ErrorNotBridgeOrTokenRatePusher","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"internalType":"uint256","name":"rateL1Timestamp_","type":"uint256"}],"name":"ErrorTokenRateIsOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenRate_","type":"uint256"}],"name":"ErrorTokenRateIsOutOfSaneRange","type":"error"},{"inputs":[],"name":"ErrorTokenRateUpdateTooOld","type":"error"},{"inputs":[],"name":"ErrorUnauthorizedMessenger","type":"error"},{"inputs":[],"name":"ErrorWrongCrossDomainSender","type":"error"},{"inputs":[],"name":"ErrorWrongTokenRateIndex","type":"error"},{"inputs":[],"name":"ErrorZeroAddressAdmin","type":"error"},{"inputs":[],"name":"ErrorZeroAddressL1TokenRatePusher","type":"error"},{"inputs":[],"name":"ErrorZeroAddressL2ERC20TokenBridge","type":"error"},{"inputs":[],"name":"ErrorZeroAddressMessenger","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"newRateL1Timestamp_","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currentRateL1Timestamp_","type":"uint256"}],"name":"DormantTokenRateUpdateIgnored","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rateReceivedL2Timestamp","type":"uint256"}],"name":"RateReceivedTimestampUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"rateL1Timestamp_","type":"uint256"}],"name":"RateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"rateL1Timestamp_","type":"uint256"}],"name":"TokenRateL1TimestampIsInFuture","type":"event"},{"anonymous":false,"inputs":[],"name":"TokenRateUpdateAttemptDuringPause","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"rateL1Timestamp_","type":"uint256"}],"name":"TokenRateUpdatesPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"rateL1Timestamp_","type":"uint256"}],"name":"TokenRateUpdatesResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"newRateL1Timestamp_","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currentRateL1Timestamp_","type":"uint256"}],"name":"UpdateRateIsTooOften","type":"event"},{"inputs":[],"name":"DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L1_TOKEN_RATE_PUSHER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L2_ERC20_TOKEN_BRIDGE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ALLOWED_L2_TO_L1_CLOCK_LAG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ALLOWED_TOKEN_RATE_DEVIATION_PER_DAY_BP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SANE_TOKEN_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MESSENGER","outputs":[{"internalType":"contract ICrossDomainMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_SANE_TOKEN_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_TIME_BETWEEN_TOKEN_RATE_UPDATES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OLDEST_RATE_ALLOWED_IN_PAUSE_TIME_SPAN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATE_UPDATE_DISABLER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATE_UPDATE_ENABLER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_RATE_OUTDATED_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenRateIndex_","type":"uint256"}],"name":"getTokenRateByIndex","outputs":[{"components":[{"internalType":"uint128","name":"tokenRate","type":"uint128"},{"internalType":"uint64","name":"rateUpdatedL1Timestamp","type":"uint64"},{"internalType":"uint64","name":"rateReceivedL2Timestamp","type":"uint64"}],"internalType":"struct TokenRateOracle.TokenRateData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenRatesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin_","type":"address"},{"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"internalType":"uint256","name":"rateUpdatedL1Timestamp_","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isLikelyOutdated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTokenRateUpdatesPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestAnswer","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId_","type":"uint80"},{"internalType":"int256","name":"answer_","type":"int256"},{"internalType":"uint256","name":"startedAt_","type":"uint256"},{"internalType":"uint256","name":"updatedAt_","type":"uint256"},{"internalType":"uint80","name":"answeredInRound_","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenRateIndex_","type":"uint256"}],"name":"pauseTokenRateUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"internalType":"uint256","name":"rateUpdatedL1Timestamp_","type":"uint256"}],"name":"resumeTokenRateUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenRate_","type":"uint256"},{"internalType":"uint256","name":"rateUpdatedL1Timestamp_","type":"uint256"}],"name":"updateRate","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101806040523480156200001257600080fd5b506040516200291b3803806200291b833981016040819052620000359162000178565b876001600160a01b0381166200005e57604051635d4339db60e01b815260040160405180910390fd5b6001600160a01b0316608052620000a47f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a660001962000157602090811b6200163c17901c565b6001600160a01b038716620000cc5760405163bac34ad960e01b815260040160405180910390fd5b6001600160a01b038616620000f4576040516311d4a29b60e01b815260040160405180910390fd5b82158062000103575061271083115b1562000122576040516318adb27160e01b815260040160405180910390fd5b6001600160a01b0396871660a0529490951660c05260e0929092526101005261012052610140919091526101605250620001f3565b9055565b80516001600160a01b03811681146200017357600080fd5b919050565b600080600080600080600080610100898b0312156200019657600080fd5b620001a1896200015b565b9750620001b160208a016200015b565b9650620001c160408a016200015b565b9550606089015194506080890151935060a0890151925060c0890151915060e089015190509295985092959890939650565b60805160a05160c05160e05161010051610120516101405161016051612675620002a66000396000818161051a0152610d1c01526000818161022201526111570152600081816104f30152611d240152600081816105410152818161077401528181610b92015261135501526000818161040501526109e801526000818161057b01526119350152600081816104c40152611883015260008181610478015281816118df015261196c01526126756000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c80637a1ac61e1161010f578063a14a3a24116100a2578063ccac043411610071578063ccac04341461053c578063d547741f14610563578063fbe939a014610576578063feaf968c1461059d57600080fd5b8063a14a3a24146104bf578063a217fddf146104e6578063bc180be8146104ee578063bfd290a41461051557600080fd5b8063882bd77d116100de578063882bd77d146104005780638aa104351461042757806391d148541461042f578063927ede2d1461047357600080fd5b80637a1ac61e1461036557806380416b88146103785780638076f9e8146103d1578063842170f7146103f857600080fd5b80632fd39d64116101875780634aab251a116101565780634aab251a1461031b57806350d25bcd146103425780635dd6b3701461034a578063673489b11461035257600080fd5b80632fd39d64146102e6578063313ce567146102ee57806336568abe146102f5578063405abb411461030857600080fd5b806316cd0362116101c357806316cd036214610281578063248a9ca3146102965780632e0f2625146102b95780632f2ff15d146102d357600080fd5b806301ffc9a7146101f55780630d42a7d61461021d5780630e43df141461025257806311b5811214610279575b600080fd5b6102086102033660046120d8565b6105dc565b60405190151581526020015b60405180910390f35b6102447f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610214565b6102447f1e8b59162351029dd98a93e3f40b9a963abf5ee753e69105079697f8cb505af381565b610244610675565b61029461028f36600461211a565b61068f565b005b6102446102a436600461213c565b60009081526020819052604090206001015490565b6102c1601b81565b60405160ff9091168152602001610214565b6102946102e1366004612177565b6109ba565b6102086109e4565b601b6102c1565b610294610303366004612177565b610a55565b61029461031636600461211a565b610b08565b6102447f5a883d2caeb13c05f1649a05c9c61c1deb622a06bff8d94d071d35c5ad8c2c9481565b610244610fac565b61024461102b565b61029461036036600461213c565b611037565b6102946103733660046121a7565b611286565b61038b61038636600461213c565b6114c0565b6040805182516fffffffffffffffffffffffffffffffff16815260208084015167ffffffffffffffff908116918301919091529282015190921690820152606001610214565b7fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d2654610244565b610208611553565b6102447f000000000000000000000000000000000000000000000000000000000000000081565b61024461155d565b61020861043d366004612177565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b61049a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b61049a7f000000000000000000000000000000000000000000000000000000000000000081565b610244600081565b6102447f000000000000000000000000000000000000000000000000000000000000000081565b6102447f000000000000000000000000000000000000000000000000000000000000000081565b6102447f000000000000000000000000000000000000000000000000000000000000000081565b610294610571366004612177565b611587565b61049a7f000000000000000000000000000000000000000000000000000000000000000081565b6105a56115ac565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a001610214565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061066f57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6106816002601b61220b565b61068c90600a61234e565b81565b7f5a883d2caeb13c05f1649a05c9c61c1deb622a06bff8d94d071d35c5ad8c2c946106b981611640565b6106c161164d565b6106f7576040517ffef4699300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107036002601b61220b565b61070e90600a61234e565b8310806107305750610722601b600261235d565b61072d90600a61234e565b83115b1561076f576040517fd86902a5000000000000000000000000000000000000000000000000000000008152600481018490526024015b60405180910390fd5b6107997f000000000000000000000000000000000000000000000000000000000000000042612382565b8211156107d5576040517f106c81b100000000000000000000000000000000000000000000000000000000815260048101839052602401610766565b6107dd611677565b54700100000000000000000000000000000000900467ffffffffffffffff16821015610838576040517f8716566200000000000000000000000000000000000000000000000000000000815260048101839052602401610766565b6109378383427fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26604080516060810182526fffffffffffffffffffffffffffffffff958616815267ffffffffffffffff9485166020808301918252948616928201928352835460018101855560009485529490932090519301805492519151851678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff92909516700100000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931693909516929092171716179055565b61094160006116af565b817f74c329375918146936c6defccdbabd509023d6839ce07218ed589158568eb4de8460405161097391815260200190565b60405180910390a2817fb38780ddde1f073d91c150de2696f3f7085883648ba21cc5ef01029cb21d1916846040516109ad91815260200190565b60405180910390a2505050565b6000828152602081905260409020600101546109d581611640565b6109df83836116d8565b505050565b60007f0000000000000000000000000000000000000000000000000000000000000000610a0f611677565b54610a4091907801000000000000000000000000000000000000000000000000900467ffffffffffffffff16612382565b421180610a505750610a5061164d565b905090565b73ffffffffffffffffffffffffffffffffffffffff81163314610afa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610766565b610b0482826117c8565b5050565b610b113361187f565b610b47576040517fa97b330100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b4f61164d565b15610b81576040517fb2060185a4d2afae65ae653883a35989c4a457d46be023d7ca17f5f09b124fd990600090a15050565b6000610b8b611677565b9050610bb77f000000000000000000000000000000000000000000000000000000000000000042612382565b821115610bfa576040517fd73b40ae0000000000000000000000000000000000000000000000000000000081526004810184905260248101839052604401610766565b8054700100000000000000000000000000000000900467ffffffffffffffff16821015610c7357805460405170010000000000000000000000000000000090910467ffffffffffffffff169083907ffaa0ce015a4ea00d0246bd2e8280972df2297522b812fcb5b47eae66ff19537a90600090a3505050565b8054700100000000000000000000000000000000900467ffffffffffffffff16821415610d1457805467ffffffffffffffff4290811678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911782556040517f2a546807251eae099f8c990bb960ef40de2d3fbc5b51dde7a04b1837f40d3a2890600090a2505050565b8054610d5f907f000000000000000000000000000000000000000000000000000000000000000090700100000000000000000000000000000000900467ffffffffffffffff16612382565b821015610db857805460405170010000000000000000000000000000000090910467ffffffffffffffff169083907f6efe9409e7f5944320a82e8b08ac78c38cb7c2ba9aa20885be2768c542017df190600090a3505050565b8054610df8906fffffffffffffffffffffffffffffffff8116908590700100000000000000000000000000000000900467ffffffffffffffff1685611a26565b610e38576040517f6403c1c70000000000000000000000000000000000000000000000000000000081526004810184905260248101839052604401610766565b42821115610e7b57817f6aca59d565c890fc85031b9461c3abc72c6d82e696ca27dc6906ab5bfaf477c584604051610e7291815260200190565b60405180910390a25b610f7a8383427fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26604080516060810182526fffffffffffffffffffffffffffffffff958616815267ffffffffffffffff9485166020808301918252948616928201928352835460018101855560009485529490932090519301805492519151851678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff92909516700100000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931693909516929092171716179055565b817fb38780ddde1f073d91c150de2696f3f7085883648ba21cc5ef01029cb21d1916846040516109ad91815260200190565b600080610fb7611677565b6040805160608101825291546fffffffffffffffffffffffffffffffff811680845267ffffffffffffffff7001000000000000000000000000000000008304811660208601527801000000000000000000000000000000000000000000000000909204909116929091019190915292915050565b610681601b600261235d565b7f1e8b59162351029dd98a93e3f40b9a963abf5ee753e69105079697f8cb505af361106181611640565b61106961164d565b156110a0576040517f73e939ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006110ab83611a61565b6040805160608101825291546fffffffffffffffffffffffffffffffff8116835267ffffffffffffffff700100000000000000000000000000000000820481166020850152780100000000000000000000000000000000000000000000000090910416908201529050600161113d7fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d2690565b54611148919061239a565b831415801561118d575061117c7f00000000000000000000000000000000000000000000000000000000000000004261239a565b816040015167ffffffffffffffff16105b156111c4576040517fa070ddee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111cd83611b00565b6111d760016116af565b60208082015182516040516fffffffffffffffffffffffffffffffff909116815267ffffffffffffffff909116917f8c09dc8e7131bdaafd6dfac4a3c44132e89051217c79a65c72829b5172e9e9a6910160405180910390a260208082015182516040516fffffffffffffffffffffffffffffffff909116815267ffffffffffffffff909116917fb38780ddde1f073d91c150de2696f3f7085883648ba21cc5ef01029cb21d191691016109ad565b6112906001611bd0565b73ffffffffffffffffffffffffffffffffffffffff83166112dd576040517fc6ab211700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112e96002601b61220b565b6112f490600a61234e565b8210806113165750611308601b600261235d565b61131390600a61234e565b82115b15611350576040517fd86902a500000000000000000000000000000000000000000000000000000000815260048101839052602401610766565b61137a7f000000000000000000000000000000000000000000000000000000000000000042612382565b8111156113b6576040517f106c81b100000000000000000000000000000000000000000000000000000000815260048101829052602401610766565b6113c16000846116d8565b6109df8282427fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26604080516060810182526fffffffffffffffffffffffffffffffff958616815267ffffffffffffffff9485166020808301918252948616928201928352835460018101855560009485529490932090519301805492519151851678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff92909516700100000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931693909516929092171716179055565b60408051606081018252600080825260208201819052918101919091526114e682611a61565b6040805160608101825291546fffffffffffffffffffffffffffffffff8116835267ffffffffffffffff7001000000000000000000000000000000008204811660208501527801000000000000000000000000000000000000000000000000909104169082015292915050565b6000610a5061164d565b6000610a507f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a65490565b6000828152602081905260409020600101546115a281611640565b6109df83836117c8565b6000806000806000806115bd611677565b6040805160608101825291546fffffffffffffffffffffffffffffffff811680845267ffffffffffffffff70010000000000000000000000000000000083048116602086018190527801000000000000000000000000000000000000000000000000909304169390920183905298909750889650909450859350915050565b9055565b61164a8133611c18565b50565b6000610a507f0133fe49a9684f44ae5928d6aef02b435a3b70175343dba35a4548c3da48ac565490565b6000610a5060017fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26546116aa919061239a565b611a61565b61164a7f0133fe49a9684f44ae5928d6aef02b435a3b70175343dba35a4548c3da48ac56829055565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610b045760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561176a3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610b045760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156118dd57506001919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16148015611a1157507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f991906123b1565b73ffffffffffffffffffffffffffffffffffffffff16145b15611a1e57506001919050565b506000919050565b600080611a338385611ce8565b9050611a3f8682611d52565b8511158015611a575750611a538682611da0565b8510155b9695505050505050565b60007fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26548210611abd576040517f7e936eca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d268281548110611aef57611aef6123ce565b906000526020600020019050919050565b7fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d2654808210611b2d575050565b60006001611b3b848461239a565b611b45919061239a565b905060005b81811015611bca577fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26805480611b8257611b826123fd565b60008281526020812082017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081019190915501905580611bc28161242c565b915050611b4a565b50505050565b611bd861155d565b15611c0f576040517f61394a8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61164a81611e09565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610b0457611c6e8173ffffffffffffffffffffffffffffffffffffffff166014611e68565b611c79836020611e68565b604051602001611c8a929190612491565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261076691600401612512565b600080611cf5838561239a565b90506000620151806001611d098285612382565b611d13919061239a565b611d1d9190612563565b9050611d497f00000000000000000000000000000000000000000000000000000000000000008261259e565b95945050505050565b600080612710611d628482612382565b611d6c908661259e565b611d769190612563565b9050611d9881611d88601b600261235d565b611d9390600a61234e565b6120b2565b949350505050565b600080611daf6002601b61220b565b611dba90600a61234e565b90506127108311611de957612710611dd2848261239a565b611ddc908661259e565b611de69190612563565b90505b611d9881611df96002601b61220b565b611e0490600a61234e565b6120c8565b611e327f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6829055565b6040518181527ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9060200160405180910390a150565b60606000611e7783600261259e565b611e82906002612382565b67ffffffffffffffff811115611e9a57611e9a6125db565b6040519080825280601f01601f191660200182016040528015611ec4576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611efb57611efb6123ce565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611f5e57611f5e6123ce565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000611f9a84600261259e565b611fa5906001612382565b90505b6001811115612042577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611fe657611fe66123ce565b1a60f81b828281518110611ffc57611ffc6123ce565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361203b8161260a565b9050611fa8565b5083156120ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610766565b9392505050565b60008183106120c157816120ab565b5090919050565b6000818310156120c157816120ab565b6000602082840312156120ea57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146120ab57600080fd5b6000806040838503121561212d57600080fd5b50508035926020909101359150565b60006020828403121561214e57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461164a57600080fd5b6000806040838503121561218a57600080fd5b82359150602083013561219c81612155565b809150509250929050565b6000806000606084860312156121bc57600080fd5b83356121c781612155565b95602085013595506040909401359392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600060ff821660ff841680821015612225576122256121dc565b90039392505050565b600181815b8085111561228757817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561226d5761226d6121dc565b8085161561227a57918102915b93841c9390800290612233565b509250929050565b60008261229e5750600161066f565b816122ab5750600061066f565b81600181146122c157600281146122cb576122e7565b600191505061066f565b60ff8411156122dc576122dc6121dc565b50506001821b61066f565b5060208310610133831016604e8410600b841016171561230a575081810a61066f565b612314838361222e565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612346576123466121dc565b029392505050565b60006120ab60ff84168361228f565b600060ff821660ff84168060ff0382111561237a5761237a6121dc565b019392505050565b60008219821115612395576123956121dc565b500190565b6000828210156123ac576123ac6121dc565b500390565b6000602082840312156123c357600080fd5b81516120ab81612155565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561245e5761245e6121dc565b5060010190565b60005b83811015612480578181015183820152602001612468565b83811115611bca5750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516124c9816017850160208801612465565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612506816028840160208801612465565b01602801949350505050565b6020815260008251806020840152612531816040850160208701612465565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600082612599577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156125d6576125d66121dc565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600081612619576126196121dc565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220092491d5189b5cf74f329d7721dddff9623a0541f01b93d31ef18e0d6d627bf464736f6c634300080a003300000000000000000000000042000000000000000000000000000000000000070000000000000000000000001a513e9b6434a12c7bb5b9af3b21963308dee3720000000000000000000000003f9600439ad97fc6f55c2ac7c118f8fd0595eb740000000000000000000000000000000000000000000000000000000000016da0000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000e10
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101f05760003560e01c80637a1ac61e1161010f578063a14a3a24116100a2578063ccac043411610071578063ccac04341461053c578063d547741f14610563578063fbe939a014610576578063feaf968c1461059d57600080fd5b8063a14a3a24146104bf578063a217fddf146104e6578063bc180be8146104ee578063bfd290a41461051557600080fd5b8063882bd77d116100de578063882bd77d146104005780638aa104351461042757806391d148541461042f578063927ede2d1461047357600080fd5b80637a1ac61e1461036557806380416b88146103785780638076f9e8146103d1578063842170f7146103f857600080fd5b80632fd39d64116101875780634aab251a116101565780634aab251a1461031b57806350d25bcd146103425780635dd6b3701461034a578063673489b11461035257600080fd5b80632fd39d64146102e6578063313ce567146102ee57806336568abe146102f5578063405abb411461030857600080fd5b806316cd0362116101c357806316cd036214610281578063248a9ca3146102965780632e0f2625146102b95780632f2ff15d146102d357600080fd5b806301ffc9a7146101f55780630d42a7d61461021d5780630e43df141461025257806311b5811214610279575b600080fd5b6102086102033660046120d8565b6105dc565b60405190151581526020015b60405180910390f35b6102447f000000000000000000000000000000000000000000000000000000000001518081565b604051908152602001610214565b6102447f1e8b59162351029dd98a93e3f40b9a963abf5ee753e69105079697f8cb505af381565b610244610675565b61029461028f36600461211a565b61068f565b005b6102446102a436600461213c565b60009081526020819052604090206001015490565b6102c1601b81565b60405160ff9091168152602001610214565b6102946102e1366004612177565b6109ba565b6102086109e4565b601b6102c1565b610294610303366004612177565b610a55565b61029461031636600461211a565b610b08565b6102447f5a883d2caeb13c05f1649a05c9c61c1deb622a06bff8d94d071d35c5ad8c2c9481565b610244610fac565b61024461102b565b61029461036036600461213c565b611037565b6102946103733660046121a7565b611286565b61038b61038636600461213c565b6114c0565b6040805182516fffffffffffffffffffffffffffffffff16815260208084015167ffffffffffffffff908116918301919091529282015190921690820152606001610214565b7fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d2654610244565b610208611553565b6102447f0000000000000000000000000000000000000000000000000000000000016da081565b61024461155d565b61020861043d366004612177565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b61049a7f000000000000000000000000420000000000000000000000000000000000000781565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b61049a7f0000000000000000000000001a513e9b6434a12c7bb5b9af3b21963308dee37281565b610244600081565b6102447f00000000000000000000000000000000000000000000000000000000000001f481565b6102447f0000000000000000000000000000000000000000000000000000000000000e1081565b6102447f000000000000000000000000000000000000000000000000000000000001518081565b610294610571366004612177565b611587565b61049a7f0000000000000000000000003f9600439ad97fc6f55c2ac7c118f8fd0595eb7481565b6105a56115ac565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a001610214565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061066f57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6106816002601b61220b565b61068c90600a61234e565b81565b7f5a883d2caeb13c05f1649a05c9c61c1deb622a06bff8d94d071d35c5ad8c2c946106b981611640565b6106c161164d565b6106f7576040517ffef4699300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107036002601b61220b565b61070e90600a61234e565b8310806107305750610722601b600261235d565b61072d90600a61234e565b83115b1561076f576040517fd86902a5000000000000000000000000000000000000000000000000000000008152600481018490526024015b60405180910390fd5b6107997f000000000000000000000000000000000000000000000000000000000001518042612382565b8211156107d5576040517f106c81b100000000000000000000000000000000000000000000000000000000815260048101839052602401610766565b6107dd611677565b54700100000000000000000000000000000000900467ffffffffffffffff16821015610838576040517f8716566200000000000000000000000000000000000000000000000000000000815260048101839052602401610766565b6109378383427fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26604080516060810182526fffffffffffffffffffffffffffffffff958616815267ffffffffffffffff9485166020808301918252948616928201928352835460018101855560009485529490932090519301805492519151851678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff92909516700100000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931693909516929092171716179055565b61094160006116af565b817f74c329375918146936c6defccdbabd509023d6839ce07218ed589158568eb4de8460405161097391815260200190565b60405180910390a2817fb38780ddde1f073d91c150de2696f3f7085883648ba21cc5ef01029cb21d1916846040516109ad91815260200190565b60405180910390a2505050565b6000828152602081905260409020600101546109d581611640565b6109df83836116d8565b505050565b60007f0000000000000000000000000000000000000000000000000000000000016da0610a0f611677565b54610a4091907801000000000000000000000000000000000000000000000000900467ffffffffffffffff16612382565b421180610a505750610a5061164d565b905090565b73ffffffffffffffffffffffffffffffffffffffff81163314610afa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610766565b610b0482826117c8565b5050565b610b113361187f565b610b47576040517fa97b330100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b4f61164d565b15610b81576040517fb2060185a4d2afae65ae653883a35989c4a457d46be023d7ca17f5f09b124fd990600090a15050565b6000610b8b611677565b9050610bb77f000000000000000000000000000000000000000000000000000000000001518042612382565b821115610bfa576040517fd73b40ae0000000000000000000000000000000000000000000000000000000081526004810184905260248101839052604401610766565b8054700100000000000000000000000000000000900467ffffffffffffffff16821015610c7357805460405170010000000000000000000000000000000090910467ffffffffffffffff169083907ffaa0ce015a4ea00d0246bd2e8280972df2297522b812fcb5b47eae66ff19537a90600090a3505050565b8054700100000000000000000000000000000000900467ffffffffffffffff16821415610d1457805467ffffffffffffffff4290811678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911782556040517f2a546807251eae099f8c990bb960ef40de2d3fbc5b51dde7a04b1837f40d3a2890600090a2505050565b8054610d5f907f0000000000000000000000000000000000000000000000000000000000000e1090700100000000000000000000000000000000900467ffffffffffffffff16612382565b821015610db857805460405170010000000000000000000000000000000090910467ffffffffffffffff169083907f6efe9409e7f5944320a82e8b08ac78c38cb7c2ba9aa20885be2768c542017df190600090a3505050565b8054610df8906fffffffffffffffffffffffffffffffff8116908590700100000000000000000000000000000000900467ffffffffffffffff1685611a26565b610e38576040517f6403c1c70000000000000000000000000000000000000000000000000000000081526004810184905260248101839052604401610766565b42821115610e7b57817f6aca59d565c890fc85031b9461c3abc72c6d82e696ca27dc6906ab5bfaf477c584604051610e7291815260200190565b60405180910390a25b610f7a8383427fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26604080516060810182526fffffffffffffffffffffffffffffffff958616815267ffffffffffffffff9485166020808301918252948616928201928352835460018101855560009485529490932090519301805492519151851678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff92909516700100000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931693909516929092171716179055565b817fb38780ddde1f073d91c150de2696f3f7085883648ba21cc5ef01029cb21d1916846040516109ad91815260200190565b600080610fb7611677565b6040805160608101825291546fffffffffffffffffffffffffffffffff811680845267ffffffffffffffff7001000000000000000000000000000000008304811660208601527801000000000000000000000000000000000000000000000000909204909116929091019190915292915050565b610681601b600261235d565b7f1e8b59162351029dd98a93e3f40b9a963abf5ee753e69105079697f8cb505af361106181611640565b61106961164d565b156110a0576040517f73e939ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006110ab83611a61565b6040805160608101825291546fffffffffffffffffffffffffffffffff8116835267ffffffffffffffff700100000000000000000000000000000000820481166020850152780100000000000000000000000000000000000000000000000090910416908201529050600161113d7fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d2690565b54611148919061239a565b831415801561118d575061117c7f00000000000000000000000000000000000000000000000000000000000151804261239a565b816040015167ffffffffffffffff16105b156111c4576040517fa070ddee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111cd83611b00565b6111d760016116af565b60208082015182516040516fffffffffffffffffffffffffffffffff909116815267ffffffffffffffff909116917f8c09dc8e7131bdaafd6dfac4a3c44132e89051217c79a65c72829b5172e9e9a6910160405180910390a260208082015182516040516fffffffffffffffffffffffffffffffff909116815267ffffffffffffffff909116917fb38780ddde1f073d91c150de2696f3f7085883648ba21cc5ef01029cb21d191691016109ad565b6112906001611bd0565b73ffffffffffffffffffffffffffffffffffffffff83166112dd576040517fc6ab211700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112e96002601b61220b565b6112f490600a61234e565b8210806113165750611308601b600261235d565b61131390600a61234e565b82115b15611350576040517fd86902a500000000000000000000000000000000000000000000000000000000815260048101839052602401610766565b61137a7f000000000000000000000000000000000000000000000000000000000001518042612382565b8111156113b6576040517f106c81b100000000000000000000000000000000000000000000000000000000815260048101829052602401610766565b6113c16000846116d8565b6109df8282427fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26604080516060810182526fffffffffffffffffffffffffffffffff958616815267ffffffffffffffff9485166020808301918252948616928201928352835460018101855560009485529490932090519301805492519151851678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff92909516700100000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931693909516929092171716179055565b60408051606081018252600080825260208201819052918101919091526114e682611a61565b6040805160608101825291546fffffffffffffffffffffffffffffffff8116835267ffffffffffffffff7001000000000000000000000000000000008204811660208501527801000000000000000000000000000000000000000000000000909104169082015292915050565b6000610a5061164d565b6000610a507f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a65490565b6000828152602081905260409020600101546115a281611640565b6109df83836117c8565b6000806000806000806115bd611677565b6040805160608101825291546fffffffffffffffffffffffffffffffff811680845267ffffffffffffffff70010000000000000000000000000000000083048116602086018190527801000000000000000000000000000000000000000000000000909304169390920183905298909750889650909450859350915050565b9055565b61164a8133611c18565b50565b6000610a507f0133fe49a9684f44ae5928d6aef02b435a3b70175343dba35a4548c3da48ac565490565b6000610a5060017fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26546116aa919061239a565b611a61565b61164a7f0133fe49a9684f44ae5928d6aef02b435a3b70175343dba35a4548c3da48ac56829055565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610b045760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561176a3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610b045760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60007f0000000000000000000000001a513e9b6434a12c7bb5b9af3b21963308dee37273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156118dd57506001919050565b7f000000000000000000000000420000000000000000000000000000000000000773ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16148015611a1157507f0000000000000000000000003f9600439ad97fc6f55c2ac7c118f8fd0595eb7473ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000420000000000000000000000000000000000000773ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f991906123b1565b73ffffffffffffffffffffffffffffffffffffffff16145b15611a1e57506001919050565b506000919050565b600080611a338385611ce8565b9050611a3f8682611d52565b8511158015611a575750611a538682611da0565b8510155b9695505050505050565b60007fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26548210611abd576040517f7e936eca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d268281548110611aef57611aef6123ce565b906000526020600020019050919050565b7fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d2654808210611b2d575050565b60006001611b3b848461239a565b611b45919061239a565b905060005b81811015611bca577fbe5dcc93fa7a9bf03faca37ef40993af4ba6b2eb195bd06f5a670ee5f2970d26805480611b8257611b826123fd565b60008281526020812082017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081019190915501905580611bc28161242c565b915050611b4a565b50505050565b611bd861155d565b15611c0f576040517f61394a8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61164a81611e09565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610b0457611c6e8173ffffffffffffffffffffffffffffffffffffffff166014611e68565b611c79836020611e68565b604051602001611c8a929190612491565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261076691600401612512565b600080611cf5838561239a565b90506000620151806001611d098285612382565b611d13919061239a565b611d1d9190612563565b9050611d497f00000000000000000000000000000000000000000000000000000000000001f48261259e565b95945050505050565b600080612710611d628482612382565b611d6c908661259e565b611d769190612563565b9050611d9881611d88601b600261235d565b611d9390600a61234e565b6120b2565b949350505050565b600080611daf6002601b61220b565b611dba90600a61234e565b90506127108311611de957612710611dd2848261239a565b611ddc908661259e565b611de69190612563565b90505b611d9881611df96002601b61220b565b611e0490600a61234e565b6120c8565b611e327f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6829055565b6040518181527ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9060200160405180910390a150565b60606000611e7783600261259e565b611e82906002612382565b67ffffffffffffffff811115611e9a57611e9a6125db565b6040519080825280601f01601f191660200182016040528015611ec4576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611efb57611efb6123ce565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611f5e57611f5e6123ce565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000611f9a84600261259e565b611fa5906001612382565b90505b6001811115612042577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611fe657611fe66123ce565b1a60f81b828281518110611ffc57611ffc6123ce565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361203b8161260a565b9050611fa8565b5083156120ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610766565b9392505050565b60008183106120c157816120ab565b5090919050565b6000818310156120c157816120ab565b6000602082840312156120ea57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146120ab57600080fd5b6000806040838503121561212d57600080fd5b50508035926020909101359150565b60006020828403121561214e57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461164a57600080fd5b6000806040838503121561218a57600080fd5b82359150602083013561219c81612155565b809150509250929050565b6000806000606084860312156121bc57600080fd5b83356121c781612155565b95602085013595506040909401359392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600060ff821660ff841680821015612225576122256121dc565b90039392505050565b600181815b8085111561228757817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561226d5761226d6121dc565b8085161561227a57918102915b93841c9390800290612233565b509250929050565b60008261229e5750600161066f565b816122ab5750600061066f565b81600181146122c157600281146122cb576122e7565b600191505061066f565b60ff8411156122dc576122dc6121dc565b50506001821b61066f565b5060208310610133831016604e8410600b841016171561230a575081810a61066f565b612314838361222e565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612346576123466121dc565b029392505050565b60006120ab60ff84168361228f565b600060ff821660ff84168060ff0382111561237a5761237a6121dc565b019392505050565b60008219821115612395576123956121dc565b500190565b6000828210156123ac576123ac6121dc565b500390565b6000602082840312156123c357600080fd5b81516120ab81612155565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561245e5761245e6121dc565b5060010190565b60005b83811015612480578181015183820152602001612468565b83811115611bca5750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516124c9816017850160208801612465565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612506816028840160208801612465565b01602801949350505050565b6020815260008251806020840152612531816040850160208701612465565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600082612599577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156125d6576125d66121dc565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600081612619576126196121dc565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220092491d5189b5cf74f329d7721dddff9623a0541f01b93d31ef18e0d6d627bf464736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000042000000000000000000000000000000000000070000000000000000000000001a513e9b6434a12c7bb5b9af3b21963308dee3720000000000000000000000003f9600439ad97fc6f55c2ac7c118f8fd0595eb740000000000000000000000000000000000000000000000000000000000016da0000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000e10
-----Decoded View---------------
Arg [0] : messenger_ (address): 0x4200000000000000000000000000000000000007
Arg [1] : l2ERC20TokenBridge_ (address): 0x1A513e9B6434a12C7bB5B9AF3B21963308DEE372
Arg [2] : l1TokenRatePusher_ (address): 0x3F9600439Ad97fC6f55C2AC7C118f8Fd0595eB74
Arg [3] : tokenRateOutdatedDelay_ (uint256): 93600
Arg [4] : maxAllowedL2ToL1ClockLag_ (uint256): 86400
Arg [5] : maxAllowedTokenRateDeviationPerDayBp_ (uint256): 500
Arg [6] : oldestRateAllowedInPauseTimeSpan_ (uint256): 86400
Arg [7] : minTimeBetweenTokenRateUpdates_ (uint256): 3600
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000004200000000000000000000000000000000000007
Arg [1] : 0000000000000000000000001a513e9b6434a12c7bb5b9af3b21963308dee372
Arg [2] : 0000000000000000000000003f9600439ad97fc6f55c2ac7c118f8fd0595eb74
Arg [3] : 0000000000000000000000000000000000000000000000000000000000016da0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [5] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [6] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000e10
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.