Source Code
Overview
HYPE Balance
HYPE Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PythPriceOracle
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 9999 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
// Terms: https://liminal.money/xtokens/license
pragma solidity 0.8.28;
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {IPriceOracle} from "./interfaces/IPriceOracle.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IPyth} from "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
import {PythStructs} from "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";
/**
* @title PythPriceOracle
* @notice Oracle integration with Pyth Network price feeds
* @dev Uses Pyth's pull-based price model with real-time updates
*/
contract PythPriceOracle is AccessControlUpgradeable, IPriceOracle {
/// @notice Role for managing price IDs
bytes32 public constant PRICE_MANAGER_ROLE = keccak256("PRICE_MANAGER_ROLE");
/// @notice Maximum confidence interval threshold in basis points
uint256 public constant BASIS_POINTS = 10_000;
/// @custom:storage-location erc7201:liminal.pythPriceOracle.v1
struct PythPriceOracleStorage {
/// @notice Timelock controller for critical operations
address timeLockController;
/// @notice Asset address to Pyth price ID mapping
mapping(address => bytes32) priceIds;
/// @notice Asset decimals for conversion
mapping(address => uint8) assetDecimals;
/// @notice Underlying asset of the vault (for redemptions)
address underlyingAsset;
/// @notice Pyth Network oracle contract
IPyth pyth;
/// @notice Maximum price age for staleness check (default 60 seconds)
uint96 maxPriceAge;
/// @notice Maximum confidence interval threshold in basis points (default 50 bps = 0.5%)
uint256 maxConfidenceBps;
}
// keccak256(abi.encode(uint256(keccak256("liminal.storage.pythPriceOracle.v1")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PYTH_PRICE_ORACLE_STORAGE_LOCATION =
0x79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e00;
function _getPythPriceOracleStorage() private pure returns (PythPriceOracleStorage storage $) {
assembly {
$.slot := PYTH_PRICE_ORACLE_STORAGE_LOCATION
}
}
/// Events
event PriceIdSet(address indexed asset, bytes32 priceId, uint8 decimals);
event UnderlyingAssetSet(address indexed asset);
event MaxPriceAgeUpdated(uint96 newMaxAge);
event PythContractUpdated(address indexed newPyth);
event TimelockControllerSet(address indexed oldTimelock, address indexed newTimelock);
event MaxConfidenceBpsUpdated(uint256 newMaxConfidenceBps);
/// @notice Modifier for timelock-protected functions
modifier onlyTimelock() {
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
require(msg.sender == $.timeLockController, "PythOracle: only timelock");
_;
}
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initialize the oracle
* @dev Ownership (DEFAULT_ADMIN_ROLE) is granted to deployer
* @param _deployer Deployer address (receives DEFAULT_ADMIN_ROLE)
* @param _priceManager Initial price manager for setting price IDs
* @param _pyth Pyth Network contract address
* @param _underlyingAsset Vault's underlying asset for redemptions
* @param _timeLockController Timelock controller for critical operations
* @param _maxConfidenceBps Maximum confidence interval threshold in basis points (default 50 bps = 0.5%)
*/
function initialize(
address _deployer,
address _priceManager,
address _pyth,
address _underlyingAsset,
address _timeLockController,
uint256 _maxConfidenceBps
) external initializer {
require(_deployer != address(0), "PythOracle: zero deployer");
require(_priceManager != address(0), "PythOracle: zero manager");
require(_pyth != address(0), "PythOracle: zero pyth");
require(_underlyingAsset != address(0), "PythOracle: zero underlying");
require(_timeLockController != address(0), "PythOracle: zero timelock");
require(_maxConfidenceBps > 0, "PythOracle: zero confidence threshold");
require(_maxConfidenceBps <= BASIS_POINTS, "PythOracle: confidence threshold too high");
__AccessControl_init();
// Grant ownership to deployer
_grantRole(DEFAULT_ADMIN_ROLE, _deployer);
_grantRole(PRICE_MANAGER_ROLE, _priceManager);
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
$.pyth = IPyth(_pyth);
$.underlyingAsset = _underlyingAsset;
$.maxPriceAge = 3600; // 1 hour default
$.timeLockController = _timeLockController;
$.maxConfidenceBps = _maxConfidenceBps;
emit UnderlyingAssetSet(_underlyingAsset);
}
/**
* @notice Set Pyth price ID for an asset
* @param asset Asset address
* @param priceId Pyth price feed ID (32 bytes)
* @param decimals Asset token decimals
*/
function setPriceId(address asset, bytes32 priceId, uint8 decimals) external onlyTimelock {
require(asset != address(0), "PythOracle: zero asset");
require(priceId != bytes32(0), "PythOracle: zero price ID");
require(decimals <= 18, "PythOracle: invalid decimals");
require(decimals == IERC20Metadata(asset).decimals(), "PythOracle: decimals mismatch");
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
$.priceIds[asset] = priceId;
$.assetDecimals[asset] = decimals;
emit PriceIdSet(asset, priceId, decimals);
}
/**
* @notice Batch set price IDs for multiple assets
* @param assets Array of asset addresses
* @param _priceIds Array of Pyth price feed IDs
* @param decimalsArray Array of token decimals
*/
function setPriceIds(address[] calldata assets, bytes32[] calldata _priceIds, uint8[] calldata decimalsArray)
external
onlyTimelock
{
require(assets.length == _priceIds.length, "PythOracle: length mismatch");
require(assets.length == decimalsArray.length, "PythOracle: decimals mismatch");
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
for (uint256 i = 0; i < assets.length; i++) {
require(assets[i] != address(0), "PythOracle: zero asset");
require(_priceIds[i] != bytes32(0), "PythOracle: zero price ID");
require(decimalsArray[i] <= 18, "PythOracle: invalid decimals");
require(decimalsArray[i] == IERC20Metadata(assets[i]).decimals(), "PythOracle: decimals mismatch");
$.priceIds[assets[i]] = _priceIds[i];
$.assetDecimals[assets[i]] = decimalsArray[i];
emit PriceIdSet(assets[i], _priceIds[i], decimalsArray[i]);
}
}
/**
* @notice Get price of asset in terms of underlying asset
* @param asset Asset to price
* @return Price scaled to 18 decimals
*/
function getPrice(address asset) external view override returns (uint256) {
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
if (asset == $.underlyingAsset) {
return 1e18; // 1:1 for underlying asset
}
PythStructs.Price memory assetPrice = _getPythPrice(asset);
PythStructs.Price memory underlyingPrice = _getPythPrice($.underlyingAsset);
// Convert Pyth prices (with expo) to 18 decimal format
uint256 assetPriceUSD = _convertPythPrice(assetPrice);
uint256 underlyingPriceUSD = _convertPythPrice(underlyingPrice);
// Price = (asset price in USD / underlying price in USD) * 1e18
return (assetPriceUSD * 1e18) / underlyingPriceUSD;
}
/**
* @notice Get USD price of an asset
* @param asset Asset address
* @return Price in USD with 8 decimals (Pyth standard)
*/
function getPriceInUSD(address asset) external view override returns (uint256) {
PythStructs.Price memory price = _getPythPrice(asset);
return _convertPythPrice(price);
}
/**
* @notice Convert amount between assets using Pyth prices
* @param fromAsset Source asset
* @param toAsset Target asset
* @param amount Amount in source asset
* @return Converted amount in target asset's native decimals (eg: USDC 6 decimals, WETH 18 decimals)
*/
function convertAmount(address fromAsset, address toAsset, uint256 amount)
external
view
override
returns (uint256)
{
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
if (fromAsset == toAsset) {
// Same asset conversion - always return the same amount
return amount;
}
PythStructs.Price memory fromPrice = _getPythPrice(fromAsset);
PythStructs.Price memory toPrice = _getPythPrice(toAsset);
uint8 fromDecimals = $.assetDecimals[fromAsset];
uint8 toDecimals = $.assetDecimals[toAsset];
require(amount > 0, "PythOracle: zero amount");
// Convert prices to 18 decimals for high precision calculation
uint256 fromPrice18 = _convertPythPriceTo18Decimals(fromPrice);
uint256 toPrice18 = _convertPythPriceTo18Decimals(toPrice);
// Normalize amount to 18 decimals
uint256 amount18 = _normalizeDecimals(amount, fromDecimals, 18);
// Calculate: (amount18 * fromPrice18) / toPrice18
uint256 result18 = (amount18 * fromPrice18) / toPrice18;
// Always return in the target asset's native decimals
return _normalizeDecimals(result18, 18, toDecimals);
}
/**
* @notice Get Pyth price with staleness check
* @param asset Asset address
* @return Pyth price struct
*/
function _getPythPrice(address asset) internal view returns (PythStructs.Price memory) {
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
bytes32 priceId = $.priceIds[asset];
require(priceId != bytes32(0), "PythOracle: price ID not set");
// Check staleness
PythStructs.Price memory price = $.pyth.getPriceNoOlderThan(priceId, $.maxPriceAge);
// Check that price is positive (price.price is int64)
require(price.price > 0, "PythOracle: invalid price");
// Check confidence interval
_validateConfidence(price, $.maxConfidenceBps);
return price;
}
/**
* @notice Validate price confidence interval against threshold
* @param price Pyth price struct
* @param maxConfThreshold Maximum allowed confidence interval in basis points
* @dev Reverts if conf/price ratio exceeds the threshold
*/
function _validateConfidence(PythStructs.Price memory price, uint256 maxConfThreshold) internal pure {
// Calculate confidence ratio: (conf / price) * BASIS_POINTS
// Both conf and price have the same exponent, so we can compare them directly
uint256 confidenceRatioBps = (uint256(price.conf) * BASIS_POINTS) / uint256(uint64(price.price));
require(
confidenceRatioBps <= maxConfThreshold,
"PythOracle: confidence interval too wide"
);
}
/**
* @notice Convert Pyth price to standard 8-decimal format
* @param price Pyth price struct
* @return Price in 8 decimals
*/
function _convertPythPrice(PythStructs.Price memory price) internal pure returns (uint256) {
require(price.price > 0, "PythOracle: invalid price");
// Convert to 8 decimal places
// If expo = -6 and we want -8, we need to multiply by 10^2
// If expo = -10 and we want -8, we need to divide by 10^2
int256 normalizedPrice;
int32 targetExpo = -8;
if (price.expo == targetExpo) {
normalizedPrice = price.price;
} else if (price.expo > targetExpo) {
// expo is less negative (fewer decimals), need to add decimals
// expo=-6, target=-8: multiply by 10^2
uint256 scaleFactor = 10 ** uint256(int256(price.expo - targetExpo));
normalizedPrice = price.price * int256(scaleFactor);
} else {
// expo is more negative (more decimals), need to remove decimals
// expo=-10, target=-8: divide by 10^2
uint256 scaleFactor = 10 ** uint256(int256(targetExpo - price.expo));
normalizedPrice = price.price / int256(scaleFactor);
}
require(normalizedPrice > 0, "PythOracle: price conversion failed");
return uint256(normalizedPrice);
}
/**
* @notice Convert Pyth price to 18-decimal format for high precision calculations
* @param price Pyth price struct
* @return Price in 18 decimals
*/
function _convertPythPriceTo18Decimals(PythStructs.Price memory price) internal pure returns (uint256) {
require(price.price > 0, "PythOracle: invalid price");
// First convert to 8 decimals using existing logic
uint256 price8Decimals = _convertPythPrice(price);
// Then convert from 8 decimals to 18 decimals
return price8Decimals * 1e10; // 18 - 8 = 10
}
/**
* @notice Get maximum of two values
* @param a First value
* @param b Second value
* @return Maximum value
*/
function max(uint8 a, uint8 b) internal pure returns (uint8) {
return a > b ? a : b;
}
/**
* @notice Normalize decimals for calculations
* @param amount Amount to normalize
* @param fromDecimals Current decimals
* @param toDecimals Target decimals
* @return Normalized amount
*/
function _normalizeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) {
if (fromDecimals == toDecimals) {
return amount;
}
if (fromDecimals > toDecimals) {
return amount / (10 ** (fromDecimals - toDecimals));
} else {
return amount * (10 ** (toDecimals - fromDecimals));
}
}
// ========== ADMIN FUNCTIONS ==========
/**
* @notice Update Pyth contract address
* @param _pyth New Pyth contract address
*/
function setPythContract(address _pyth) external onlyTimelock {
require(_pyth != address(0), "PythOracle: zero address");
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
$.pyth = IPyth(_pyth);
emit PythContractUpdated(_pyth);
}
/**
* @notice Update underlying asset
* @param _underlyingAsset New underlying asset address
*/
function setUnderlyingAsset(address _underlyingAsset) external onlyTimelock {
require(_underlyingAsset != address(0), "PythOracle: zero address");
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
$.underlyingAsset = _underlyingAsset;
emit UnderlyingAssetSet(_underlyingAsset);
}
/**
* @notice Update maximum price age
* @param _maxPriceAge New maximum age in seconds
*/
function setMaxPriceAge(uint96 _maxPriceAge) external onlyTimelock {
require(_maxPriceAge > 0, "PythOracle: zero max age");
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
$.maxPriceAge = _maxPriceAge;
emit MaxPriceAgeUpdated(_maxPriceAge);
}
/**
* @notice Set the timelock controller
* @param _timeLockController New timelock controller address
* @dev Can only be called by the current timelock (with delay enforced by VaultTimelockController)
*/
function setTimelockController(address _timeLockController) external onlyTimelock {
require(_timeLockController != address(0), "PythOracle: zero timelock");
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
address oldTimelock = $.timeLockController;
$.timeLockController = _timeLockController;
emit TimelockControllerSet(oldTimelock, _timeLockController);
}
/**
* @notice Update maximum confidence interval threshold
* @param _maxConfidenceBps New maximum confidence interval in basis points
*/
function setMaxConfidenceBps(uint256 _maxConfidenceBps) external onlyTimelock {
require(_maxConfidenceBps > 0, "PythOracle: zero confidence threshold");
require(_maxConfidenceBps <= BASIS_POINTS, "PythOracle: confidence threshold too high");
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
$.maxConfidenceBps = _maxConfidenceBps;
emit MaxConfidenceBpsUpdated(_maxConfidenceBps);
}
/**
* @notice Check if asset has price feed configured
* @param asset Asset address
* @return True if price ID is set
*/
function hasPriceFeed(address asset) external view returns (bool) {
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
return $.priceIds[asset] != bytes32(0);
}
/**
* @notice Get the latest price update fee for Pyth
* @param updateData Array of price update data
* @return fee Update fee in wei
*/
function getUpdateFee(bytes[] calldata updateData) external view returns (uint256) {
PythPriceOracleStorage storage $ = _getPythPriceOracleStorage();
return $.pyth.getUpdateFee(updateData);
}
// ========== GETTER FUNCTIONS ==========
/// @notice Get timelock controller address
function timeLockController() external view returns (address) {
return _getPythPriceOracleStorage().timeLockController;
}
/// @notice Get Pyth contract address
function pyth() external view returns (IPyth) {
return _getPythPriceOracleStorage().pyth;
}
/// @notice Get price ID for an asset
function priceIds(address asset) external view returns (bytes32) {
return _getPythPriceOracleStorage().priceIds[asset];
}
/// @notice Get asset decimals
function assetDecimals(address asset) external view returns (uint8) {
return _getPythPriceOracleStorage().assetDecimals[asset];
}
/// @notice Get underlying asset address
function underlyingAsset() external view returns (address) {
return _getPythPriceOracleStorage().underlyingAsset;
}
/// @notice Get maximum price age
function maxPriceAge() external view returns (uint96) {
return _getPythPriceOracleStorage().maxPriceAge;
}
/// @notice Get maximum confidence interval threshold
function maxConfidenceBps() external view returns (uint256) {
return _getPythPriceOracleStorage().maxConfidenceBps;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
bytes32 previousAdminRole = getRoleAdmin(role);
$._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
/**
* @title IPriceOracle
* @notice Interface for price oracle
*/
interface IPriceOracle {
function getPrice(address asset) external view returns (uint256);
function getPriceInUSD(address asset) external view returns (uint256);
function convertAmount(address fromAsset, address toAsset, uint256 amount) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity >=0.6.2;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./PythStructs.sol";
import "./IPythEvents.sol";
/// @title Consume prices from the Pyth Network (https://pyth.network/).
/// @dev Please refer to the guidance at https://docs.pyth.network/consumers/best-practices for how to consume prices safely.
/// @author Pyth Data Association
interface IPyth is IPythEvents {
/// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time
function getValidTimePeriod() external view returns (uint validTimePeriod);
/// @notice Returns the price and confidence interval.
/// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds.
/// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPrice(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price and confidence interval.
/// @dev Reverts if the EMA price is not available.
/// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPrice(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the price of a price feed without any sanity checks.
/// @dev This function returns the most recent price update in this contract without any recency checks.
/// This function is unsafe as the returned price update may be arbitrarily far in the past.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getPrice` or `getPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceUnsafe(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the price that is no older than `age` seconds of the current time.
/// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.
/// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.
/// However, if the price is not recent this function returns the latest available price.
///
/// The returned price can be from arbitrarily far in the past; this function makes no guarantees that
/// the returned price is recent or useful for any particular application.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceUnsafe(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds
/// of the current time.
/// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (PythStructs.Price memory price);
/// @notice Update price feeds with given update messages.
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
/// Prices will be updated if they are more recent than the current stored prices.
/// The call will succeed even if the update is not the most recent.
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
function updatePriceFeeds(bytes[] calldata updateData) external payable;
/// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is
/// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the
/// given `publishTimes` for the price feeds and does not read the actual price update publish time within `updateData`.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
///
/// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime
/// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have
/// a newer or equal publish time than the given publish time, it will reject the transaction to save gas.
/// Otherwise, it calls updatePriceFeeds method to update the prices.
///
/// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`
function updatePriceFeedsIfNecessary(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64[] calldata publishTimes
) external payable;
/// @notice Returns the required fee to update an array of price updates.
/// @param updateData Array of price update data.
/// @return feeAmount The required fee in Wei.
function getUpdateFee(
bytes[] calldata updateData
) external view returns (uint feeAmount);
/// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published
/// within `minPublishTime` and `maxPublishTime`.
///
/// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price;
/// otherwise, please consider using `updatePriceFeeds`. This method does not store the price updates on-chain.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
///
///
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
/// no update for any of the given `priceIds` within the given time range.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
/// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
/// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
function parsePriceFeedUpdates(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minPublishTime,
uint64 maxPublishTime
) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
contract PythStructs {
// A price with a degree of uncertainty, represented as a price +- a confidence interval.
//
// The confidence interval roughly corresponds to the standard error of a normal distribution.
// Both the price and confidence are stored in a fixed-point numeric representation,
// `x * (10^expo)`, where `expo` is the exponent.
//
// Please refer to the documentation at https://docs.pyth.network/consumers/best-practices for how
// to how this price safely.
struct Price {
// Price
int64 price;
// Confidence interval around the price
uint64 conf;
// Price exponent
int32 expo;
// Unix timestamp describing when the price was published
uint publishTime;
}
// PriceFeed represents a current aggregate price from pyth publisher feeds.
struct PriceFeed {
// The price ID.
bytes32 id;
// Latest available price
Price price;
// Latest available exponentially-weighted moving average price
Price emaPrice;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)
pragma solidity >=0.8.4;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted to signal this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @title IPythEvents contains the events that Pyth contract emits.
/// @dev This interface can be used for listening to the updates for off-chain and testing purposes.
interface IPythEvents {
/// @dev Emitted when the price feed with `id` has received a fresh update.
/// @param id The Pyth Price Feed ID.
/// @param publishTime Publish time of the given price update.
/// @param price Price of the given price update.
/// @param conf Confidence interval of the given price update.
event PriceFeedUpdate(
bytes32 indexed id,
uint64 publishTime,
int64 price,
uint64 conf
);
/// @dev Emitted when a batch price update is processed successfully.
/// @param chainId ID of the source chain that the batch price update comes from.
/// @param sequenceNumber Sequence number of the batch price update.
event BatchPriceFeedUpdate(uint16 chainId, uint64 sequenceNumber);
}{
"remappings": [
"@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@pythnetwork/pyth-sdk-solidity/=lib/pyth-sdk-solidity/",
"@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/",
"@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/",
"@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/",
"@layerzerolabs/ovault-evm/=lib/devtools/packages/ovault-evm/",
"@layerzerolabs/oft-alt-evm/=lib/devtools/packages/oft-alt-evm/",
"@layerzerolabs/oft-evm-upgradeable/=lib/devtools/packages/oft-evm-upgradeable/",
"@layerzerolabs/oapp-evm-upgradeable/=lib/devtools/packages/oapp-evm-upgradeable/",
"@layerzerolabs/hyperliquid-composer/=lib/devtools/packages/hyperliquid-composer/",
"forge-std/=lib/forge-std/src/",
"solidity-bytes-utils/=lib/solidity-bytes-utils/",
"src/=src/",
"@hyper-evm-lib/=lib/hyper-evm-lib/",
"LayerZero-v2/=lib/LayerZero-v2/",
"devtools/=lib/devtools/packages/toolbox-foundry/src/",
"ds-test/=lib/solidity-bytes-utils/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"hyper-evm-lib/=lib/hyper-evm-lib/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"pyth-sdk-solidity/=lib/pyth-sdk-solidity/"
],
"optimizer": {
"enabled": true,
"runs": 9999
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxConfidenceBps","type":"uint256"}],"name":"MaxConfidenceBpsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"newMaxAge","type":"uint96"}],"name":"MaxPriceAgeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bytes32","name":"priceId","type":"bytes32"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"PriceIdSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newPyth","type":"address"}],"name":"PythContractUpdated","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":true,"internalType":"address","name":"oldTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockControllerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"}],"name":"UnderlyingAssetSet","type":"event"},{"inputs":[],"name":"BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"assetDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAsset","type":"address"},{"internalType":"address","name":"toAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"convertAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getPriceInUSD","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":"bytes[]","name":"updateData","type":"bytes[]"}],"name":"getUpdateFee","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":"address","name":"asset","type":"address"}],"name":"hasPriceFeed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":"_deployer","type":"address"},{"internalType":"address","name":"_priceManager","type":"address"},{"internalType":"address","name":"_pyth","type":"address"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"address","name":"_timeLockController","type":"address"},{"internalType":"uint256","name":"_maxConfidenceBps","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxConfidenceBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPriceAge","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"priceIds","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pyth","outputs":[{"internalType":"contract IPyth","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","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":"uint256","name":"_maxConfidenceBps","type":"uint256"}],"name":"setMaxConfidenceBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"_maxPriceAge","type":"uint96"}],"name":"setMaxPriceAge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bytes32","name":"priceId","type":"bytes32"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"setPriceId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"bytes32[]","name":"_priceIds","type":"bytes32[]"},{"internalType":"uint8[]","name":"decimalsArray","type":"uint8[]"}],"name":"setPriceIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pyth","type":"address"}],"name":"setPythContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_timeLockController","type":"address"}],"name":"setTimelockController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"}],"name":"setUnderlyingAsset","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":[],"name":"timeLockController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6080806040523460aa575f5160206128ac5f395f51905f525460ff8160401c16609b576002600160401b03196001600160401b038216016049575b6040516127fd90816100af8239f35b6001600160401b0319166001600160401b039081175f5160206128ac5f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80603a565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146117145750806302266147146116e95780630b7983a2146116c05780631584410a14611681578063248a9ca31461163757806325671dcb146115aa578063267f99bf1461156e5780632a94ac3f146114a25780632f2ff15d1461144557806331aab7591461140b57806333fbeb621461131457806336568abe146112b757806341976e09146112945780635396526c1461124f57806358b0c4ba1461110257806361041fba14610f5057806369e1829d14610f195780637158da7c14610ed457806391d1485414610e6b57806395b6ef0c1461086b578063a217fddf14610851578063b19ddcfd14610571578063d47eed4514610392578063d547741f1461032e578063db7a6828146102d1578063e1f1c4a7146102b5578063e366da2c14610255578063ef0494e6146101a45763f98d06f01461015b575f80fd5b346101a0575f6003193601126101a05760206001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416604051908152f35b5f80fd5b346101a05760206003193601126101a0577fa4d8db16e714f24a5429549843704a397ae863e6563cf9f0de80a9f2869687a660206004356102106001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b61021b811515611cff565b610229612710821115611d70565b807f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0555604051908152a1005b346101a05760206003193601126101a057602060ff6102ab6102756117b2565b6001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0260205260405f2090565b5416604051908152f35b346101a0575f6003193601126101a05760206040516127108152f35b346101a05760206003193601126101a05760206103256102ef6117b2565b6001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0160205260405f2090565b54604051908152f35b346101a05760406003193601126101a05761039060043561034d6117c8565b9061038b610386825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b61236a565b61262b565b005b346101a05760206003193601126101a05760043567ffffffffffffffff81116101a0576103c39036906004016117de565b906001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416906040519283917fd47eed45000000000000000000000000000000000000000000000000000000008352816024840160206004860152526044830160448360051b85010192825f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603015b8383106104c55787602081808a03818d5afa80156104ba575f90610487575b602090604051908152f35b506020813d6020116104b2575b816104a160209383611b2c565b810103126101a0576020905161047c565b3d9150610494565b6040513d5f823e3d90fd5b919395909294967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc9082030186528635828112156101a0578301906020823592019167ffffffffffffffff81116101a05780360383136101a0576020827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8480600198869897879852868601375f858286010152011601019801960193019091889695949261045d565b346101a05760606003193601126101a05760043567ffffffffffffffff81116101a0576105a29036906004016117de565b60243567ffffffffffffffff81116101a0576105c29036906004016117de565b9160443567ffffffffffffffff81116101a0576105e39036906004016117de565b94909261061b6001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b84830361080d5761062d868414611b86565b5f5b83811061063857005b61065e6001600160a01b03610656610651848888611de1565b611e1e565b161515611a02565b61067461066c828885611de1565b351515611a4d565b610696601260ff61068e610689858c8b611de1565b611e32565b161115611a98565b6106a4610689828988611de1565b90600460206001600160a01b036106bf610651858a8a611de1565b16604051928380927f313ce5670000000000000000000000000000000000000000000000000000000082525afa9081156104ba576001600160a01b03856107d66107b8610689878f8f8f998f918f61065160019f6107b1958f937f12ead2dbe6fe8bad0a93e6223af8fd2da939e604cd40e48c78bb5acbb8d89cca9f6106898f8b6107ab986107708f8c819e9561076b839c60ff80869a6107889d5f916107df575b5016911614611b86565b611de1565b356107826102ef610651868b8b611de1565b55611de1565b60ff61079b610275610651878787611de1565b911660ff19825416179055611de1565b98611de1565b3598611de1565b60405193849316958390929160ff6020916040840195845216910152565b0390a20161062f565b610800915060203d8111610806575b6107f88183611b2c565b810190611b6d565b5f610761565b503d6107ee565b606460405162461bcd60e51b815260206004820152601b60248201527f507974684f7261636c653a206c656e677468206d69736d6174636800000000006044820152fd5b346101a0575f6003193601126101a05760206040515f8152f35b346101a05760c06003193601126101a0576108846117b2565b61088c6117c8565b604435906001600160a01b0382168092036101a0576064356001600160a01b038116938482036101a057608435916001600160a01b0383168093036101a05760a435937ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549560ff8760401c16159667ffffffffffffffff811680159081610e63575b6001149081610e59575b159081610e50575b50610e28578760017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008316177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055610dd3575b506001600160a01b03841615610d8f576001600160a01b03821615610d4b578015610d07578715610cc3576109aa8515156118a5565b6109b5861515611cff565b6109c3612710871115611d70565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615610c9b57610a09610a7c92610a03610aee966123e3565b50612492565b506001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0455565b6001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e035416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0355565b750e1000000000000000000000000000000000000000006001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e04557fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e00557f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0555604051917fae7ae359404b7f0ea7bff482c4942812b3a832a7435df97a0e0481974f85e7615f80a2610c0a57005b60207fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2917fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005560018152a1005b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b606460405162461bcd60e51b815260206004820152601b60248201527f507974684f7261636c653a207a65726f20756e6465726c79696e6700000000006044820152fd5b606460405162461bcd60e51b815260206004820152601560248201527f507974684f7261636c653a207a65726f207079746800000000000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601860248201527f507974684f7261636c653a207a65726f206d616e6167657200000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a207a65726f206465706c6f796572000000000000006044820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005588610974565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b9050158a610921565b303b159150610919565b89915061090f565b346101a05760406003193601126101a057610e846117c8565b6004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346101a0575f6003193601126101a05760206001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e035416604051908152f35b346101a05760606003193601126101a0576020610f48610f376117b2565b610f3f6117c8565b60443591611bd1565b604051908152f35b346101a05760606003193601126101a057610f696117b2565b6024359060443560ff8116928382036101a057610fb16001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b6001600160a01b03831693610fc7851515611a02565b610fd2821515611a4d565b610fdf6012821115611a98565b6040517f313ce567000000000000000000000000000000000000000000000000000000008152602081600481895afa9485156104ba5761105060ff7f12ead2dbe6fe8bad0a93e6223af8fd2da939e604cd40e48c78bb5acbb8d89cca976110c2945f916110e3575b50168414611b86565b8361108b826001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0160205260405f2090565b556001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0260205260405f2090565b805460ff19169190911790556040805191825260ff929092166020820152a2005b6110fc915060203d602011610806576107f88183611b2c565b8a611047565b346101a05760206003193601126101a0576004356bffffffffffffffffffffffff8116908181036101a0576111626001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b811561120b577fb67b19b7d690779d3527a62b17c2b5a1999dcaf245f4c256b90c3aa7ec17869c916020916001600160a01b037fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e04549260a01b169116177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0455604051908152a1005b606460405162461bcd60e51b815260206004820152601860248201527f507974684f7261636c653a207a65726f206d61782061676500000000000000006044820152fd5b346101a0575f6003193601126101a05760206001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416604051908152f35b346101a05760206003193601126101a0576020610f486112b26117b2565b611967565b346101a05760406003193601126101a0576112d06117c8565b336001600160a01b038216036112ec576103909060043561262b565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101a05760206003193601126101a0576001600160a01b036113356117b2565b611363827f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b1661136f81151561185a565b6113e5816001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0455565b7fd4c2825f9c4e957c9c076ef67fb370c0d3fb435ea8eea471ba9bfc9e8a4ac8f25f80a2005b346101a0575f6003193601126101a05760206040517f3515f38d031dcbca5f1dac4c5afc1efca2020e42efdd9c5806ae7e963d18435a8152f35b346101a05760406003193601126101a0576103906004356114646117c8565b9061149d610386825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b61255e565b346101a05760206003193601126101a0577fffffffffffffffffffffffff00000000000000000000000000000000000000006114dc6117b2565b7f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e00546001600160a01b038082169261151584331461180f565b169283916115248315156118a5565b16177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e00557f1d87f057e6bf90805585c1d6a7f32a68db5fee62898018cb09508b4090fa412b5f80a3005b346101a0575f6003193601126101a05760207f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0554604051908152f35b346101a05760206003193601126101a0576115c36117b2565b6115f86001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b6116116001600160a01b03821691610a7c83151561185a565b7fae7ae359404b7f0ea7bff482c4942812b3a832a7435df97a0e0481974f85e7615f80a2005b346101a05760206003193601126101a0576020610f486004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b346101a0575f6003193601126101a05760207f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045460a01c604051908152f35b346101a05760206003193601126101a05760206116de6102ef6117b2565b541515604051908152f35b346101a05760206003193601126101a0576020610f4861170f61170a6117b2565b611e8b565b61211c565b346101a05760206003193601126101a057600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101a057817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115611788575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483611781565b600435906001600160a01b03821682036101a057565b602435906001600160a01b03821682036101a057565b9181601f840112156101a05782359167ffffffffffffffff83116101a0576020808501948460051b0101116101a057565b1561181657565b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a206f6e6c792074696d656c6f636b000000000000006044820152fd5b1561186157565b606460405162461bcd60e51b815260206004820152601860248201527f507974684f7261636c653a207a65726f206164647265737300000000000000006044820152fd5b156118ac57565b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a207a65726f2074696d656c6f636b000000000000006044820152fd5b8181029291811591840414171561190357565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b811561193a570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b6001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e03541690816001600160a01b038216146119f4576119c16119bb6119b56119c793611e8b565b93611e8b565b9261211c565b9161211c565b670de0b6b3a7640000820291808304670de0b6b3a76400001490151715611903576119f191611930565b90565b5050670de0b6b3a764000090565b15611a0957565b606460405162461bcd60e51b815260206004820152601660248201527f507974684f7261636c653a207a65726f206173736574000000000000000000006044820152fd5b15611a5457565b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a207a65726f207072696365204944000000000000006044820152fd5b15611a9f57565b606460405162461bcd60e51b815260206004820152601c60248201527f507974684f7261636c653a20696e76616c696420646563696d616c73000000006044820152fd5b6080810190811067ffffffffffffffff821117611aff57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611aff57604052565b908160209103126101a0575160ff811681036101a05790565b15611b8d57565b606460405162461bcd60e51b815260206004820152601d60248201527f507974684f7261636c653a20646563696d616c73206d69736d617463680000006044820152fd5b916001600160a01b0382166001600160a01b03841614611cf957611bf483611e8b565b9060ff611c7781611c3e611c0787611e8b565b976001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0260205260405f2090565b5416946001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0260205260405f2090565b5416928115611cb5576119f194611ca6611cab92611ca0611c9a611cb0976126ee565b936126ee565b94612744565b6118f0565b611930565b612791565b606460405162461bcd60e51b815260206004820152601760248201527f507974684f7261636c653a207a65726f20616d6f756e740000000000000000006044820152fd5b91505090565b15611d0657565b608460405162461bcd60e51b815260206004820152602560248201527f507974684f7261636c653a207a65726f20636f6e666964656e6365207468726560448201527f73686f6c640000000000000000000000000000000000000000000000000000006064820152fd5b15611d7757565b608460405162461bcd60e51b815260206004820152602960248201527f507974684f7261636c653a20636f6e666964656e6365207468726573686f6c6460448201527f20746f6f206869676800000000000000000000000000000000000000000000006064820152fd5b9190811015611df15760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b356001600160a01b03811681036101a05790565b3560ff811681036101a05790565b15611e4757565b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a20696e76616c6964207072696365000000000000006044820152fd5b611ee5905f6060604051611e9e81611ae3565b82815282602082015282604082015201526001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0160205260405f2090565b5480156120ca5760806001600160a01b039160447f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e04549160405194859384927fa4ae35e000000000000000000000000000000000000000000000000000000000845260048401528060a01c6024840152165afa9081156104ba575f91612044575b50611f765f825160070b13611e40565b7f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e055467ffffffffffffffff602083015116612710810290808204612710149015171561190357611fd29067ffffffffffffffff84511690611930565b11611fda5790565b608460405162461bcd60e51b815260206004820152602860248201527f507974684f7261636c653a20636f6e666964656e636520696e74657276616c2060448201527f746f6f20776964650000000000000000000000000000000000000000000000006064820152fd5b90506080813d6080116120c2575b8161205f60809383611b2c565b810103126101a0576040519061207482611ae3565b80518060070b81036101a0578252602081015167ffffffffffffffff811681036101a05760208301526040810151908160030b82036101a0576060916040840152015160608201525f611f66565b3d9150612052565b606460405162461bcd60e51b815260206004820152601c60248201527f507974684f7261636c653a207072696365204944206e6f7420736574000000006044820152fd5b604d811161190357600a0a90565b61212b5f825160070b13611e40565b60408101805160030b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff882036121d85750505160070b5b5f81131561216e5790565b608460405162461bcd60e51b815260206004820152602360248201527f507974684f7261636c653a20707269636520636f6e76657273696f6e2066616960448201527f6c656400000000000000000000000000000000000000000000000000000000006064820152fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff88213156122b057600891505160030b01637fffffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000821217611903576122449060030b61210e565b905160070b818102917f800000000000000000000000000000000000000000000000000000000000000081145f8312166119035781830514901517612163577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff803637fffffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000008212176119035761230e9060030b61210e565b905160070b811561193a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82147f80000000000000000000000000000000000000000000000000000000000000008214166119035705612163565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0333165f5260205260ff60405f205416156123b45750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b6001600160a01b0381165f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1661248d576001600160a01b03165f8181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d60205260408120805460ff191660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b505f90565b6001600160a01b0381165f9081527fe0f046686b1edc4d344636b7deb5220de95653dbaa8432f1f459800335f71413602052604090205460ff1661248d576001600160a01b03165f8181527fe0f046686b1edc4d344636b7deb5220de95653dbaa8432f1f459800335f7141360205260408120805460ff191660011790553391907f3515f38d031dcbca5f1dac4c5afc1efca2020e42efdd9c5806ae7e963d18435a907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0383165f5260205260ff60405f205416155f1461262557805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0383165f5260205260405f20600160ff198254161790556001600160a01b03339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0383165f5260205260ff60405f2054165f1461262557805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0383165f5260205260405f2060ff1981541690556001600160a01b03339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b6127019061170f5f825160070b13611e40565b6402540be4008102908082046402540be40014901517156119035790565b9060ff8091169116039060ff821161190357565b60ff16604d811161190357600a0a90565b60ff82166012811461278b57601210156127745761276e61276960126119f19461271f565b612733565b90611930565b6127856127696119f193601261271f565b906118f0565b50905090565b60ff82168060121461278b57601211156127b65761276e6127696119f193601261271f565b61278561276960126119f19461271f56fea2646970667358221220344b59826bbc010c939e7f653052d466273c9bb73161d608ca477107068516b064736f6c634300081c0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146117145750806302266147146116e95780630b7983a2146116c05780631584410a14611681578063248a9ca31461163757806325671dcb146115aa578063267f99bf1461156e5780632a94ac3f146114a25780632f2ff15d1461144557806331aab7591461140b57806333fbeb621461131457806336568abe146112b757806341976e09146112945780635396526c1461124f57806358b0c4ba1461110257806361041fba14610f5057806369e1829d14610f195780637158da7c14610ed457806391d1485414610e6b57806395b6ef0c1461086b578063a217fddf14610851578063b19ddcfd14610571578063d47eed4514610392578063d547741f1461032e578063db7a6828146102d1578063e1f1c4a7146102b5578063e366da2c14610255578063ef0494e6146101a45763f98d06f01461015b575f80fd5b346101a0575f6003193601126101a05760206001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416604051908152f35b5f80fd5b346101a05760206003193601126101a0577fa4d8db16e714f24a5429549843704a397ae863e6563cf9f0de80a9f2869687a660206004356102106001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b61021b811515611cff565b610229612710821115611d70565b807f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0555604051908152a1005b346101a05760206003193601126101a057602060ff6102ab6102756117b2565b6001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0260205260405f2090565b5416604051908152f35b346101a0575f6003193601126101a05760206040516127108152f35b346101a05760206003193601126101a05760206103256102ef6117b2565b6001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0160205260405f2090565b54604051908152f35b346101a05760406003193601126101a05761039060043561034d6117c8565b9061038b610386825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b61236a565b61262b565b005b346101a05760206003193601126101a05760043567ffffffffffffffff81116101a0576103c39036906004016117de565b906001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416906040519283917fd47eed45000000000000000000000000000000000000000000000000000000008352816024840160206004860152526044830160448360051b85010192825f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603015b8383106104c55787602081808a03818d5afa80156104ba575f90610487575b602090604051908152f35b506020813d6020116104b2575b816104a160209383611b2c565b810103126101a0576020905161047c565b3d9150610494565b6040513d5f823e3d90fd5b919395909294967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc9082030186528635828112156101a0578301906020823592019167ffffffffffffffff81116101a05780360383136101a0576020827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8480600198869897879852868601375f858286010152011601019801960193019091889695949261045d565b346101a05760606003193601126101a05760043567ffffffffffffffff81116101a0576105a29036906004016117de565b60243567ffffffffffffffff81116101a0576105c29036906004016117de565b9160443567ffffffffffffffff81116101a0576105e39036906004016117de565b94909261061b6001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b84830361080d5761062d868414611b86565b5f5b83811061063857005b61065e6001600160a01b03610656610651848888611de1565b611e1e565b161515611a02565b61067461066c828885611de1565b351515611a4d565b610696601260ff61068e610689858c8b611de1565b611e32565b161115611a98565b6106a4610689828988611de1565b90600460206001600160a01b036106bf610651858a8a611de1565b16604051928380927f313ce5670000000000000000000000000000000000000000000000000000000082525afa9081156104ba576001600160a01b03856107d66107b8610689878f8f8f998f918f61065160019f6107b1958f937f12ead2dbe6fe8bad0a93e6223af8fd2da939e604cd40e48c78bb5acbb8d89cca9f6106898f8b6107ab986107708f8c819e9561076b839c60ff80869a6107889d5f916107df575b5016911614611b86565b611de1565b356107826102ef610651868b8b611de1565b55611de1565b60ff61079b610275610651878787611de1565b911660ff19825416179055611de1565b98611de1565b3598611de1565b60405193849316958390929160ff6020916040840195845216910152565b0390a20161062f565b610800915060203d8111610806575b6107f88183611b2c565b810190611b6d565b5f610761565b503d6107ee565b606460405162461bcd60e51b815260206004820152601b60248201527f507974684f7261636c653a206c656e677468206d69736d6174636800000000006044820152fd5b346101a0575f6003193601126101a05760206040515f8152f35b346101a05760c06003193601126101a0576108846117b2565b61088c6117c8565b604435906001600160a01b0382168092036101a0576064356001600160a01b038116938482036101a057608435916001600160a01b0383168093036101a05760a435937ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549560ff8760401c16159667ffffffffffffffff811680159081610e63575b6001149081610e59575b159081610e50575b50610e28578760017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008316177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055610dd3575b506001600160a01b03841615610d8f576001600160a01b03821615610d4b578015610d07578715610cc3576109aa8515156118a5565b6109b5861515611cff565b6109c3612710871115611d70565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c1615610c9b57610a09610a7c92610a03610aee966123e3565b50612492565b506001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0455565b6001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e035416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0355565b750e1000000000000000000000000000000000000000006001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e04557fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e00557f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0555604051917fae7ae359404b7f0ea7bff482c4942812b3a832a7435df97a0e0481974f85e7615f80a2610c0a57005b60207fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2917fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005560018152a1005b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b606460405162461bcd60e51b815260206004820152601b60248201527f507974684f7261636c653a207a65726f20756e6465726c79696e6700000000006044820152fd5b606460405162461bcd60e51b815260206004820152601560248201527f507974684f7261636c653a207a65726f207079746800000000000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601860248201527f507974684f7261636c653a207a65726f206d616e6167657200000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a207a65726f206465706c6f796572000000000000006044820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005588610974565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b9050158a610921565b303b159150610919565b89915061090f565b346101a05760406003193601126101a057610e846117c8565b6004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346101a0575f6003193601126101a05760206001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e035416604051908152f35b346101a05760606003193601126101a0576020610f48610f376117b2565b610f3f6117c8565b60443591611bd1565b604051908152f35b346101a05760606003193601126101a057610f696117b2565b6024359060443560ff8116928382036101a057610fb16001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b6001600160a01b03831693610fc7851515611a02565b610fd2821515611a4d565b610fdf6012821115611a98565b6040517f313ce567000000000000000000000000000000000000000000000000000000008152602081600481895afa9485156104ba5761105060ff7f12ead2dbe6fe8bad0a93e6223af8fd2da939e604cd40e48c78bb5acbb8d89cca976110c2945f916110e3575b50168414611b86565b8361108b826001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0160205260405f2090565b556001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0260205260405f2090565b805460ff19169190911790556040805191825260ff929092166020820152a2005b6110fc915060203d602011610806576107f88183611b2c565b8a611047565b346101a05760206003193601126101a0576004356bffffffffffffffffffffffff8116908181036101a0576111626001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b811561120b577fb67b19b7d690779d3527a62b17c2b5a1999dcaf245f4c256b90c3aa7ec17869c916020916001600160a01b037fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e04549260a01b169116177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0455604051908152a1005b606460405162461bcd60e51b815260206004820152601860248201527f507974684f7261636c653a207a65726f206d61782061676500000000000000006044820152fd5b346101a0575f6003193601126101a05760206001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416604051908152f35b346101a05760206003193601126101a0576020610f486112b26117b2565b611967565b346101a05760406003193601126101a0576112d06117c8565b336001600160a01b038216036112ec576103909060043561262b565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101a05760206003193601126101a0576001600160a01b036113356117b2565b611363827f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b1661136f81151561185a565b6113e5816001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045416177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0455565b7fd4c2825f9c4e957c9c076ef67fb370c0d3fb435ea8eea471ba9bfc9e8a4ac8f25f80a2005b346101a0575f6003193601126101a05760206040517f3515f38d031dcbca5f1dac4c5afc1efca2020e42efdd9c5806ae7e963d18435a8152f35b346101a05760406003193601126101a0576103906004356114646117c8565b9061149d610386825f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b61255e565b346101a05760206003193601126101a0577fffffffffffffffffffffffff00000000000000000000000000000000000000006114dc6117b2565b7f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e00546001600160a01b038082169261151584331461180f565b169283916115248315156118a5565b16177f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e00557f1d87f057e6bf90805585c1d6a7f32a68db5fee62898018cb09508b4090fa412b5f80a3005b346101a0575f6003193601126101a05760207f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0554604051908152f35b346101a05760206003193601126101a0576115c36117b2565b6115f86001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e005416331461180f565b6116116001600160a01b03821691610a7c83151561185a565b7fae7ae359404b7f0ea7bff482c4942812b3a832a7435df97a0e0481974f85e7615f80a2005b346101a05760206003193601126101a0576020610f486004355f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052600160405f20015490565b346101a0575f6003193601126101a05760207f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e045460a01c604051908152f35b346101a05760206003193601126101a05760206116de6102ef6117b2565b541515604051908152f35b346101a05760206003193601126101a0576020610f4861170f61170a6117b2565b611e8b565b61211c565b346101a05760206003193601126101a057600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101a057817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115611788575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483611781565b600435906001600160a01b03821682036101a057565b602435906001600160a01b03821682036101a057565b9181601f840112156101a05782359167ffffffffffffffff83116101a0576020808501948460051b0101116101a057565b1561181657565b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a206f6e6c792074696d656c6f636b000000000000006044820152fd5b1561186157565b606460405162461bcd60e51b815260206004820152601860248201527f507974684f7261636c653a207a65726f206164647265737300000000000000006044820152fd5b156118ac57565b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a207a65726f2074696d656c6f636b000000000000006044820152fd5b8181029291811591840414171561190357565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b811561193a570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b6001600160a01b037f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e03541690816001600160a01b038216146119f4576119c16119bb6119b56119c793611e8b565b93611e8b565b9261211c565b9161211c565b670de0b6b3a7640000820291808304670de0b6b3a76400001490151715611903576119f191611930565b90565b5050670de0b6b3a764000090565b15611a0957565b606460405162461bcd60e51b815260206004820152601660248201527f507974684f7261636c653a207a65726f206173736574000000000000000000006044820152fd5b15611a5457565b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a207a65726f207072696365204944000000000000006044820152fd5b15611a9f57565b606460405162461bcd60e51b815260206004820152601c60248201527f507974684f7261636c653a20696e76616c696420646563696d616c73000000006044820152fd5b6080810190811067ffffffffffffffff821117611aff57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611aff57604052565b908160209103126101a0575160ff811681036101a05790565b15611b8d57565b606460405162461bcd60e51b815260206004820152601d60248201527f507974684f7261636c653a20646563696d616c73206d69736d617463680000006044820152fd5b916001600160a01b0382166001600160a01b03841614611cf957611bf483611e8b565b9060ff611c7781611c3e611c0787611e8b565b976001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0260205260405f2090565b5416946001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0260205260405f2090565b5416928115611cb5576119f194611ca6611cab92611ca0611c9a611cb0976126ee565b936126ee565b94612744565b6118f0565b611930565b612791565b606460405162461bcd60e51b815260206004820152601760248201527f507974684f7261636c653a207a65726f20616d6f756e740000000000000000006044820152fd5b91505090565b15611d0657565b608460405162461bcd60e51b815260206004820152602560248201527f507974684f7261636c653a207a65726f20636f6e666964656e6365207468726560448201527f73686f6c640000000000000000000000000000000000000000000000000000006064820152fd5b15611d7757565b608460405162461bcd60e51b815260206004820152602960248201527f507974684f7261636c653a20636f6e666964656e6365207468726573686f6c6460448201527f20746f6f206869676800000000000000000000000000000000000000000000006064820152fd5b9190811015611df15760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b356001600160a01b03811681036101a05790565b3560ff811681036101a05790565b15611e4757565b606460405162461bcd60e51b815260206004820152601960248201527f507974684f7261636c653a20696e76616c6964207072696365000000000000006044820152fd5b611ee5905f6060604051611e9e81611ae3565b82815282602082015282604082015201526001600160a01b03165f527f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e0160205260405f2090565b5480156120ca5760806001600160a01b039160447f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e04549160405194859384927fa4ae35e000000000000000000000000000000000000000000000000000000000845260048401528060a01c6024840152165afa9081156104ba575f91612044575b50611f765f825160070b13611e40565b7f79f8fe64cf697304b8736b5ceebe50109f667154b58cb0fe6be0d930c76b5e055467ffffffffffffffff602083015116612710810290808204612710149015171561190357611fd29067ffffffffffffffff84511690611930565b11611fda5790565b608460405162461bcd60e51b815260206004820152602860248201527f507974684f7261636c653a20636f6e666964656e636520696e74657276616c2060448201527f746f6f20776964650000000000000000000000000000000000000000000000006064820152fd5b90506080813d6080116120c2575b8161205f60809383611b2c565b810103126101a0576040519061207482611ae3565b80518060070b81036101a0578252602081015167ffffffffffffffff811681036101a05760208301526040810151908160030b82036101a0576060916040840152015160608201525f611f66565b3d9150612052565b606460405162461bcd60e51b815260206004820152601c60248201527f507974684f7261636c653a207072696365204944206e6f7420736574000000006044820152fd5b604d811161190357600a0a90565b61212b5f825160070b13611e40565b60408101805160030b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff882036121d85750505160070b5b5f81131561216e5790565b608460405162461bcd60e51b815260206004820152602360248201527f507974684f7261636c653a20707269636520636f6e76657273696f6e2066616960448201527f6c656400000000000000000000000000000000000000000000000000000000006064820152fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff88213156122b057600891505160030b01637fffffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000821217611903576122449060030b61210e565b905160070b818102917f800000000000000000000000000000000000000000000000000000000000000081145f8312166119035781830514901517612163577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff803637fffffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000008212176119035761230e9060030b61210e565b905160070b811561193a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82147f80000000000000000000000000000000000000000000000000000000000000008214166119035705612163565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0333165f5260205260ff60405f205416156123b45750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b6001600160a01b0381165f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1661248d576001600160a01b03165f8181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d60205260408120805460ff191660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b505f90565b6001600160a01b0381165f9081527fe0f046686b1edc4d344636b7deb5220de95653dbaa8432f1f459800335f71413602052604090205460ff1661248d576001600160a01b03165f8181527fe0f046686b1edc4d344636b7deb5220de95653dbaa8432f1f459800335f7141360205260408120805460ff191660011790553391907f3515f38d031dcbca5f1dac4c5afc1efca2020e42efdd9c5806ae7e963d18435a907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0383165f5260205260ff60405f205416155f1461262557805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0383165f5260205260405f20600160ff198254161790556001600160a01b03339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0383165f5260205260ff60405f2054165f1461262557805f527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260405f206001600160a01b0383165f5260205260405f2060ff1981541690556001600160a01b03339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b6127019061170f5f825160070b13611e40565b6402540be4008102908082046402540be40014901517156119035790565b9060ff8091169116039060ff821161190357565b60ff16604d811161190357600a0a90565b60ff82166012811461278b57601210156127745761276e61276960126119f19461271f565b612733565b90611930565b6127856127696119f193601261271f565b906118f0565b50905090565b60ff82168060121461278b57601211156127b65761276e6127696119f193601261271f565b61278561276960126119f19461271f56fea2646970667358221220344b59826bbc010c939e7f653052d466273c9bb73161d608ca477107068516b064736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in HYPE
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
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.