Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
PythUpgradable
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "./Pyth.sol"; import "./PythInternalStructs.sol"; import "./PythGetters.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "./PythGovernance.sol"; import "./Pyth.sol"; import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol"; contract PythUpgradable is Initializable, OwnableUpgradeable, UUPSUpgradeable, Pyth, PythGovernance { function initialize( address wormhole, uint16[] calldata dataSourceEmitterChainIds, bytes32[] calldata dataSourceEmitterAddresses, uint16 governanceEmitterChainId, bytes32 governanceEmitterAddress, uint64 governanceInitialSequence, uint validTimePeriodSeconds, uint singleUpdateFeeInWei ) public initializer { __Ownable_init(); __UUPSUpgradeable_init(); Pyth._initialize( wormhole, dataSourceEmitterChainIds, dataSourceEmitterAddresses, governanceEmitterChainId, governanceEmitterAddress, governanceInitialSequence, validTimePeriodSeconds, singleUpdateFeeInWei ); renounceOwnership(); } /// Ensures the contract cannot be uninitialized and taken over. /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} // Only allow the owner to upgrade the proxy to a new implementation. // The contract has no owner so this function will always revert // but UUPSUpgradeable expects this method to be implemented. function _authorizeUpgrade(address) internal override onlyOwner {} function pythUpgradableMagic() public pure returns (uint32) { return 0x97a6f304; } // Execute a UpgradeContract governance message function upgradeUpgradableContract( UpgradeContractPayload memory payload ) internal override { address oldImplementation = _getImplementation(); _upgradeToAndCallUUPS(payload.newImplementation, new bytes(0), false); // Calling a method using `this.<method>` will cause a contract call that will use // the new contract. This call will fail if the method does not exists or the magic // is different. if (this.pythUpgradableMagic() != 0x97a6f304) revert PythErrors.InvalidGovernanceMessage(); emit ContractUpgraded(oldImplementation, _getImplementation()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967UpgradeUpgradeable is Initializable { function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { _functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @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] * ``` * 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 Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @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 { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; import "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; import "./PythStructs.sol"; import "./IPyth.sol"; import "./PythErrors.sol"; abstract contract AbstractPyth is IPyth { /// @notice Returns the price feed with given id. /// @dev Reverts if the price does not exist. /// @param id The Pyth Price Feed ID of which to fetch the PriceFeed. function queryPriceFeed( bytes32 id ) public view virtual returns (PythStructs.PriceFeed memory priceFeed); /// @notice Returns true if a price feed with the given id exists. /// @param id The Pyth Price Feed ID of which to check its existence. function priceFeedExists( bytes32 id ) public view virtual returns (bool exists); /// @notice This function is deprecated and is only kept for backward compatibility. function getValidTimePeriod() public view virtual returns (uint validTimePeriod); /// @notice This function is deprecated and is only kept for backward compatibility. function getPrice( bytes32 id ) external view virtual returns (PythStructs.Price memory price) { return getPriceNoOlderThan(id, getValidTimePeriod()); } /// @notice This function is deprecated and is only kept for backward compatibility. function getEmaPrice( bytes32 id ) external view virtual returns (PythStructs.Price memory price) { return getEmaPriceNoOlderThan(id, getValidTimePeriod()); } function getPriceUnsafe( bytes32 id ) public view virtual override returns (PythStructs.Price memory price) { PythStructs.PriceFeed memory priceFeed = queryPriceFeed(id); return priceFeed.price; } function getPriceNoOlderThan( bytes32 id, uint age ) public view virtual override returns (PythStructs.Price memory price) { price = getPriceUnsafe(id); if (diff(block.timestamp, price.publishTime) > age) revert PythErrors.StalePrice(); return price; } function getEmaPriceUnsafe( bytes32 id ) public view virtual override returns (PythStructs.Price memory price) { PythStructs.PriceFeed memory priceFeed = queryPriceFeed(id); return priceFeed.emaPrice; } function getEmaPriceNoOlderThan( bytes32 id, uint age ) public view virtual override returns (PythStructs.Price memory price) { price = getEmaPriceUnsafe(id); if (diff(block.timestamp, price.publishTime) > age) revert PythErrors.StalePrice(); return price; } function diff(uint x, uint y) internal pure returns (uint) { if (x > y) { return x - y; } else { return y - x; } } // Access modifier is overridden to public to be able to call it locally. function updatePriceFeeds( bytes[] calldata updateData ) public payable virtual override; function updatePriceFeedsIfNecessary( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes ) external payable virtual override { if (priceIds.length != publishTimes.length) revert PythErrors.InvalidArgument(); for (uint i = 0; i < priceIds.length; i++) { if ( !priceFeedExists(priceIds[i]) || queryPriceFeed(priceIds[i]).price.publishTime < publishTimes[i] ) { updatePriceFeeds(updateData); return; } } revert PythErrors.NoFreshUpdate(); } function parsePriceFeedUpdates( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64 minPublishTime, uint64 maxPublishTime ) external payable virtual override returns (PythStructs.PriceFeed[] memory priceFeeds); function parsePriceFeedUpdatesUnique( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64 minPublishTime, uint64 maxPublishTime ) external payable virtual override returns (PythStructs.PriceFeed[] memory priceFeeds); }
// 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/documentation/pythnet-price-feeds/best-practices for how to consume prices safely. /// @author Pyth Data Association interface IPyth is IPythEvents { /// @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 `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 may store the price updates on-chain, if they /// are more recent than the current stored prices. /// /// 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); /// @notice Similar to `parsePriceFeedUpdates` but ensures the updates returned are /// the first updates published in minPublishTime. That is, if there are multiple updates for a given timestamp, /// this method will return the first update. This method may store the price updates on-chain, if they /// are more recent than the current stored prices. /// /// /// @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 and uniqueness condition. /// @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 parsePriceFeedUpdatesUnique( 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; /// @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 ); }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; library PythErrors { // Function arguments are invalid (e.g., the arguments lengths mismatch) // Signature: 0xa9cb9e0d error InvalidArgument(); // Update data is coming from an invalid data source. // Signature: 0xe60dce71 error InvalidUpdateDataSource(); // Update data is invalid (e.g., deserialization error) // Signature: 0xe69ffece error InvalidUpdateData(); // Insufficient fee is paid to the method. // Signature: 0x025dbdd4 error InsufficientFee(); // There is no fresh update, whereas expected fresh updates. // Signature: 0xde2c57fa error NoFreshUpdate(); // There is no price feed found within the given range or it does not exists. // Signature: 0x45805f5d error PriceFeedNotFoundWithinRange(); // Price feed not found or it is not pushed on-chain yet. // Signature: 0x14aebe68 error PriceFeedNotFound(); // Requested price is stale. // Signature: 0x19abf40e error StalePrice(); // Given message is not a valid Wormhole VAA. // Signature: 0x2acbe915 error InvalidWormholeVaa(); // Governance message is invalid (e.g., deserialization error). // Signature: 0x97363b35 error InvalidGovernanceMessage(); // Governance message is not for this contract. // Signature: 0x63daeb77 error InvalidGovernanceTarget(); // Governance message is coming from an invalid data source. // Signature: 0x360f2d87 error InvalidGovernanceDataSource(); // Governance message is old. // Signature: 0x88d1b847 error OldGovernanceMessage(); // The wormhole address to set in SetWormholeAddress governance is invalid. // Signature: 0x13d3ed82 error InvalidWormholeAddressToSet(); }
// 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/documentation/pythnet-price-feeds/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: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage( bytes storage _preBytes, bytes memory _postBytes ) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add( add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)) ) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add( add( add(_bytes, lengthmod), mul(0x20, iszero(lengthmod)) ), _start ) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress( bytes memory _bytes, uint256 _start ) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div( mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000 ) } return tempAddress; } function toUint8( bytes memory _bytes, uint256 _start ) internal pure returns (uint8) { require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16( bytes memory _bytes, uint256 _start ) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32( bytes memory _bytes, uint256 _start ) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64( bytes memory _bytes, uint256 _start ) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96( bytes memory _bytes, uint256 _start ) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128( bytes memory _bytes, uint256 _start ) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256( bytes memory _bytes, uint256 _start ) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32( bytes memory _bytes, uint256 _start ) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for { } eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. * * @notice This is the **unsafe** version of BytesLib which removed all the checks (out of bound, ...) * to be more gas efficient. */ pragma solidity >=0.8.0 <0.9.0; library UnsafeBytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage( bytes storage _preBytes, bytes memory _postBytes ) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add( add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)) ) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add( add( add(_bytes, lengthmod), mul(0x20, iszero(lengthmod)) ), _start ) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress( bytes memory _bytes, uint256 _start ) internal pure returns (address) { address tempAddress; assembly { tempAddress := div( mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000 ) } return tempAddress; } function toUint8( bytes memory _bytes, uint256 _start ) internal pure returns (uint8) { uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16( bytes memory _bytes, uint256 _start ) internal pure returns (uint16) { uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32( bytes memory _bytes, uint256 _start ) internal pure returns (uint32) { uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64( bytes memory _bytes, uint256 _start ) internal pure returns (uint64) { uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96( bytes memory _bytes, uint256 _start ) internal pure returns (uint96) { uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128( bytes memory _bytes, uint256 _start ) internal pure returns (uint128) { uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256( bytes memory _bytes, uint256 _start ) internal pure returns (uint256) { uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32( bytes memory _bytes, uint256 _start ) internal pure returns (bytes32) { bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for { } eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. * * @notice This is the **unsafe** version of BytesLib which removed all the checks (out of bound, ...) * to be more gas efficient. */ pragma solidity >=0.8.0 <0.9.0; library UnsafeCalldataBytesLib { function slice( bytes calldata _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes calldata) { return _bytes[_start:_start + _length]; } function sliceFrom( bytes calldata _bytes, uint256 _start ) internal pure returns (bytes calldata) { return _bytes[_start:_bytes.length]; } function toAddress( bytes calldata _bytes, uint256 _start ) internal pure returns (address) { address tempAddress; assembly { tempAddress := shr(96, calldataload(add(_bytes.offset, _start))) } return tempAddress; } function toUint8( bytes calldata _bytes, uint256 _start ) internal pure returns (uint8) { uint8 tempUint; assembly { tempUint := shr(248, calldataload(add(_bytes.offset, _start))) } return tempUint; } function toUint16( bytes calldata _bytes, uint256 _start ) internal pure returns (uint16) { uint16 tempUint; assembly { tempUint := shr(240, calldataload(add(_bytes.offset, _start))) } return tempUint; } function toUint32( bytes calldata _bytes, uint256 _start ) internal pure returns (uint32) { uint32 tempUint; assembly { tempUint := shr(224, calldataload(add(_bytes.offset, _start))) } return tempUint; } function toUint64( bytes calldata _bytes, uint256 _start ) internal pure returns (uint64) { uint64 tempUint; assembly { tempUint := shr(192, calldataload(add(_bytes.offset, _start))) } return tempUint; } function toUint96( bytes calldata _bytes, uint256 _start ) internal pure returns (uint96) { uint96 tempUint; assembly { tempUint := shr(160, calldataload(add(_bytes.offset, _start))) } return tempUint; } function toUint128( bytes calldata _bytes, uint256 _start ) internal pure returns (uint128) { uint128 tempUint; assembly { tempUint := shr(128, calldataload(add(_bytes.offset, _start))) } return tempUint; } function toUint256( bytes calldata _bytes, uint256 _start ) internal pure returns (uint256) { uint256 tempUint; assembly { tempUint := calldataload(add(_bytes.offset, _start)) } return tempUint; } function toBytes32( bytes calldata _bytes, uint256 _start ) internal pure returns (bytes32) { bytes32 tempBytes32; assembly { tempBytes32 := calldataload(add(_bytes.offset, _start)) } return tempBytes32; } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "./external/UnsafeCalldataBytesLib.sol"; /** * @dev This library provides methods to construct and verify Merkle Tree proofs efficiently. * */ library MerkleTree { uint8 constant MERKLE_LEAF_PREFIX = 0; uint8 constant MERKLE_NODE_PREFIX = 1; uint8 constant MERKLE_EMPTY_LEAF_PREFIX = 2; function hash(bytes memory input) internal pure returns (bytes20) { return bytes20(keccak256(input)); } function emptyLeafHash() internal pure returns (bytes20) { return hash(abi.encodePacked(MERKLE_EMPTY_LEAF_PREFIX)); } function leafHash(bytes memory data) internal pure returns (bytes20) { return hash(abi.encodePacked(MERKLE_LEAF_PREFIX, data)); } function nodeHash( bytes20 childA, bytes20 childB ) internal pure returns (bytes20) { if (childA > childB) { (childA, childB) = (childB, childA); } return hash(abi.encodePacked(MERKLE_NODE_PREFIX, childA, childB)); } /// @notice Verify Merkle Tree proof for given leaf data based on data on memory. /// @dev To optimize gas usage, this method doesn't take the proof as a bytes array /// but rather takes the encoded proof and the offset of the proof in the /// encoded proof array possibly containing multiple proofs. Also, the method /// does not perform any check on the boundry of the `encodedProof` and the /// `proofOffset` parameters. It is the caller's responsibility to ensure /// that the `encodedProof` is long enough to contain the proof and the /// `proofOffset` is not out of bound. function isProofValid( bytes calldata encodedProof, uint proofOffset, bytes20 root, bytes calldata leafData ) internal pure returns (bool valid, uint endOffset) { unchecked { bytes20 currentDigest = MerkleTree.leafHash(leafData); uint8 proofSize = UnsafeCalldataBytesLib.toUint8( encodedProof, proofOffset ); proofOffset += 1; for (uint i = 0; i < proofSize; i++) { bytes20 siblingDigest = bytes20( UnsafeCalldataBytesLib.toAddress(encodedProof, proofOffset) ); proofOffset += 20; currentDigest = MerkleTree.nodeHash( currentDigest, siblingDigest ); } valid = currentDigest == root; endOffset = proofOffset; } } /// @notice Construct Merkle Tree proofs for given list of messages. /// @dev This function is only used for testing purposes and is not efficient /// for production use-cases. /// /// This method creates a merkle tree with leaf size of (2^depth) with the /// messages as leafs (in the same given order) and returns the root digest /// and the proofs for each message. If the number of messages is not a power /// of 2, the tree is padded with empty messages. function constructProofs( bytes[] memory messages, uint8 depth ) internal pure returns (bytes20 root, bytes[] memory proofs) { require((1 << depth) >= messages.length, "depth too small"); bytes20[] memory tree = new bytes20[]((1 << (depth + 1))); // The tree is structured as follows: // 1 // 2 3 // 4 5 6 7 // ... // In this structure the parent of node x is x//2 and the children // of node x are x*2 and x*2 + 1. Also, the sibling of the node x // is x^1. The root is at index 1 and index 0 is not used. // Filling the leaf hashes bytes20 cachedEmptyLeafHash = emptyLeafHash(); for (uint i = 0; i < (1 << depth); i++) { if (i < messages.length) { tree[(1 << depth) + i] = leafHash(messages[i]); } else { tree[(1 << depth) + i] = cachedEmptyLeafHash; } } // Filling the node hashes from bottom to top for (uint k = depth; k > 0; k--) { uint level = k - 1; uint levelNumNodes = (1 << level); for (uint i = 0; i < levelNumNodes; i++) { uint id = (1 << level) + i; tree[id] = nodeHash(tree[id * 2], tree[id * 2 + 1]); } } root = tree[1]; proofs = new bytes[](messages.length); for (uint i = 0; i < messages.length; i++) { // depth is the number of sibling nodes in the path from the leaf to the root proofs[i] = abi.encodePacked(depth); uint idx = (1 << depth) + i; // This loop iterates through the leaf and its parents // and keeps adding the sibling of the current node to the proof. while (idx > 1) { proofs[i] = abi.encodePacked( proofs[i], tree[idx ^ 1] // Sibling of this node ); // Jump to parent idx /= 2; } } } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "../libraries/external/UnsafeBytesLib.sol"; import "@pythnetwork/pyth-sdk-solidity/AbstractPyth.sol"; import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol"; import "./PythAccumulator.sol"; import "./PythGetters.sol"; import "./PythSetters.sol"; import "./PythInternalStructs.sol"; abstract contract Pyth is PythGetters, PythSetters, AbstractPyth, PythAccumulator { function _initialize( address wormhole, uint16[] calldata dataSourceEmitterChainIds, bytes32[] calldata dataSourceEmitterAddresses, uint16 governanceEmitterChainId, bytes32 governanceEmitterAddress, uint64 governanceInitialSequence, uint validTimePeriodSeconds, uint singleUpdateFeeInWei ) internal { setWormhole(wormhole); if ( dataSourceEmitterChainIds.length != dataSourceEmitterAddresses.length ) revert PythErrors.InvalidArgument(); for (uint i = 0; i < dataSourceEmitterChainIds.length; i++) { PythInternalStructs.DataSource memory ds = PythInternalStructs .DataSource( dataSourceEmitterChainIds[i], dataSourceEmitterAddresses[i] ); if (PythGetters.isValidDataSource(ds.chainId, ds.emitterAddress)) revert PythErrors.InvalidArgument(); _state.isValidDataSource[hashDataSource(ds)] = true; _state.validDataSources.push(ds); } { PythInternalStructs.DataSource memory ds = PythInternalStructs .DataSource(governanceEmitterChainId, governanceEmitterAddress); PythSetters.setGovernanceDataSource(ds); PythSetters.setLastExecutedGovernanceSequence( governanceInitialSequence ); } PythSetters.setValidTimePeriodSeconds(validTimePeriodSeconds); PythSetters.setSingleUpdateFeeInWei(singleUpdateFeeInWei); } function updatePriceFeeds( bytes[] calldata updateData ) public payable override { uint totalNumUpdates = 0; for (uint i = 0; i < updateData.length; ) { totalNumUpdates += updatePriceInfosFromAccumulatorUpdate( updateData[i] ); unchecked { i++; } } uint requiredFee = getTotalFee(totalNumUpdates); if (msg.value < requiredFee) revert PythErrors.InsufficientFee(); } /// This method is deprecated, please use the `getUpdateFee(bytes[])` instead. function getUpdateFee( uint updateDataSize ) public view returns (uint feeAmount) { // In the accumulator update data a single update can contain // up to 255 messages and we charge a singleUpdateFee per each // message return 255 * singleUpdateFeeInWei() * updateDataSize; } function getUpdateFee( bytes[] calldata updateData ) public view override returns (uint feeAmount) { uint totalNumUpdates = 0; for (uint i = 0; i < updateData.length; i++) { if ( updateData[i].length > 4 && UnsafeCalldataBytesLib.toUint32(updateData[i], 0) == ACCUMULATOR_MAGIC ) { ( uint offset, UpdateType updateType ) = extractUpdateTypeFromAccumulatorHeader(updateData[i]); if (updateType != UpdateType.WormholeMerkle) { revert PythErrors.InvalidUpdateData(); } totalNumUpdates += parseWormholeMerkleHeaderNumUpdates( updateData[i], offset ); } else { revert PythErrors.InvalidUpdateData(); } } return getTotalFee(totalNumUpdates); } // This is an overwrite of the same method in AbstractPyth.sol // to be more gas efficient. function updatePriceFeedsIfNecessary( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes ) external payable override { if (priceIds.length != publishTimes.length) revert PythErrors.InvalidArgument(); for (uint i = 0; i < priceIds.length; ) { // If the price does not exist, then the publish time is zero and // this condition will work fine. if (latestPriceInfoPublishTime(priceIds[i]) < publishTimes[i]) { updatePriceFeeds(updateData); return; } unchecked { i++; } } revert PythErrors.NoFreshUpdate(); } // This is an overwrite of the same method in AbstractPyth.sol // to be more gas efficient. It cannot move to PythGetters as it // is overwriting the interface. Even indirect calling of a similar // method from PythGetter has some gas overhead. function getPriceUnsafe( bytes32 id ) public view override returns (PythStructs.Price memory price) { PythInternalStructs.PriceInfo storage info = _state.latestPriceInfo[id]; price.publishTime = info.publishTime; price.expo = info.expo; price.price = info.price; price.conf = info.conf; if (price.publishTime == 0) revert PythErrors.PriceFeedNotFound(); } // This is an overwrite of the same method in AbstractPyth.sol // to be more gas efficient. It cannot move to PythGetters as it // is overwriting the interface. Even indirect calling of a similar // method from PythGetter has some gas overhead. function getEmaPriceUnsafe( bytes32 id ) public view override returns (PythStructs.Price memory price) { PythInternalStructs.PriceInfo storage info = _state.latestPriceInfo[id]; price.publishTime = info.publishTime; price.expo = info.expo; price.price = info.emaPrice; price.conf = info.emaConf; if (price.publishTime == 0) revert PythErrors.PriceFeedNotFound(); } function parsePriceFeedUpdatesInternal( bytes[] calldata updateData, bytes32[] calldata priceIds, PythInternalStructs.ParseConfig memory config ) internal returns (PythStructs.PriceFeed[] memory priceFeeds) { { uint requiredFee = getUpdateFee(updateData); if (msg.value < requiredFee) revert PythErrors.InsufficientFee(); } unchecked { priceFeeds = new PythStructs.PriceFeed[](priceIds.length); for (uint i = 0; i < updateData.length; i++) { if ( updateData[i].length > 4 && UnsafeCalldataBytesLib.toUint32(updateData[i], 0) == ACCUMULATOR_MAGIC ) { uint offset; { UpdateType updateType; ( offset, updateType ) = extractUpdateTypeFromAccumulatorHeader( updateData[i] ); if (updateType != UpdateType.WormholeMerkle) { revert PythErrors.InvalidUpdateData(); } } bytes20 digest; uint8 numUpdates; bytes calldata encoded; ( offset, digest, numUpdates, encoded ) = extractWormholeMerkleHeaderDigestAndNumUpdatesAndEncodedFromAccumulatorUpdate( updateData[i], offset ); for (uint j = 0; j < numUpdates; j++) { PythInternalStructs.PriceInfo memory priceInfo; bytes32 priceId; uint64 prevPublishTime; ( offset, priceInfo, priceId, prevPublishTime ) = extractPriceInfoFromMerkleProof( digest, encoded, offset ); updateLatestPriceIfNecessary(priceId, priceInfo); { // check whether caller requested for this data uint k = findIndexOfPriceId(priceIds, priceId); // If priceFeed[k].id != 0 then it means that there was a valid // update for priceIds[k] and we don't need to process this one. if (k == priceIds.length || priceFeeds[k].id != 0) { continue; } uint publishTime = uint(priceInfo.publishTime); // Check the publish time of the price is within the given range // and only fill the priceFeedsInfo if it is. // If is not, default id value of 0 will still be set and // this will allow other updates for this price id to be processed. if ( publishTime >= config.minPublishTime && publishTime <= config.maxPublishTime && (!config.checkUniqueness || config.minPublishTime > prevPublishTime) ) { fillPriceFeedFromPriceInfo( priceFeeds, k, priceId, priceInfo, publishTime ); } } } if (offset != encoded.length) revert PythErrors.InvalidUpdateData(); } else { revert PythErrors.InvalidUpdateData(); } } for (uint k = 0; k < priceIds.length; k++) { if (priceFeeds[k].id == 0) { revert PythErrors.PriceFeedNotFoundWithinRange(); } } } } function parsePriceFeedUpdates( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64 minPublishTime, uint64 maxPublishTime ) external payable override returns (PythStructs.PriceFeed[] memory priceFeeds) { return parsePriceFeedUpdatesInternal( updateData, priceIds, PythInternalStructs.ParseConfig( minPublishTime, maxPublishTime, false ) ); } function parsePriceFeedUpdatesUnique( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64 minPublishTime, uint64 maxPublishTime ) external payable override returns (PythStructs.PriceFeed[] memory priceFeeds) { return parsePriceFeedUpdatesInternal( updateData, priceIds, PythInternalStructs.ParseConfig( minPublishTime, maxPublishTime, true ) ); } function getTotalFee( uint totalNumUpdates ) private view returns (uint requiredFee) { return totalNumUpdates * singleUpdateFeeInWei(); } function findIndexOfPriceId( bytes32[] calldata priceIds, bytes32 targetPriceId ) private pure returns (uint index) { uint k = 0; for (; k < priceIds.length; k++) { if (priceIds[k] == targetPriceId) { break; } } return k; } function fillPriceFeedFromPriceInfo( PythStructs.PriceFeed[] memory priceFeeds, uint k, bytes32 priceId, PythInternalStructs.PriceInfo memory info, uint publishTime ) private pure { priceFeeds[k].id = priceId; priceFeeds[k].price.price = info.price; priceFeeds[k].price.conf = info.conf; priceFeeds[k].price.expo = info.expo; priceFeeds[k].price.publishTime = publishTime; priceFeeds[k].emaPrice.price = info.emaPrice; priceFeeds[k].emaPrice.conf = info.emaConf; priceFeeds[k].emaPrice.expo = info.expo; priceFeeds[k].emaPrice.publishTime = publishTime; } function queryPriceFeed( bytes32 id ) public view override returns (PythStructs.PriceFeed memory priceFeed) { // Look up the latest price info for the given ID PythInternalStructs.PriceInfo memory info = latestPriceInfo(id); if (info.publishTime == 0) revert PythErrors.PriceFeedNotFound(); priceFeed.id = id; priceFeed.price.price = info.price; priceFeed.price.conf = info.conf; priceFeed.price.expo = info.expo; priceFeed.price.publishTime = uint(info.publishTime); priceFeed.emaPrice.price = info.emaPrice; priceFeed.emaPrice.conf = info.emaConf; priceFeed.emaPrice.expo = info.expo; priceFeed.emaPrice.publishTime = uint(info.publishTime); } function priceFeedExists(bytes32 id) public view override returns (bool) { return (latestPriceInfoPublishTime(id) != 0); } function getValidTimePeriod() public view override returns (uint) { return validTimePeriodSeconds(); } function version() public pure returns (string memory) { return "1.4.3"; } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "../libraries/external/UnsafeBytesLib.sol"; import "../libraries/external/UnsafeCalldataBytesLib.sol"; import "@pythnetwork/pyth-sdk-solidity/AbstractPyth.sol"; import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol"; import "./PythGetters.sol"; import "./PythSetters.sol"; import "./PythInternalStructs.sol"; import "../libraries/MerkleTree.sol"; abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth { uint32 constant ACCUMULATOR_MAGIC = 0x504e4155; // Stands for PNAU (Pyth Network Accumulator Update) uint32 constant ACCUMULATOR_WORMHOLE_MAGIC = 0x41555756; // Stands for AUWV (Accumulator Update Wormhole Verficiation) uint8 constant MINIMUM_ALLOWED_MINOR_VERSION = 0; uint8 constant MAJOR_VERSION = 1; enum UpdateType { WormholeMerkle } enum MessageType { PriceFeed } // This method is also used by batch attestation but moved here // as the batch attestation will deprecate soon. function parseAndVerifyPythVM( bytes calldata encodedVm ) internal view returns (IWormhole.VM memory vm) { { bool valid; (vm, valid, ) = wormhole().parseAndVerifyVM(encodedVm); if (!valid) revert PythErrors.InvalidWormholeVaa(); } if (!isValidDataSource(vm.emitterChainId, vm.emitterAddress)) revert PythErrors.InvalidUpdateDataSource(); } function extractUpdateTypeFromAccumulatorHeader( bytes calldata accumulatorUpdate ) internal pure returns (uint offset, UpdateType updateType) { unchecked { offset = 0; { uint32 magic = UnsafeCalldataBytesLib.toUint32( accumulatorUpdate, offset ); offset += 4; if (magic != ACCUMULATOR_MAGIC) revert PythErrors.InvalidUpdateData(); uint8 majorVersion = UnsafeCalldataBytesLib.toUint8( accumulatorUpdate, offset ); offset += 1; if (majorVersion != MAJOR_VERSION) revert PythErrors.InvalidUpdateData(); uint8 minorVersion = UnsafeCalldataBytesLib.toUint8( accumulatorUpdate, offset ); offset += 1; // Minor versions are forward compatible, so we only check // that the minor version is not less than the minimum allowed if (minorVersion < MINIMUM_ALLOWED_MINOR_VERSION) revert PythErrors.InvalidUpdateData(); // This field ensure that we can add headers in the future // without breaking the contract (future compatibility) uint8 trailingHeaderSize = UnsafeCalldataBytesLib.toUint8( accumulatorUpdate, offset ); offset += 1; // We use another offset for the trailing header and in the end add the // offset by trailingHeaderSize to skip the future headers. // // An example would be like this: // uint trailingHeaderOffset = offset // uint x = UnsafeBytesLib.ToUint8(accumulatorUpdate, trailingHeaderOffset) // trailingHeaderOffset += 1 offset += trailingHeaderSize; } updateType = UpdateType( UnsafeCalldataBytesLib.toUint8(accumulatorUpdate, offset) ); offset += 1; if (accumulatorUpdate.length < offset) revert PythErrors.InvalidUpdateData(); } } function extractWormholeMerkleHeaderDigestAndNumUpdatesAndEncodedFromAccumulatorUpdate( bytes calldata accumulatorUpdate, uint encodedOffset ) internal view returns ( uint offset, bytes20 digest, uint8 numUpdates, bytes calldata encoded ) { unchecked { encoded = UnsafeCalldataBytesLib.slice( accumulatorUpdate, encodedOffset, accumulatorUpdate.length - encodedOffset ); offset = 0; uint16 whProofSize = UnsafeCalldataBytesLib.toUint16( encoded, offset ); offset += 2; { bytes memory encodedPayload; { IWormhole.VM memory vm = parseAndVerifyPythVM( UnsafeCalldataBytesLib.slice( encoded, offset, whProofSize ) ); offset += whProofSize; // TODO: Do we need to emit an update for accumulator update? If so what should we emit? // emit AccumulatorUpdate(vm.chainId, vm.sequence); encodedPayload = vm.payload; } uint payloadOffset = 0; { uint32 magic = UnsafeBytesLib.toUint32( encodedPayload, payloadOffset ); payloadOffset += 4; if (magic != ACCUMULATOR_WORMHOLE_MAGIC) revert PythErrors.InvalidUpdateData(); UpdateType updateType = UpdateType( UnsafeBytesLib.toUint8(encodedPayload, payloadOffset) ); ++payloadOffset; if (updateType != UpdateType.WormholeMerkle) revert PythErrors.InvalidUpdateData(); // This field is not used // uint64 slot = UnsafeBytesLib.toUint64(encodedPayload, payloadoffset); payloadOffset += 8; // This field is not used // uint32 ringSize = UnsafeBytesLib.toUint32(encodedPayload, payloadoffset); payloadOffset += 4; digest = bytes20( UnsafeBytesLib.toAddress(encodedPayload, payloadOffset) ); payloadOffset += 20; // We don't check equality to enable future compatibility. if (payloadOffset > encodedPayload.length) revert PythErrors.InvalidUpdateData(); } } numUpdates = UnsafeCalldataBytesLib.toUint8(encoded, offset); offset += 1; } } function parseWormholeMerkleHeaderNumUpdates( bytes calldata wormholeMerkleUpdate, uint offset ) internal pure returns (uint8 numUpdates) { uint16 whProofSize = UnsafeCalldataBytesLib.toUint16( wormholeMerkleUpdate, offset ); offset += 2; offset += whProofSize; numUpdates = UnsafeCalldataBytesLib.toUint8( wormholeMerkleUpdate, offset ); } function extractPriceInfoFromMerkleProof( bytes20 digest, bytes calldata encoded, uint offset ) internal pure returns ( uint endOffset, PythInternalStructs.PriceInfo memory priceInfo, bytes32 priceId, uint64 prevPublishTime ) { unchecked { bytes calldata encodedMessage; uint16 messageSize = UnsafeCalldataBytesLib.toUint16( encoded, offset ); offset += 2; encodedMessage = UnsafeCalldataBytesLib.slice( encoded, offset, messageSize ); offset += messageSize; bool valid; (valid, endOffset) = MerkleTree.isProofValid( encoded, offset, digest, encodedMessage ); if (!valid) { revert PythErrors.InvalidUpdateData(); } MessageType messageType = MessageType( UnsafeCalldataBytesLib.toUint8(encodedMessage, 0) ); if (messageType == MessageType.PriceFeed) { (priceInfo, priceId, prevPublishTime) = parsePriceFeedMessage( encodedMessage, 1 ); } else { revert PythErrors.InvalidUpdateData(); } return (endOffset, priceInfo, priceId, prevPublishTime); } } function parsePriceFeedMessage( bytes calldata encodedPriceFeed, uint offset ) private pure returns ( PythInternalStructs.PriceInfo memory priceInfo, bytes32 priceId, uint64 prevPublishTime ) { unchecked { priceId = UnsafeCalldataBytesLib.toBytes32( encodedPriceFeed, offset ); offset += 32; priceInfo.price = int64( UnsafeCalldataBytesLib.toUint64(encodedPriceFeed, offset) ); offset += 8; priceInfo.conf = UnsafeCalldataBytesLib.toUint64( encodedPriceFeed, offset ); offset += 8; priceInfo.expo = int32( UnsafeCalldataBytesLib.toUint32(encodedPriceFeed, offset) ); offset += 4; // Publish time is i64 in some environments due to the standard in that // environment. This would not cause any problem because since the signed // integer is represented in two's complement, the value would be the same // in both cases (for a million year at least) priceInfo.publishTime = UnsafeCalldataBytesLib.toUint64( encodedPriceFeed, offset ); offset += 8; // We do not store this field because it is not used on the latest feed queries. prevPublishTime = UnsafeBytesLib.toUint64(encodedPriceFeed, offset); offset += 8; priceInfo.emaPrice = int64( UnsafeCalldataBytesLib.toUint64(encodedPriceFeed, offset) ); offset += 8; priceInfo.emaConf = UnsafeCalldataBytesLib.toUint64( encodedPriceFeed, offset ); offset += 8; if (offset > encodedPriceFeed.length) revert PythErrors.InvalidUpdateData(); } } function updatePriceInfosFromAccumulatorUpdate( bytes calldata accumulatorUpdate ) internal returns (uint8 numUpdates) { ( uint encodedOffset, UpdateType updateType ) = extractUpdateTypeFromAccumulatorHeader(accumulatorUpdate); if (updateType != UpdateType.WormholeMerkle) { revert PythErrors.InvalidUpdateData(); } uint offset; bytes20 digest; bytes calldata encoded; ( offset, digest, numUpdates, encoded ) = extractWormholeMerkleHeaderDigestAndNumUpdatesAndEncodedFromAccumulatorUpdate( accumulatorUpdate, encodedOffset ); unchecked { for (uint i = 0; i < numUpdates; i++) { PythInternalStructs.PriceInfo memory priceInfo; bytes32 priceId; uint64 prevPublishTime; ( offset, priceInfo, priceId, prevPublishTime ) = extractPriceInfoFromMerkleProof(digest, encoded, offset); updateLatestPriceIfNecessary(priceId, priceInfo); } } if (offset != encoded.length) revert PythErrors.InvalidUpdateData(); } }
// contracts/PythDeprecatedStructs.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; // This contract contains self contained structs of all our deprecated structs. // When deprecating the structs, make sure that there be no dependency to // the sdk as the sdk might change. // // By storing these structs, we keep deprecated fields definitions correctly. Then, // in the future, we can use them to cleanup their storage and redeem some gas back. contract PythDeprecatedStructs { // Structs related to the _deprecatedLatestPriceInfoV1 enum DeprecatedPriceStatusV1 { UNKNOWN, TRADING, HALTED, AUCTION } struct DeprecatedPriceFeedV1 { // The price ID. bytes32 id; // Product account key. bytes32 productId; // The current price. int64 price; // Confidence interval around the price. uint64 conf; // Price exponent. int32 expo; // Status of price. DeprecatedPriceStatusV1 status; // Maximum number of allowed publishers that can contribute to a price. uint32 maxNumPublishers; // Number of publishers that made up current aggregate. uint32 numPublishers; // Exponentially moving average price. int64 emaPrice; // Exponentially moving average confidence interval. uint64 emaConf; // Unix timestamp describing when the price was published uint64 publishTime; // Price of previous price with TRADING status int64 prevPrice; // Confidence interval of previous price with TRADING status uint64 prevConf; // Unix timestamp describing when the previous price with TRADING status was published uint64 prevPublishTime; } struct DeprecatedPriceInfoV1 { uint256 attestationTime; uint256 arrivalTime; uint256 arrivalBlock; DeprecatedPriceFeedV1 priceFeed; } // Structs related to the _deprecatedLatestPriceInfoV2 struct DeprecatedPriceV2 { // 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 DeprecatedPriceFeedV2 { // The price ID. bytes32 id; // Latest available price DeprecatedPriceV2 price; // Latest available exponentially-weighted moving average price DeprecatedPriceV2 emaPrice; } struct DeprecatedPriceInfoV2 { uint256 attestationTime; uint256 arrivalTime; uint256 arrivalBlock; DeprecatedPriceFeedV2 priceFeed; } }
// contracts/Getters.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "../wormhole/interfaces/IWormhole.sol"; import "./PythInternalStructs.sol"; import "./PythState.sol"; contract PythGetters is PythState { function wormhole() public view returns (IWormhole) { return IWormhole(_state.wormhole); } function latestPriceInfo( bytes32 priceId ) internal view returns (PythInternalStructs.PriceInfo memory info) { return _state.latestPriceInfo[priceId]; } function latestPriceInfoPublishTime( bytes32 priceId ) public view returns (uint64) { return _state.latestPriceInfo[priceId].publishTime; } function hashDataSource( PythInternalStructs.DataSource memory ds ) public pure returns (bytes32) { return keccak256(abi.encodePacked(ds.chainId, ds.emitterAddress)); } function isValidDataSource( uint16 dataSourceChainId, bytes32 dataSourceEmitterAddress ) public view returns (bool) { return _state.isValidDataSource[ keccak256( abi.encodePacked( dataSourceChainId, dataSourceEmitterAddress ) ) ]; } function isValidGovernanceDataSource( uint16 governanceChainId, bytes32 governanceEmitterAddress ) public view returns (bool) { return _state.governanceDataSource.chainId == governanceChainId && _state.governanceDataSource.emitterAddress == governanceEmitterAddress; } function chainId() public view returns (uint16) { return wormhole().chainId(); } function lastExecutedGovernanceSequence() public view returns (uint64) { return _state.lastExecutedGovernanceSequence; } function validDataSources() public view returns (PythInternalStructs.DataSource[] memory) { return _state.validDataSources; } function governanceDataSource() public view returns (PythInternalStructs.DataSource memory) { return _state.governanceDataSource; } function singleUpdateFeeInWei() public view returns (uint) { return _state.singleUpdateFeeInWei; } function validTimePeriodSeconds() public view returns (uint) { return _state.validTimePeriodSeconds; } function governanceDataSourceIndex() public view returns (uint32) { return _state.governanceDataSourceIndex; } }
// contracts/Governance.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "./PythGovernanceInstructions.sol"; import "./PythInternalStructs.sol"; import "./PythGetters.sol"; import "./PythSetters.sol"; import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; /** * @dev `Governance` defines a means to enacting changes to the Pyth contract. */ abstract contract PythGovernance is PythGetters, PythSetters, PythGovernanceInstructions { event ContractUpgraded( address oldImplementation, address newImplementation ); event GovernanceDataSourceSet( PythInternalStructs.DataSource oldDataSource, PythInternalStructs.DataSource newDataSource, uint64 initialSequence ); event DataSourcesSet( PythInternalStructs.DataSource[] oldDataSources, PythInternalStructs.DataSource[] newDataSources ); event FeeSet(uint oldFee, uint newFee); event ValidPeriodSet(uint oldValidPeriod, uint newValidPeriod); event WormholeAddressSet( address oldWormholeAddress, address newWormholeAddress ); function verifyGovernanceVM( bytes memory encodedVM ) internal returns (IWormhole.VM memory parsedVM) { (IWormhole.VM memory vm, bool valid, ) = wormhole().parseAndVerifyVM( encodedVM ); if (!valid) revert PythErrors.InvalidWormholeVaa(); if (!isValidGovernanceDataSource(vm.emitterChainId, vm.emitterAddress)) revert PythErrors.InvalidGovernanceDataSource(); if (vm.sequence <= lastExecutedGovernanceSequence()) revert PythErrors.OldGovernanceMessage(); setLastExecutedGovernanceSequence(vm.sequence); return vm; } function executeGovernanceInstruction(bytes calldata encodedVM) public { IWormhole.VM memory vm = verifyGovernanceVM(encodedVM); GovernanceInstruction memory gi = parseGovernanceInstruction( vm.payload ); if (gi.targetChainId != chainId() && gi.targetChainId != 0) revert PythErrors.InvalidGovernanceTarget(); if (gi.action == GovernanceAction.UpgradeContract) { if (gi.targetChainId == 0) revert PythErrors.InvalidGovernanceTarget(); upgradeContract(parseUpgradeContractPayload(gi.payload)); } else if ( gi.action == GovernanceAction.AuthorizeGovernanceDataSourceTransfer ) { AuthorizeGovernanceDataSourceTransfer( parseAuthorizeGovernanceDataSourceTransferPayload(gi.payload) ); } else if (gi.action == GovernanceAction.SetDataSources) { setDataSources(parseSetDataSourcesPayload(gi.payload)); } else if (gi.action == GovernanceAction.SetFee) { setFee(parseSetFeePayload(gi.payload)); } else if (gi.action == GovernanceAction.SetValidPeriod) { setValidPeriod(parseSetValidPeriodPayload(gi.payload)); } else if ( gi.action == GovernanceAction.RequestGovernanceDataSourceTransfer ) { // RequestGovernanceDataSourceTransfer can be only part of AuthorizeGovernanceDataSourceTransfer message revert PythErrors.InvalidGovernanceMessage(); } else if (gi.action == GovernanceAction.SetWormholeAddress) { if (gi.targetChainId == 0) revert PythErrors.InvalidGovernanceTarget(); setWormholeAddress( parseSetWormholeAddressPayload(gi.payload), encodedVM ); } else { revert PythErrors.InvalidGovernanceMessage(); } } function upgradeContract(UpgradeContractPayload memory payload) internal { // This method on this contract does not have enough access to execute this, it should be executed on the // upgradable contract. upgradeUpgradableContract(payload); } function upgradeUpgradableContract( UpgradeContractPayload memory payload ) internal virtual; // Transfer the governance data source to a new value with sanity checks // to ensure the new governance data source can manage the contract. function AuthorizeGovernanceDataSourceTransfer( AuthorizeGovernanceDataSourceTransferPayload memory payload ) internal { PythInternalStructs.DataSource memory oldGovernanceDatSource = governanceDataSource(); // Make sure the claimVaa is a valid VAA with RequestGovernanceDataSourceTransfer governance message // If it's valid then its emitter can take over the governance from the current emitter. // The VAA is checked here to ensure that the new governance data source is valid and can send message // through wormhole. (IWormhole.VM memory vm, bool valid, ) = wormhole().parseAndVerifyVM( payload.claimVaa ); if (!valid) revert PythErrors.InvalidWormholeVaa(); GovernanceInstruction memory gi = parseGovernanceInstruction( vm.payload ); if (gi.targetChainId != chainId() && gi.targetChainId != 0) revert PythErrors.InvalidGovernanceTarget(); if (gi.action != GovernanceAction.RequestGovernanceDataSourceTransfer) revert PythErrors.InvalidGovernanceMessage(); RequestGovernanceDataSourceTransferPayload memory claimPayload = parseRequestGovernanceDataSourceTransferPayload( gi.payload ); // Governance data source index is used to prevent replay attacks, so a claimVaa cannot be used twice. if ( governanceDataSourceIndex() >= claimPayload.governanceDataSourceIndex ) revert PythErrors.OldGovernanceMessage(); setGovernanceDataSourceIndex(claimPayload.governanceDataSourceIndex); PythInternalStructs.DataSource memory newGovernanceDS = PythInternalStructs.DataSource( vm.emitterChainId, vm.emitterAddress ); setGovernanceDataSource(newGovernanceDS); // Setting the last executed governance to the claimVaa sequence to avoid using older sequences. setLastExecutedGovernanceSequence(vm.sequence); emit GovernanceDataSourceSet( oldGovernanceDatSource, governanceDataSource(), lastExecutedGovernanceSequence() ); } function setDataSources(SetDataSourcesPayload memory payload) internal { PythInternalStructs.DataSource[] memory oldDataSources = validDataSources(); for (uint i = 0; i < oldDataSources.length; i += 1) { _state.isValidDataSource[hashDataSource(oldDataSources[i])] = false; } delete _state.validDataSources; for (uint i = 0; i < payload.dataSources.length; i++) { _state.validDataSources.push(payload.dataSources[i]); _state.isValidDataSource[ hashDataSource(payload.dataSources[i]) ] = true; } emit DataSourcesSet(oldDataSources, validDataSources()); } function setFee(SetFeePayload memory payload) internal { uint oldFee = singleUpdateFeeInWei(); setSingleUpdateFeeInWei(payload.newFee); emit FeeSet(oldFee, singleUpdateFeeInWei()); } function setValidPeriod(SetValidPeriodPayload memory payload) internal { uint oldValidPeriod = validTimePeriodSeconds(); setValidTimePeriodSeconds(payload.newValidPeriod); emit ValidPeriodSet(oldValidPeriod, validTimePeriodSeconds()); } function setWormholeAddress( SetWormholeAddressPayload memory payload, bytes memory encodedVM ) internal { address oldWormholeAddress = address(wormhole()); setWormhole(payload.newWormholeAddress); // We want to verify that the new wormhole address is valid, so we make sure that it can // parse and verify the same governance VAA that is used to set it. (IWormhole.VM memory vm, bool valid, ) = wormhole().parseAndVerifyVM( encodedVM ); if (!valid) revert PythErrors.InvalidGovernanceMessage(); if (!isValidGovernanceDataSource(vm.emitterChainId, vm.emitterAddress)) revert PythErrors.InvalidGovernanceMessage(); if (vm.sequence != lastExecutedGovernanceSequence()) revert PythErrors.InvalidWormholeAddressToSet(); GovernanceInstruction memory gi = parseGovernanceInstruction( vm.payload ); if (gi.action != GovernanceAction.SetWormholeAddress) revert PythErrors.InvalidWormholeAddressToSet(); // Purposefully, we don't check whether the chainId is the same as the current chainId because // we might want to change the chain id of the wormhole contract. // The following check is not necessary for security, but is a sanity check that the new wormhole // contract parses the payload correctly. SetWormholeAddressPayload memory newPayload = parseSetWormholeAddressPayload(gi.payload); if (newPayload.newWormholeAddress != payload.newWormholeAddress) revert PythErrors.InvalidWormholeAddressToSet(); emit WormholeAddressSet(oldWormholeAddress, address(wormhole())); } }
// contracts/GovernanceStructs.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "../libraries/external/BytesLib.sol"; import "./PythInternalStructs.sol"; import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol"; /** * @dev `PythGovernanceInstructions` defines a set of structs and parsing functions * for Pyth governance instructions. */ contract PythGovernanceInstructions { using BytesLib for bytes; // Magic is `PTGM` encoded as a 4 byte data: Pyth Governance Message uint32 constant MAGIC = 0x5054474d; enum GovernanceModule { Executor, // 0 Target, // 1 EvmExecutor, // 2 // The stacks target chain contract has custom governance instructions and needs its own module. StacksTarget // 3 } GovernanceModule constant MODULE = GovernanceModule.Target; enum GovernanceAction { UpgradeContract, // 0 AuthorizeGovernanceDataSourceTransfer, // 1 SetDataSources, // 2 SetFee, // 3 SetValidPeriod, // 4 RequestGovernanceDataSourceTransfer, // 5 SetWormholeAddress // 6 } struct GovernanceInstruction { GovernanceModule module; GovernanceAction action; uint16 targetChainId; bytes payload; } struct UpgradeContractPayload { address newImplementation; } struct AuthorizeGovernanceDataSourceTransferPayload { // Transfer governance control over this contract to another data source. // The claimVaa field is a VAA created by the new data source; using a VAA prevents mistakes // in the handoff by ensuring that the new data source can send VAAs (i.e., is not an invalid address). bytes claimVaa; } struct RequestGovernanceDataSourceTransferPayload { // Governance data source index is used to prevent replay attacks // So a claimVaa cannot be used twice. uint32 governanceDataSourceIndex; } struct SetDataSourcesPayload { PythInternalStructs.DataSource[] dataSources; } struct SetFeePayload { uint newFee; } struct SetValidPeriodPayload { uint newValidPeriod; } struct SetWormholeAddressPayload { address newWormholeAddress; } /// @dev Parse a GovernanceInstruction function parseGovernanceInstruction( bytes memory encodedInstruction ) public pure returns (GovernanceInstruction memory gi) { uint index = 0; uint32 magic = encodedInstruction.toUint32(index); if (magic != MAGIC) revert PythErrors.InvalidGovernanceMessage(); index += 4; uint8 modNumber = encodedInstruction.toUint8(index); gi.module = GovernanceModule(modNumber); index += 1; if (gi.module != MODULE) revert PythErrors.InvalidGovernanceTarget(); uint8 actionNumber = encodedInstruction.toUint8(index); gi.action = GovernanceAction(actionNumber); index += 1; gi.targetChainId = encodedInstruction.toUint16(index); index += 2; // As solidity performs math operations in a checked mode // if the length of the encoded instruction be smaller than index // it will revert. So we don't need any extra check. gi.payload = encodedInstruction.slice( index, encodedInstruction.length - index ); } /// @dev Parse a UpgradeContractPayload (action 1) with minimal validation function parseUpgradeContractPayload( bytes memory encodedPayload ) public pure returns (UpgradeContractPayload memory uc) { uint index = 0; uc.newImplementation = address(encodedPayload.toAddress(index)); index += 20; if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a AuthorizeGovernanceDataSourceTransferPayload (action 2) with minimal validation function parseAuthorizeGovernanceDataSourceTransferPayload( bytes memory encodedPayload ) public pure returns (AuthorizeGovernanceDataSourceTransferPayload memory sgds) { sgds.claimVaa = encodedPayload; } /// @dev Parse a AuthorizeGovernanceDataSourceTransferPayload (action 2) with minimal validation function parseRequestGovernanceDataSourceTransferPayload( bytes memory encodedPayload ) public pure returns (RequestGovernanceDataSourceTransferPayload memory sgdsClaim) { uint index = 0; sgdsClaim.governanceDataSourceIndex = encodedPayload.toUint32(index); index += 4; if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a SetDataSourcesPayload (action 3) with minimal validation function parseSetDataSourcesPayload( bytes memory encodedPayload ) public pure returns (SetDataSourcesPayload memory sds) { uint index = 0; uint8 dataSourcesLength = encodedPayload.toUint8(index); index += 1; sds.dataSources = new PythInternalStructs.DataSource[]( dataSourcesLength ); for (uint i = 0; i < dataSourcesLength; i++) { sds.dataSources[i].chainId = encodedPayload.toUint16(index); index += 2; sds.dataSources[i].emitterAddress = encodedPayload.toBytes32(index); index += 32; } if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a SetFeePayload (action 4) with minimal validation function parseSetFeePayload( bytes memory encodedPayload ) public pure returns (SetFeePayload memory sf) { uint index = 0; uint64 val = encodedPayload.toUint64(index); index += 8; uint64 expo = encodedPayload.toUint64(index); index += 8; sf.newFee = uint256(val) * uint256(10) ** uint256(expo); if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a SetValidPeriodPayload (action 5) with minimal validation function parseSetValidPeriodPayload( bytes memory encodedPayload ) public pure returns (SetValidPeriodPayload memory svp) { uint index = 0; svp.newValidPeriod = uint256(encodedPayload.toUint64(index)); index += 8; if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a UpdateWormholeAddressPayload (action 6) with minimal validation function parseSetWormholeAddressPayload( bytes memory encodedPayload ) public pure returns (SetWormholeAddressPayload memory sw) { uint index = 0; sw.newWormholeAddress = address(encodedPayload.toAddress(index)); index += 20; if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } }
// contracts/Structs.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "../libraries/external/BytesLib.sol"; import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; contract PythInternalStructs { using BytesLib for bytes; struct ParseConfig { uint64 minPublishTime; uint64 maxPublishTime; bool checkUniqueness; } struct PriceInfo { // slot 1 uint64 publishTime; int32 expo; int64 price; uint64 conf; // slot 2 int64 emaPrice; uint64 emaConf; } struct DataSource { uint16 chainId; bytes32 emitterAddress; } }
// contracts/Setters.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "./PythState.sol"; import "@pythnetwork/pyth-sdk-solidity/IPythEvents.sol"; contract PythSetters is PythState, IPythEvents { function setWormhole(address wh) internal { _state.wormhole = payable(wh); } function updateLatestPriceIfNecessary( bytes32 priceId, PythInternalStructs.PriceInfo memory info ) internal { uint64 latestPublishTime = _state.latestPriceInfo[priceId].publishTime; if (info.publishTime > latestPublishTime) { _state.latestPriceInfo[priceId] = info; emit PriceFeedUpdate( priceId, info.publishTime, info.price, info.conf ); } } function setSingleUpdateFeeInWei(uint fee) internal { _state.singleUpdateFeeInWei = fee; } function setValidTimePeriodSeconds(uint validTimePeriodSeconds) internal { _state.validTimePeriodSeconds = validTimePeriodSeconds; } function setGovernanceDataSource( PythInternalStructs.DataSource memory newDataSource ) internal { _state.governanceDataSource = newDataSource; } function setLastExecutedGovernanceSequence(uint64 sequence) internal { _state.lastExecutedGovernanceSequence = sequence; } function setGovernanceDataSourceIndex(uint32 newIndex) internal { _state.governanceDataSourceIndex = newIndex; } }
// contracts/State.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "./PythInternalStructs.sol"; import "./PythDeprecatedStructs.sol"; contract PythStorage { struct State { address wormhole; uint16 _deprecatedPyth2WormholeChainId; // Replaced by validDataSources/isValidDataSource bytes32 _deprecatedPyth2WormholeEmitter; // Ditto // After a backward-incompatible change in PriceFeed this mapping got deprecated. mapping(bytes32 => PythDeprecatedStructs.DeprecatedPriceInfoV1) _deprecatedLatestPriceInfoV1; // For tracking all active emitter/chain ID pairs PythInternalStructs.DataSource[] validDataSources; // (chainId, emitterAddress) => isValid; takes advantage of // constant-time mapping lookup for VM verification mapping(bytes32 => bool) isValidDataSource; uint singleUpdateFeeInWei; /// Maximum acceptable time period before price is considered to be stale. /// This includes attestation delay, block time, and potential clock drift /// between the source/target chains. uint validTimePeriodSeconds; // Governance data source. VAA messages from this source can change this contract // state. e.g., upgrade the contract, change the valid data sources, and more. PythInternalStructs.DataSource governanceDataSource; // Sequence number of the last executed governance message. Any governance message // with a lower or equal sequence number will be discarded. This prevents double-execution, // and also makes sure that messages are executed in the right order. uint64 lastExecutedGovernanceSequence; // After a backward-incompatible change in PriceFeed this mapping got deprecated. mapping(bytes32 => PythDeprecatedStructs.DeprecatedPriceInfoV2) _deprecatedLatestPriceInfoV2; // Index of the governance data source, increased each time the governance data source // changes. uint32 governanceDataSourceIndex; // Mapping of cached price information // priceId => PriceInfo mapping(bytes32 => PythInternalStructs.PriceInfo) latestPriceInfo; } } contract PythState { PythStorage.State _state; }
// contracts/Messages.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "../Structs.sol"; interface IWormhole is Structs { event LogMessagePublished( address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel ); function publishMessage( uint32 nonce, bytes memory payload, uint8 consistencyLevel ) external payable returns (uint64 sequence); function parseAndVerifyVM( bytes calldata encodedVM ) external view returns (Structs.VM memory vm, bool valid, string memory reason); function verifyVM( Structs.VM memory vm ) external view returns (bool valid, string memory reason); function verifySignatures( bytes32 hash, Structs.Signature[] memory signatures, Structs.GuardianSet memory guardianSet ) external pure returns (bool valid, string memory reason); function parseVM( bytes memory encodedVM ) external pure returns (Structs.VM memory vm); function getGuardianSet( uint32 index ) external view returns (Structs.GuardianSet memory); function getCurrentGuardianSetIndex() external view returns (uint32); function getGuardianSetExpiry() external view returns (uint32); function governanceActionIsConsumed( bytes32 hash ) external view returns (bool); function isInitialized(address impl) external view returns (bool); function chainId() external view returns (uint16); function governanceChainId() external view returns (uint16); function governanceContract() external view returns (bytes32); function messageFee() external view returns (uint256); }
// contracts/Structs.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; interface Structs { struct Provider { uint16 chainId; uint16 governanceChainId; bytes32 governanceContract; } struct GuardianSet { address[] keys; uint32 expirationTime; } struct Signature { bytes32 r; bytes32 s; uint8 v; uint8 guardianIndex; } struct VM { uint8 version; uint32 timestamp; uint32 nonce; uint16 emitterChainId; bytes32 emitterAddress; uint64 sequence; uint8 consistencyLevel; bytes payload; uint32 guardianSetIndex; Signature[] signatures; bytes32 hash; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InsufficientFee","type":"error"},{"inputs":[],"name":"InvalidArgument","type":"error"},{"inputs":[],"name":"InvalidGovernanceDataSource","type":"error"},{"inputs":[],"name":"InvalidGovernanceMessage","type":"error"},{"inputs":[],"name":"InvalidGovernanceTarget","type":"error"},{"inputs":[],"name":"InvalidUpdateData","type":"error"},{"inputs":[],"name":"InvalidUpdateDataSource","type":"error"},{"inputs":[],"name":"InvalidWormholeAddressToSet","type":"error"},{"inputs":[],"name":"InvalidWormholeVaa","type":"error"},{"inputs":[],"name":"NoFreshUpdate","type":"error"},{"inputs":[],"name":"OldGovernanceMessage","type":"error"},{"inputs":[],"name":"PriceFeedNotFound","type":"error"},{"inputs":[],"name":"PriceFeedNotFoundWithinRange","type":"error"},{"inputs":[],"name":"StalePrice","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"}],"name":"ContractUpgraded","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"}],"indexed":false,"internalType":"struct PythInternalStructs.DataSource[]","name":"oldDataSources","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"}],"indexed":false,"internalType":"struct PythInternalStructs.DataSource[]","name":"newDataSources","type":"tuple[]"}],"name":"DataSourcesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"FeeSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"}],"indexed":false,"internalType":"struct PythInternalStructs.DataSource","name":"oldDataSource","type":"tuple"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"}],"indexed":false,"internalType":"struct PythInternalStructs.DataSource","name":"newDataSource","type":"tuple"},{"indexed":false,"internalType":"uint64","name":"initialSequence","type":"uint64"}],"name":"GovernanceDataSourceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"publishTime","type":"uint64"},{"indexed":false,"internalType":"int64","name":"price","type":"int64"},{"indexed":false,"internalType":"uint64","name":"conf","type":"uint64"}],"name":"PriceFeedUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldValidPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValidPeriod","type":"uint256"}],"name":"ValidPeriodSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldWormholeAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newWormholeAddress","type":"address"}],"name":"WormholeAddressSet","type":"event"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedVM","type":"bytes"}],"name":"executeGovernanceInstruction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"getEmaPrice","outputs":[{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"uint256","name":"age","type":"uint256"}],"name":"getEmaPriceNoOlderThan","outputs":[{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"getEmaPriceUnsafe","outputs":[{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"getPrice","outputs":[{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"uint256","name":"age","type":"uint256"}],"name":"getPriceNoOlderThan","outputs":[{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"getPriceUnsafe","outputs":[{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"updateData","type":"bytes[]"}],"name":"getUpdateFee","outputs":[{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"updateDataSize","type":"uint256"}],"name":"getUpdateFee","outputs":[{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidTimePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governanceDataSource","outputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"}],"internalType":"struct PythInternalStructs.DataSource","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governanceDataSourceIndex","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"}],"internalType":"struct PythInternalStructs.DataSource","name":"ds","type":"tuple"}],"name":"hashDataSource","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"wormhole","type":"address"},{"internalType":"uint16[]","name":"dataSourceEmitterChainIds","type":"uint16[]"},{"internalType":"bytes32[]","name":"dataSourceEmitterAddresses","type":"bytes32[]"},{"internalType":"uint16","name":"governanceEmitterChainId","type":"uint16"},{"internalType":"bytes32","name":"governanceEmitterAddress","type":"bytes32"},{"internalType":"uint64","name":"governanceInitialSequence","type":"uint64"},{"internalType":"uint256","name":"validTimePeriodSeconds","type":"uint256"},{"internalType":"uint256","name":"singleUpdateFeeInWei","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"dataSourceChainId","type":"uint16"},{"internalType":"bytes32","name":"dataSourceEmitterAddress","type":"bytes32"}],"name":"isValidDataSource","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"governanceChainId","type":"uint16"},{"internalType":"bytes32","name":"governanceEmitterAddress","type":"bytes32"}],"name":"isValidGovernanceDataSource","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastExecutedGovernanceSequence","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"priceId","type":"bytes32"}],"name":"latestPriceInfoPublishTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPayload","type":"bytes"}],"name":"parseAuthorizeGovernanceDataSourceTransferPayload","outputs":[{"components":[{"internalType":"bytes","name":"claimVaa","type":"bytes"}],"internalType":"struct PythGovernanceInstructions.AuthorizeGovernanceDataSourceTransferPayload","name":"sgds","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedInstruction","type":"bytes"}],"name":"parseGovernanceInstruction","outputs":[{"components":[{"internalType":"enum PythGovernanceInstructions.GovernanceModule","name":"module","type":"uint8"},{"internalType":"enum PythGovernanceInstructions.GovernanceAction","name":"action","type":"uint8"},{"internalType":"uint16","name":"targetChainId","type":"uint16"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PythGovernanceInstructions.GovernanceInstruction","name":"gi","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"updateData","type":"bytes[]"},{"internalType":"bytes32[]","name":"priceIds","type":"bytes32[]"},{"internalType":"uint64","name":"minPublishTime","type":"uint64"},{"internalType":"uint64","name":"maxPublishTime","type":"uint64"}],"name":"parsePriceFeedUpdates","outputs":[{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"},{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"emaPrice","type":"tuple"}],"internalType":"struct PythStructs.PriceFeed[]","name":"priceFeeds","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"updateData","type":"bytes[]"},{"internalType":"bytes32[]","name":"priceIds","type":"bytes32[]"},{"internalType":"uint64","name":"minPublishTime","type":"uint64"},{"internalType":"uint64","name":"maxPublishTime","type":"uint64"}],"name":"parsePriceFeedUpdatesUnique","outputs":[{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"},{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"emaPrice","type":"tuple"}],"internalType":"struct PythStructs.PriceFeed[]","name":"priceFeeds","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPayload","type":"bytes"}],"name":"parseRequestGovernanceDataSourceTransferPayload","outputs":[{"components":[{"internalType":"uint32","name":"governanceDataSourceIndex","type":"uint32"}],"internalType":"struct PythGovernanceInstructions.RequestGovernanceDataSourceTransferPayload","name":"sgdsClaim","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPayload","type":"bytes"}],"name":"parseSetDataSourcesPayload","outputs":[{"components":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"}],"internalType":"struct PythInternalStructs.DataSource[]","name":"dataSources","type":"tuple[]"}],"internalType":"struct PythGovernanceInstructions.SetDataSourcesPayload","name":"sds","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPayload","type":"bytes"}],"name":"parseSetFeePayload","outputs":[{"components":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"internalType":"struct PythGovernanceInstructions.SetFeePayload","name":"sf","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPayload","type":"bytes"}],"name":"parseSetValidPeriodPayload","outputs":[{"components":[{"internalType":"uint256","name":"newValidPeriod","type":"uint256"}],"internalType":"struct PythGovernanceInstructions.SetValidPeriodPayload","name":"svp","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPayload","type":"bytes"}],"name":"parseSetWormholeAddressPayload","outputs":[{"components":[{"internalType":"address","name":"newWormholeAddress","type":"address"}],"internalType":"struct PythGovernanceInstructions.SetWormholeAddressPayload","name":"sw","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPayload","type":"bytes"}],"name":"parseUpgradeContractPayload","outputs":[{"components":[{"internalType":"address","name":"newImplementation","type":"address"}],"internalType":"struct PythGovernanceInstructions.UpgradeContractPayload","name":"uc","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"priceFeedExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pythUpgradableMagic","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"queryPriceFeed","outputs":[{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"price","type":"tuple"},{"components":[{"internalType":"int64","name":"price","type":"int64"},{"internalType":"uint64","name":"conf","type":"uint64"},{"internalType":"int32","name":"expo","type":"int32"},{"internalType":"uint256","name":"publishTime","type":"uint256"}],"internalType":"struct PythStructs.Price","name":"emaPrice","type":"tuple"}],"internalType":"struct PythStructs.PriceFeed","name":"priceFeed","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"singleUpdateFeeInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"updateData","type":"bytes[]"}],"name":"updatePriceFeeds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"updateData","type":"bytes[]"},{"internalType":"bytes32[]","name":"priceIds","type":"bytes32[]"},{"internalType":"uint64[]","name":"publishTimes","type":"uint64[]"}],"name":"updatePriceFeedsIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"validDataSources","outputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"}],"internalType":"struct PythInternalStructs.DataSource[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validTimePeriodSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"wormhole","outputs":[{"internalType":"contract IWormhole","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a06040523060601b6080523480156200001857600080fd5b50600054610100900460ff16158080156200003a5750600054600160ff909116105b806200006a575062000057306200014460201b62001ccf1760201c565b1580156200006a575060005460ff166001145b620000d25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b6000805460ff191660011790558015620000f6576000805461ff0019166101001790555b80156200013d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5062000153565b6001600160a01b03163b151590565b60805160601c6150586200018e60003960008181610a9201528181610ad201528181610cac01528181610cec0152610d6801526150586000f3fe6080604052600436106102725760003560e01c80638881016f1161014f578063b5ec0261116100c1578063d82d58a51161007a578063d82d58a514610819578063e17efd4814610852578063e18910a314610872578063e3795cc114610887578063ef9e5e281461089e578063f2fde38b146108b157600080fd5b8063b5ec02611461074c578063b6ed701e14610784578063b9256d28146107a4578063caaf43f1146107b7578063cb718a9b146107e4578063d47eed45146107f957600080fd5b80639a8a0592116101135780639a8a0592146106af578063a38d81c6146106d7578063a4ae35e0146106f9578063aac41292146105f9578063accca7f914610719578063b5dcc9111461072c57600080fd5b80638881016f146105f957806389a5bb4d146106315780638da5cb5b146106515780639474f45b1461066f57806396834ad31461068f57600080fd5b806352d1902d116101e85780636c72f51b116101ac5780636c72f51b14610504578063711a2e2814610530578063715018a6146105505780637b72bcae1461056557806384acd1bb1461059a57806387c5bd1b146105cc57600080fd5b806352d1902d1461045057806354fd4d5014610465578063586d3cf81461049957806358c67635146104b75780636b7f53ca146104d757600080fd5b8063437209a71161023a578063437209a7146103605780634716e9c51461039057806348b6404d146103b05780634c469d8c146103cf5780634d7a734e1461041d5780634f1ef2861461043d57600080fd5b8063146faf771461027757806314dd317f1461029957806331d98b3f146102cd5780633659cfe6146102fa578063426234e41461031a575b600080fd5b34801561028357600080fd5b50610297610292366004614351565b6108d1565b005b3480156102a557600080fd5b506102b96102b436600461467e565b610a13565b604051905181526020015b60405180910390f35b3480156102d957600080fd5b506102ed6102e83660046145c1565b610a6d565b6040516102c49190614c91565b34801561030657600080fd5b50610297610315366004614337565b610a87565b34801561032657600080fd5b506040805180820182526000808252602091820152815180830190925260d05461ffff16825260d154908201526040516102c49190614c06565b34801561036c57600080fd5b5061038061037b36600461488f565b610b6d565b60405190151581526020016102c4565b6103a361039e366004614530565b610bc0565b6040516102c49190614a77565b3480156103bc57600080fd5b5060ce545b6040519081526020016102c4565b3480156103db57600080fd5b506104056103ea3660046145c1565b600090815260d560205260409020546001600160401b031690565b6040516001600160401b0390911681526020016102c4565b34801561042957600080fd5b506102b961043836600461467e565b610c09565b61029761044b366004614411565b610ca1565b34801561045c57600080fd5b506103c1610d5b565b34801561047157600080fd5b506040805180820182526005815264312e342e3360d81b602082015290516102c49190614af5565b3480156104a557600080fd5b5060d2546001600160401b0316610405565b3480156104c357600080fd5b506103806104d236600461488f565b610e0e565b3480156104e357600080fd5b506104f76104f236600461467e565b610e31565b6040516102c49190614c21565b34801561051057600080fd5b5060d45463ffffffff165b60405163ffffffff90911681526020016102c4565b34801561053c57600080fd5b506102ed61054b3660046145f1565b611035565b34801561055c57600080fd5b50610297611076565b34801561057157600080fd5b5061058561058036600461467e565b61108a565b604051905163ffffffff1681526020016102c4565b3480156105a657600080fd5b5060c9546001600160a01b03165b6040516001600160a01b0390911681526020016102c4565b3480156105d857600080fd5b506105ec6105e736600461467e565b6110b8565b6040516102c49190614ccb565b34801561060557600080fd5b5061061961061436600461467e565b611234565b60405190516001600160a01b031681526020016102c4565b34801561063d57600080fd5b506103c161064c3660046146b0565b611265565b34801561065d57600080fd5b506033546001600160a01b03166105b4565b34801561067b57600080fd5b506102ed61068a3660046145c1565b6112b7565b34801561069b57600080fd5b506102ed6106aa3660046145c1565b611338565b3480156106bb57600080fd5b506106c46113bd565b60405161ffff90911681526020016102c4565b3480156106e357600080fd5b506106ec611446565b6040516102c49190614a3f565b34801561070557600080fd5b506102ed6107143660046145f1565b6114b9565b6103a3610727366004614530565b6114ca565b34801561073857600080fd5b506102ed6107473660046145c1565b611508565b34801561075857600080fd5b506103806107673660046145c1565b600090815260d560205260409020546001600160401b0316151590565b34801561079057600080fd5b5061029761079f366004614612565b61151c565b6102976107b236600461449b565b611836565b3480156107c357600080fd5b506107d76107d23660046145c1565b61192d565b6040516102c49190614c82565b3480156107f057600080fd5b5060cf546103c1565b34801561080557600080fd5b506103c161081436600461445c565b6119fb565b34801561082557600080fd5b5061084561083436600461467e565b604080516020810190915290815290565b6040516102c49190614beb565b34801561085e57600080fd5b506103c161086d3660046145c1565b611ba2565b34801561087e57600080fd5b506103c1611bc3565b34801561089357600080fd5b506397a6f30461051b565b6102976108ac36600461445c565b611bce565b3480156108bd57600080fd5b506102976108cc366004614337565b611c59565b600054610100900460ff16158080156108f15750600054600160ff909116105b8061090b5750303b15801561090b575060005460ff166001145b6109735760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610996576000805461ff0019166101001790555b61099e611cde565b6109a6611d0d565b6109b88b8b8b8b8b8b8b8b8b8b611d34565b6109c0611076565b8015610a06576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050505050565b6040805160208101909152600081526000610a2e8382611f1c565b6001600160401b03168252610a44600882614df4565b905080835114610a67576040516397363b3560e01b815260040160405180910390fd5b50919050565b610a7561400d565b610a8182610714611bc3565b92915050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415610ad05760405162461bcd60e51b815260040161096a90614b08565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610b02611f79565b6001600160a01b031614610b285760405162461bcd60e51b815260040161096a90614b54565b610b3181611f95565b610b6a8160005b6040519080825280601f01601f191660200182016040528015610b62576020820181803683370190505b506000611f9d565b50565b6040805160f09390931b6001600160f01b0319166020808501919091526022808501939093528151808503909301835260429093018152815191830191909120600090815260cd90925290205460ff1690565b6060610bfe878787876040518060600160405280896001600160401b03168152602001886001600160401b031681526020016000151581525061211c565b979650505050505050565b604080516020810190915260008152600080610c258482611f1c565b9050610c32600883614df4565b91506000610c408584611f1c565b9050610c4d600884614df4565b9250610c636001600160401b038216600a614e4f565b610c76906001600160401b038416614ef7565b845284518314610c99576040516397363b3560e01b815260040160405180910390fd5b505050919050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415610cea5760405162461bcd60e51b815260040161096a90614b08565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610d1c611f79565b6001600160a01b031614610d425760405162461bcd60e51b815260040161096a90614b54565b610d4b82611f95565b610d5782826001611f9d565b5050565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610dfb5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840161096a565b50600080516020614fdc83398151915290565b60d05460009061ffff8481169116148015610e2a575060d15482145b9392505050565b610e5d604080516080810190915280600081526020016000815260006020820152606060409091015290565b600080610e6a8482612477565b905063ffffffff8116635054474d14610e96576040516397363b3560e01b815260040160405180910390fd5b610ea1600483614df4565b91506000610eaf85846124d4565b90508060ff166003811115610ed457634e487b7160e01b600052602160045260246000fd5b84906003811115610ef557634e487b7160e01b600052602160045260246000fd5b90816003811115610f1657634e487b7160e01b600052602160045260246000fd5b905250610f24600184614df4565b9250600184516003811115610f4957634e487b7160e01b600052602160045260246000fd5b14610f67576040516363daeb7760e01b815260040160405180910390fd5b6000610f7386856124d4565b90508060ff166006811115610f9857634e487b7160e01b600052602160045260246000fd5b85602001906006811115610fbc57634e487b7160e01b600052602160045260246000fd5b90816006811115610fdd57634e487b7160e01b600052602160045260246000fd5b905250610feb600185614df4565b9350610ff78685612530565b61ffff16604086015261100b600285614df4565b93506110268485885161101e9190614f16565b88919061258d565b60608601525092949350505050565b61103d61400d565b611046836112b7565b90508161105742836060015161269a565b1115610a8157604051630cd5fa0760e11b815260040160405180910390fd5b61107e6126bf565b6110886000612719565b565b60408051602081019091526000815260006110a58382612477565b63ffffffff168252610a44600482614df4565b6040805160208101909152606081526000806110d484826124d4565b90506110e1600183614df4565b91508060ff166001600160401b0381111561110c57634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561115157816020015b604080518082019091526000808252602082015281526020019060019003908161112a5790505b50835260005b8160ff1681101561120b5761116c8584612530565b845180518390811061118e57634e487b7160e01b600052603260045260246000fd5b602090810291909101015161ffff90911690526111ac600284614df4565b92506111b8858461276b565b84518051839081106111da57634e487b7160e01b600052603260045260246000fd5b602002602001015160200181815250506020836111f79190614df4565b92508061120381614f59565b915050611157565b508184511461122d576040516397363b3560e01b815260040160405180910390fd5b5050919050565b604080516020810190915260008152600061124f83826127c9565b6001600160a01b03168252610a44601482614df4565b60008160000151826020015160405160200161129a92919060f09290921b6001600160f01b0319168252600282015260220190565b604051602081830303815290604052805190602001209050919050565b6112bf61400d565b600082815260d5602090815260409182902080546001600160401b0380821660608701819052600160401b92839004600390810b810b900b958701959095526001830154600781810b810b900b875291909104169184019190915290610a6757604051630295d7cd60e31b815260040160405180910390fd5b61134061400d565b600082815260d5602090815260409182902080546001600160401b0380821660608701819052600160401b8304600390810b810b900b95870195909552600160601b8204600790810b810b900b8652600160a01b909104169184019190915290610a6757604051630295d7cd60e31b815260040160405180910390fd5b60006113d160c9546001600160a01b031690565b6001600160a01b0316639a8a05926040518163ffffffff1660e01b815260040160206040518083038186803b15801561140957600080fd5b505afa15801561141d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114419190614873565b905090565b606060c9600301805480602002602001604051908101604052809291908181526020016000905b828210156114b05760008481526020908190206040805180820190915260028502909101805461ffff16825260019081015482840152908352909201910161146d565b50505050905090565b6114c161400d565b61104683611338565b6060610bfe878787876040518060600160405280896001600160401b03168152602001886001600160401b031681526020016001151581525061211c565b61151061400d565b610a818261054b611bc3565b600061155d83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061282e92505050565b9050600061156e8260e00151610e31565b90506115786113bd565b61ffff16816040015161ffff161415801561159a5750604081015161ffff1615155b156115b8576040516363daeb7760e01b815260040160405180910390fd5b6000816020015160068111156115de57634e487b7160e01b600052602160045260246000fd5b141561162457604081015161ffff1661160a576040516363daeb7760e01b815260040160405180910390fd5b61161f61161a8260600151611234565b612971565b611830565b60018160200151600681111561164a57634e487b7160e01b600052602160045260246000fd5b14156116715761161f61166c8260600151604080516020810190915290815290565b61297a565b60028160200151600681111561169757634e487b7160e01b600052602160045260246000fd5b14156116b25761161f6116ad82606001516110b8565b612c56565b6003816020015160068111156116d857634e487b7160e01b600052602160045260246000fd5b14156116f35761161f6116ee8260600151610c09565b612dff565b60048160200151600681111561171957634e487b7160e01b600052602160045260246000fd5b14156117345761161f61172f8260600151610a13565b612e51565b60058160200151600681111561175a57634e487b7160e01b600052602160045260246000fd5b1415611779576040516397363b3560e01b815260040160405180910390fd5b60068160200151600681111561179f57634e487b7160e01b600052602160045260246000fd5b141561181757604081015161ffff166117cb576040516363daeb7760e01b815260040160405180910390fd5b61161f6117db8260600151611234565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612e8e92505050565b6040516397363b3560e01b815260040160405180910390fd5b50505050565b8281146118565760405163a9cb9e0d60e01b815260040160405180910390fd5b60005b8381101561190b5782828281811061188157634e487b7160e01b600052603260045260246000fd5b905060200201602081019061189691906148d4565b6001600160401b03166118e48686848181106118c257634e487b7160e01b600052603260045260246000fd5b90506020020135600090815260d560205260409020546001600160401b031690565b6001600160401b03161015611903576118fd8787611bce565b50611925565b600101611859565b50604051636f162bfd60e11b815260040160405180910390fd5b505050505050565b611935614034565b6000611940836130c2565b80519091506001600160401b031661196b57604051630295d7cd60e31b815260040160405180910390fd5b91815260408083015160208084018051600793840b840b905260608087015182516001600160401b039182169085015283880180518451600391820b820b9089015289519451948316948401949094526080890151878901805191880b90970b905260a089015186519083169501949094529251845190830b90920b919094015293519051931692019190915290565b600080805b83811015611b90576004858583818110611a2a57634e487b7160e01b600052603260045260246000fd5b9050602002810190611a3c9190614ce6565b9050118015611a90575063504e4155611a88868684818110611a6e57634e487b7160e01b600052603260045260246000fd5b9050602002810190611a809190614ce6565b503560e01c90565b63ffffffff16145b15611b6557600080611ad2878785818110611abb57634e487b7160e01b600052603260045260246000fd5b9050602002810190611acd9190614ce6565b613154565b90925090506000818015611af657634e487b7160e01b600052602160045260246000fd5b14611b145760405163734fff6760e11b815260040160405180910390fd5b611b4f878785818110611b3757634e487b7160e01b600052603260045260246000fd5b9050602002810190611b499190614ce6565b8461321b565b611b5c9060ff1685614df4565b93505050611b7e565b60405163734fff6760e11b815260040160405180910390fd5b80611b8881614f59565b915050611a00565b50611b9a81613252565b949350505050565b600081611bae60ce5490565b611bb99060ff614ef7565b610a819190614ef7565b600061144160cf5490565b6000805b82811015611c2b57611c14848483818110611bfd57634e487b7160e01b600052603260045260246000fd5b9050602002810190611c0f9190614ce6565b613267565b611c219060ff1683614df4565b9150600101611bd2565b506000611c3782613252565b9050803410156118305760405162976f7560e21b815260040160405180910390fd5b611c616126bf565b6001600160a01b038116611cc65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161096a565b610b6a81612719565b6001600160a01b03163b151590565b600054610100900460ff16611d055760405162461bcd60e51b815260040161096a90614ba0565b611088613348565b600054610100900460ff166110885760405162461bcd60e51b815260040161096a90614ba0565b611d3d8a613378565b878614611d5d5760405163a9cb9e0d60e01b815260040160405180910390fd5b60005b88811015611ec757600060405180604001604052808c8c85818110611d9557634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611daa9190614857565b61ffff1681526020018a8a85818110611dd357634e487b7160e01b600052603260045260246000fd5b905060200201358152509050611df181600001518260200151610b6d565b15611e0f5760405163a9cb9e0d60e01b815260040160405180910390fd5b600160cd6000611e1e84611265565b81526020808201929092526040016000908120805460ff19169315159390931790925560cc8054600181018255925282517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebe6002909302928301805461ffff191661ffff90921691909117905591909101517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebf9091015580611ebf81614f59565b915050611d60565b506040805180820190915261ffff86168082526020820186905260d0805461ffff1916909117905560d1859055611efd8461339a565b50611f078260cf55565b611f108160ce55565b50505050505050505050565b6000611f29826008614df4565b83511015611f705760405162461bcd60e51b8152602060048201526014602482015273746f55696e7436345f6f75744f66426f756e647360601b604482015260640161096a565b50016008015190565b600080516020614fdc833981519152546001600160a01b031690565b610b6a6126bf565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611fd557611fd0836133bd565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561200e57600080fd5b505afa92505050801561203e575060408051601f3d908101601f1916820190925261203b918101906145d9565b60015b6120a15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840161096a565b600080516020614fdc83398151915281146121105760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840161096a565b50611fd0838383613459565b6060600061212a87876119fb565b90508034101561214c5760405162976f7560e21b815260040160405180910390fd5b50826001600160401b0381111561217357634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156121ac57816020015b612199614034565b8152602001906001900390816121915790505b50905060005b858110156124105760048787838181106121dc57634e487b7160e01b600052603260045260246000fd5b90506020028101906121ee9190614ce6565b9050118015612228575063504e4155612220888884818110611a6e57634e487b7160e01b600052603260045260246000fd5b63ffffffff16145b15611b6557600080612253898985818110611abb57634e487b7160e01b600052603260045260246000fd5b9092509050600081801561227757634e487b7160e01b600052602160045260246000fd5b146122955760405163734fff6760e11b815260040160405180910390fd5b506000803660006122d78c8c888181106122bf57634e487b7160e01b600052603260045260246000fd5b90506020028101906122d19190614ce6565b8761347e565b93985091965094509250905060005b8360ff168110156123e2576122f9614061565b6000806123088887878c6135c0565b929b509094509250905061231c8284613696565b60006123298f8f856137d8565b90508d81148061236357508b818151811061235457634e487b7160e01b600052603260045260246000fd5b60209081029190910101515115155b1561237157505050506123da565b83518d516001600160401b039182169116811080159061239e57508d602001516001600160401b03168111155b80156123c257508d6040015115806123c257508d516001600160401b038085169116115b156123d4576123d48d83868885613829565b50505050505b6001016122e6565b508481146124035760405163734fff6760e11b815260040160405180910390fd5b50505050506001016121b2565b5060005b8381101561246d5781818151811061243c57634e487b7160e01b600052603260045260246000fd5b602090810291909101015151612465576040516345805f5d60e01b815260040160405180910390fd5b600101612414565b5095945050505050565b6000612484826004614df4565b835110156124cb5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7433325f6f75744f66426f756e647360601b604482015260640161096a565b50016004015190565b60006124e1826001614df4565b835110156125275760405162461bcd60e51b8152602060048201526013602482015272746f55696e74385f6f75744f66426f756e647360681b604482015260640161096a565b50016001015190565b600061253d826002614df4565b835110156125845760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b604482015260640161096a565b50016002015190565b60608161259b81601f614df4565b10156125da5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015260640161096a565b6125e48284614df4565b845110156126285760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015260640161096a565b6060821580156126475760405191506000825260208201604052612691565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612680578051835260209283019201612668565b5050858452601f01601f1916604052505b50949350505050565b6000818311156126b5576126ae8284614f16565b9050610a81565b6126ae8383614f16565b6033546001600160a01b031633146110885760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161096a565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000612778826020614df4565b835110156127c05760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b604482015260640161096a565b50016020015190565b60006127d6826014614df4565b8351101561281e5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b604482015260640161096a565b500160200151600160601b900490565b612836614096565b60008061284b60c9546001600160a01b031690565b6001600160a01b031663c0fd8bde856040518263ffffffff1660e01b81526004016128769190614af5565b60006040518083038186803b15801561288e57600080fd5b505afa1580156128a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128ca9190810190614706565b5091509150806128ed57604051632acbe91560e01b815260040160405180910390fd5b6128ff82606001518360800151610e0e565b61291c5760405163360f2d8760e01b815260040160405180910390fd5b60d2546001600160401b03166001600160401b03168260a001516001600160401b03161161295d576040516388d1b84760e01b815260040160405180910390fd5b61296a8260a0015161339a565b5092915050565b610b6a81613a69565b60006129ae6040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015290565b90506000806129c560c9546001600160a01b031690565b845160405163607ec5ef60e11b81526001600160a01b03929092169163c0fd8bde916129f391600401614af5565b60006040518083038186803b158015612a0b57600080fd5b505afa158015612a1f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a479190810190614706565b509150915080612a6a57604051632acbe91560e01b815260040160405180910390fd5b6000612a798360e00151610e31565b9050612a836113bd565b61ffff16816040015161ffff1614158015612aa55750604081015161ffff1615155b15612ac3576040516363daeb7760e01b815260040160405180910390fd5b600581602001516006811115612ae957634e487b7160e01b600052602160045260246000fd5b14612b07576040516397363b3560e01b815260040160405180910390fd5b6000612b16826060015161108a565b805190915063ffffffff16612b3060d45463ffffffff1690565b63ffffffff1610612b54576040516388d1b84760e01b815260040160405180910390fd5b805160d4805463ffffffff191663ffffffff90921691909117905560408051808201909152606085015161ffff1680825260808601516020830181905260d0805461ffff191690921790915560d155612bb08560a0015161339a565b7f6bce23ef3d34e51710fe4700b43ba5f1733a6215c883f384671a4ece3ea8aa2086612c046040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015290565b60d25460408051845161ffff90811682526020958601518683015284511691810191909152929091015160608301526001600160401b0316608082015260a0015b60405180910390a150505050505050565b6000612c60611446565b905060005b8151811015612cd857600060c96004016000612ca7858581518110612c9a57634e487b7160e01b600052603260045260246000fd5b6020026020010151611265565b81526020810191909152604001600020805460ff1916911515919091179055612cd1600182614df4565b9050612c65565b50612ce560cc60006140f1565b60005b825151811015612dba578251805160cc919083908110612d1857634e487b7160e01b600052603260045260246000fd5b60209081029190910181015182546001808201855560009485528385208351600290930201805461ffff191661ffff90931692909217825591909201519181019190915584518051919260cd929091612d899186908110612c9a57634e487b7160e01b600052603260045260246000fd5b81526020810191909152604001600020805460ff191691151591909117905580612db281614f59565b915050612ce8565b507fd451e0fcb7c5b9e13de533604d158069dad159841c45f39f09d379bfc423080d81612de5611446565b604051612df3929190614a52565b60405180910390a15050565b6000612e0a60ce5490565b825160ce5590507f74dbbbe280ef27b79a8a0c449d5ae2ba7a31849103241d0f98df70bbc9d03e3781612e3c60ce5490565b60408051928352602083019190915201612df3565b6000612e5c60cf5490565b825160cf5590507fcdb88a22f82ddd76115ab7c66cf08eb1e40afe80c9b31017eb2cbdb1570b33ae81612e3c60cf5490565b6000612ea260c9546001600160a01b031690565b9050612eb18360000151613378565b600080612ec660c9546001600160a01b031690565b6001600160a01b031663c0fd8bde856040518263ffffffff1660e01b8152600401612ef19190614af5565b60006040518083038186803b158015612f0957600080fd5b505afa158015612f1d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f459190810190614706565b509150915080612f68576040516397363b3560e01b815260040160405180910390fd5b612f7a82606001518360800151610e0e565b612f97576040516397363b3560e01b815260040160405180910390fd5b60d2546001600160401b03166001600160401b03168260a001516001600160401b031614612fd8576040516309e9f6c160e11b815260040160405180910390fd5b6000612fe78360e00151610e31565b905060068160200151600681111561300f57634e487b7160e01b600052602160045260246000fd5b1461302d576040516309e9f6c160e11b815260040160405180910390fd5b600061303c8260600151611234565b875181519192506001600160a01b0391821691161461306e576040516309e9f6c160e11b815260040160405180910390fd5b7fd495c4e5b386d59bccca38a2277b5d70a0f5e47d7b6587a45a6f5aca221a3125856130a260c9546001600160a01b031690565b604080516001600160a01b03938416815292909116602083015201612c45565b6130ca614061565b50600090815260d56020908152604091829020825160c08101845281546001600160401b038082168352600160401b808304600390810b810b900b95840195909552600160601b8204600790810b810b810b96840196909652600160a01b9091048116606083015260019092015480850b850b90940b60808201529190920490911660a082015290565b60046000833560e01c63504e415581146131815760405163734fff6760e11b815260040160405180910390fd5b60018084019386013560f81c9081146131ad5760405163734fff6760e11b815260040160405180910390fd5b50508184016001013560f890811c9092016002818101939186010135901c60ff1680156131ea57634e487b7160e01b600052602160045260246000fd5b600192909201919050818310156132145760405163734fff6760e11b815260040160405180910390fd5b9250929050565b60008382013560f01c61322f600284614df4565b925061323f61ffff821684614df4565b92508483013560f81c5b95945050505050565b600061325d60ce5490565b610a819083614ef7565b60008060006132768585613154565b9092509050600081801561329a57634e487b7160e01b600052602160045260246000fd5b146132b85760405163734fff6760e11b815260040160405180910390fd5b6000803660006132c989898861347e565b919a50929650909450909250905060005b8760ff1681101561331b576132ed614061565b6000806132fc8787878b6135c0565b929a50909450925090506133108284613696565b5050506001016132da565b5083811461333c5760405163734fff6760e11b815260040160405180910390fd5b50505050505092915050565b600054610100900460ff1661336f5760405162461bcd60e51b815260040161096a90614ba0565b61108833612719565b60c980546001600160a01b0319166001600160a01b0392909216919091179055565b60d2805467ffffffffffffffff19166001600160401b0392909216919091179055565b6001600160a01b0381163b61342a5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161096a565b600080516020614fdc83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61346283613b67565b60008251118061346f5750805b15611fd0576118308383613ba7565b600080803681613492888888808203613c92565b600296509092509050813560f01c606060006134b86134b386868b87613c92565b613cbc565b60e0015160048082015161ffff86169a909a01999193509150634155575663ffffffff8216146134fb5760405163734fff6760e11b815260040160405180910390fd5b8183016001015160009060ff16801561352457634e487b7160e01b600052602160045260246000fd5b6001909301929050600081801561354b57634e487b7160e01b600052602160045260246000fd5b146135695760405163734fff6760e11b815260040160405180910390fd5b602c84840101518451600160601b90910460601b99506020909301928311156135a55760405163734fff6760e11b815260040160405180910390fd5b5050600188019b969a505050509381013560f81c9550935050565b60006135ca614061565b600283019260009081903690829089013560f01c6135ea8a8a8a84613c92565b925092508061ffff168801975060006136078b8b8b8f8888613dad565b98509050806136295760405163734fff6760e11b815260040160405180910390fd5b6000843560f81c801561364c57634e487b7160e01b600052602160045260246000fd5b9050600081801561366d57634e487b7160e01b600052602160045260246000fd5b1415611b655761367f85856001613e55565b919950975095505050505050945094509450949050565b600082815260d5602052604090205481516001600160401b039182169116811015611fd057600083815260d560209081526040918290208451815486840151878601516060808a01516001600160401b039586166001600160601b03199095168517600160401b63ffffffff60039690960b959095168502176fffffffffffffffffffffffffffffffff60601b1916600160601b600794850b8089169190910267ffffffffffffffff60a01b191691909117600160a01b92881692830217885560808c01516001909801805460a08e01519990950b88166fffffffffffffffffffffffffffffffff1990951694909417979096169093029590951790558551918252938101919091529283019190915284917fd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec910160405180910390a2505050565b6000805b83811015611b9a578285858381811061380557634e487b7160e01b600052603260045260246000fd5b90506020020135141561381757611b9a565b8061382181614f59565b9150506137dc565b8285858151811061384a57634e487b7160e01b600052603260045260246000fd5b60200260200101516000018181525050816040015185858151811061387f57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516000019060070b908160070b8152505081606001518585815181106138c057634e487b7160e01b600052603260045260246000fd5b602002602001015160200151602001906001600160401b031690816001600160401b031681525050816020015185858151811061390d57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516040019060030b908160030b815250508085858151811061394a57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516060018181525050816080015185858151811061398357634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516000019060070b908160070b815250508160a001518585815181106139c457634e487b7160e01b600052603260045260246000fd5b602002602001015160400151602001906001600160401b031690816001600160401b0316815250508160200151858581518110613a1157634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516040019060030b908160030b8152505080858581518110613a4e57634e487b7160e01b600052603260045260246000fd5b60200260200101516040015160600181815250505050505050565b6000613a73611f79565b8251909150613a83906000610b38565b306001600160a01b031663e3795cc16040518163ffffffff1660e01b815260040160206040518083038186803b158015613abc57600080fd5b505afa158015613ad0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613af491906148ba565b63ffffffff166397a6f30414613b1d576040516397363b3560e01b815260040160405180910390fd5b7f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a4981613b47611f79565b604080516001600160a01b03938416815292909116602083015201612df3565b613b70816133bd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b613c0f5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161096a565b600080846001600160a01b031684604051613c2a91906149f4565b600060405180830381855af49150503d8060008114613c65576040519150601f19603f3d011682016040523d82523d6000602084013e613c6a565b606091505b50915091506132498282604051806060016040528060278152602001614ffc60279139613f43565b366000858486613ca28683614df4565b92613caf93929190614dcc565b9150915094509492505050565b613cc4614096565b6000613cd860c9546001600160a01b031690565b6001600160a01b031663c0fd8bde85856040518363ffffffff1660e01b8152600401613d05929190614ac6565b60006040518083038186803b158015613d1d57600080fd5b505afa158015613d31573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613d599190810190614706565b50909250905080613d7d57604051632acbe91560e01b815260040160405180910390fd5b50613d9081606001518260800151610b6d565b610a815760405163e60dce7160e01b815260040160405180910390fd5b6000806000613df185858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613f5c92505050565b600188019790915089013560f81c60005b8160ff16811015613e345760148901988b01356001600160601b031916613e298482613f8f565b935050600101613e02565b50506001600160601b03199081169516949094149794965093945050505050565b613e5d614061565b60208483018181013560c090811c600790810b900b6040858101919091526028830135821c6060860152603083013560e01c600390810b900b85850152603483013590911c84528051601f8701849004840281018401909152858152603c90940193903591600091613eeb918890889081908401838280828437600092019190915250889250613fdb915050565b868501600881013560c090811c600790810b900b6080870152601090910135901c60a0850152601890940193905084841115613f3a5760405163734fff6760e11b815260040160405180910390fd5b93509350939050565b60608315613f52575081610e2a565b610e2a8383613fe3565b6000610a81600083604051602001613f75929190614a10565b604051602081830303815290604052805160209091012090565b60006001600160601b03198083169084161115613faa579091905b604051600160f81b60208201526001600160601b0319808516602183015283166035820152610e2a90604901613f75565b016008015190565b815115613ff35781518083602001fd5b8060405162461bcd60e51b815260040161096a9190614af5565b60408051608081018252600080825260208201819052918101829052606081019190915290565b6040805160608101909152600081526020810161404f61400d565b815260200161405c61400d565b905290565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201819052610100820183905261012082015261014081019190915290565b5080546000825560020290600052602060002090810190610b6a91905b8082111561412e57805461ffff191681556000600182015560020161410e565b5090565b80356001600160a01b038116811461414957600080fd5b919050565b60008083601f84011261415f578182fd5b5081356001600160401b03811115614175578182fd5b6020830191508360208260051b850101111561321457600080fd5b600082601f8301126141a0578081fd5b815160206001600160401b038211156141bb576141bb614fa0565b6141c9818360051b01614d75565b80838252828201915082860187848660071b89010111156141e8578586fd5b855b8581101561424b57608080838b031215614202578788fd5b61420a614d2a565b8351815286840151878201526040614223818601614326565b908201526060614234858201614326565b9082015285529385019391909101906001016141ea565b5090979650505050505050565b8051801515811461414957600080fd5b600082601f830112614278578081fd5b813561428b61428682614da5565b614d75565b81815284602083860101111561429f578283fd5b816020850160208301379081016020019190915292915050565b600082601f8301126142c9578081fd5b81516142d761428682614da5565b8181528460208386010111156142eb578283fd5b611b9a826020830160208701614f2d565b805161414981614fb6565b805163ffffffff8116811461414957600080fd5b805161414981614fc6565b805160ff8116811461414957600080fd5b600060208284031215614348578081fd5b610e2a82614132565b6000806000806000806000806000806101008b8d031215614370578586fd5b6143798b614132565b995060208b01356001600160401b0380821115614394578788fd5b6143a08e838f0161414e565b909b50995060408d01359150808211156143b8578788fd5b506143c58d828e0161414e565b90985096505060608b01356143d981614fb6565b945060808b0135935060a08b01356143f081614fc6565b8093505060c08b0135915060e08b013590509295989b9194979a5092959850565b60008060408385031215614423578182fd5b61442c83614132565b915060208301356001600160401b03811115614446578182fd5b61445285828601614268565b9150509250929050565b6000806020838503121561446e578182fd5b82356001600160401b03811115614483578283fd5b61448f8582860161414e565b90969095509350505050565b600080600080600080606087890312156144b3578384fd5b86356001600160401b03808211156144c9578586fd5b6144d58a838b0161414e565b909850965060208901359150808211156144ed578586fd5b6144f98a838b0161414e565b90965094506040890135915080821115614511578384fd5b5061451e89828a0161414e565b979a9699509497509295939492505050565b60008060008060008060808789031215614548578384fd5b86356001600160401b038082111561455e578586fd5b61456a8a838b0161414e565b90985096506020890135915080821115614582578586fd5b5061458f89828a0161414e565b90955093505060408701356145a381614fc6565b915060608701356145b381614fc6565b809150509295509295509295565b6000602082840312156145d2578081fd5b5035919050565b6000602082840312156145ea578081fd5b5051919050565b60008060408385031215614603578182fd5b50508035926020909101359150565b60008060208385031215614624578182fd5b82356001600160401b038082111561463a578384fd5b818501915085601f83011261464d578384fd5b81358181111561465b578485fd5b86602082850101111561466c578485fd5b60209290920196919550909350505050565b60006020828403121561468f578081fd5b81356001600160401b038111156146a4578182fd5b611b9a84828501614268565b6000604082840312156146c1578081fd5b604051604081018181106001600160401b03821117156146e3576146e3614fa0565b60405282356146f181614fb6565b81526020928301359281019290925250919050565b60008060006060848603121561471a578081fd5b83516001600160401b0380821115614730578283fd5b908501906101608288031215614744578283fd5b61474c614d52565b61475583614326565b815261476360208401614307565b602082015261477460408401614307565b6040820152614785606084016142fc565b6060820152608083015160808201526147a060a0840161431b565b60a08201526147b160c08401614326565b60c082015260e0830151828111156147c7578485fd5b6147d3898286016142b9565b60e0830152506101006147e7818501614307565b9082015261012083810151838111156147fe578586fd5b61480a8a828701614190565b91830191909152506101408381015190820152945061482b60208701614258565b93506040860151915080821115614840578283fd5b5061484d868287016142b9565b9150509250925092565b600060208284031215614868578081fd5b8135610e2a81614fb6565b600060208284031215614884578081fd5b8151610e2a81614fb6565b600080604083850312156148a1578182fd5b82356148ac81614fb6565b946020939093013593505050565b6000602082840312156148cb578081fd5b610e2a82614307565b6000602082840312156148e5578081fd5b8135610e2a81614fc6565b6000815180845260208085019450808401835b8381101561493757614924878351805161ffff168252602090810151910152565b6040969096019590820190600101614903565b509495945050505050565b6000815180845261495a816020860160208601614f2d565b601f01601f19169290920160200192915050565b8051825260208101516149b46020840182805160070b82526001600160401b036020820151166020830152604081015160030b6040830152606081015160608301525050565b50604081810151805160070b60a085015260208101516001600160401b031660c08501529081015160030b60e08401526060810151610100840152611fd0565b60008251614a06818460208701614f2d565b9190910192915050565b60ff60f81b8360f81b16815260008251614a31816001850160208701614f2d565b919091016001019392505050565b602081526000610e2a60208301846148f0565b604081526000614a6560408301856148f0565b828103602084015261324981856148f0565b6020808252825182820181905260009190848201906040850190845b81811015614aba57614aa683855161496e565b928401926101209290920191600101614a93565b50909695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b602081526000610e2a6020830184614942565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020815260008251602080840152611b9a6040840182614942565b815161ffff1681526020808301519082015260408101610a81565b602081526000825160048110614c3957614c39614f8a565b80602084015250602083015160078110614c5557614c55614f8a565b8060408401525061ffff60408401511660608301526060830151608080840152611b9a60a0840182614942565b6101208101610a81828461496e565b815160070b81526020808301516001600160401b03169082015260408083015160030b908201526060808301519082015260808101610a81565b6020815260008251602080840152611b9a60408401826148f0565b6000808335601e19843603018112614cfc578283fd5b8301803591506001600160401b03821115614d15578283fd5b60200191503681900382131561321457600080fd5b604051608081016001600160401b0381118282101715614d4c57614d4c614fa0565b60405290565b60405161016081016001600160401b0381118282101715614d4c57614d4c614fa0565b604051601f8201601f191681016001600160401b0381118282101715614d9d57614d9d614fa0565b604052919050565b60006001600160401b03821115614dbe57614dbe614fa0565b50601f01601f191660200190565b60008085851115614ddb578182fd5b83861115614de7578182fd5b5050820193919092039150565b60008219821115614e0757614e07614f74565b500190565b600181815b80851115614e47578160001904821115614e2d57614e2d614f74565b80851615614e3a57918102915b93841c9390800290614e11565b509250929050565b6000610e2a8383600082614e6557506001610a81565b81614e7257506000610a81565b8160018114614e885760028114614e9257614eae565b6001915050610a81565b60ff841115614ea357614ea3614f74565b50506001821b610a81565b5060208310610133831016604e8410600b8410161715614ed1575081810a610a81565b614edb8383614e0c565b8060001904821115614eef57614eef614f74565b029392505050565b6000816000190483118215151615614f1157614f11614f74565b500290565b600082821015614f2857614f28614f74565b500390565b60005b83811015614f48578181015183820152602001614f30565b838111156118305750506000910152565b6000600019821415614f6d57614f6d614f74565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b61ffff81168114610b6a57600080fd5b6001600160401b0381168114610b6a57600080fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212209f7afb5640a4e9f94c48fcacfc59de055292f6e8f069b525f3a290f54ac4d50c64736f6c63430008040033
Deployed Bytecode
0x6080604052600436106102725760003560e01c80638881016f1161014f578063b5ec0261116100c1578063d82d58a51161007a578063d82d58a514610819578063e17efd4814610852578063e18910a314610872578063e3795cc114610887578063ef9e5e281461089e578063f2fde38b146108b157600080fd5b8063b5ec02611461074c578063b6ed701e14610784578063b9256d28146107a4578063caaf43f1146107b7578063cb718a9b146107e4578063d47eed45146107f957600080fd5b80639a8a0592116101135780639a8a0592146106af578063a38d81c6146106d7578063a4ae35e0146106f9578063aac41292146105f9578063accca7f914610719578063b5dcc9111461072c57600080fd5b80638881016f146105f957806389a5bb4d146106315780638da5cb5b146106515780639474f45b1461066f57806396834ad31461068f57600080fd5b806352d1902d116101e85780636c72f51b116101ac5780636c72f51b14610504578063711a2e2814610530578063715018a6146105505780637b72bcae1461056557806384acd1bb1461059a57806387c5bd1b146105cc57600080fd5b806352d1902d1461045057806354fd4d5014610465578063586d3cf81461049957806358c67635146104b75780636b7f53ca146104d757600080fd5b8063437209a71161023a578063437209a7146103605780634716e9c51461039057806348b6404d146103b05780634c469d8c146103cf5780634d7a734e1461041d5780634f1ef2861461043d57600080fd5b8063146faf771461027757806314dd317f1461029957806331d98b3f146102cd5780633659cfe6146102fa578063426234e41461031a575b600080fd5b34801561028357600080fd5b50610297610292366004614351565b6108d1565b005b3480156102a557600080fd5b506102b96102b436600461467e565b610a13565b604051905181526020015b60405180910390f35b3480156102d957600080fd5b506102ed6102e83660046145c1565b610a6d565b6040516102c49190614c91565b34801561030657600080fd5b50610297610315366004614337565b610a87565b34801561032657600080fd5b506040805180820182526000808252602091820152815180830190925260d05461ffff16825260d154908201526040516102c49190614c06565b34801561036c57600080fd5b5061038061037b36600461488f565b610b6d565b60405190151581526020016102c4565b6103a361039e366004614530565b610bc0565b6040516102c49190614a77565b3480156103bc57600080fd5b5060ce545b6040519081526020016102c4565b3480156103db57600080fd5b506104056103ea3660046145c1565b600090815260d560205260409020546001600160401b031690565b6040516001600160401b0390911681526020016102c4565b34801561042957600080fd5b506102b961043836600461467e565b610c09565b61029761044b366004614411565b610ca1565b34801561045c57600080fd5b506103c1610d5b565b34801561047157600080fd5b506040805180820182526005815264312e342e3360d81b602082015290516102c49190614af5565b3480156104a557600080fd5b5060d2546001600160401b0316610405565b3480156104c357600080fd5b506103806104d236600461488f565b610e0e565b3480156104e357600080fd5b506104f76104f236600461467e565b610e31565b6040516102c49190614c21565b34801561051057600080fd5b5060d45463ffffffff165b60405163ffffffff90911681526020016102c4565b34801561053c57600080fd5b506102ed61054b3660046145f1565b611035565b34801561055c57600080fd5b50610297611076565b34801561057157600080fd5b5061058561058036600461467e565b61108a565b604051905163ffffffff1681526020016102c4565b3480156105a657600080fd5b5060c9546001600160a01b03165b6040516001600160a01b0390911681526020016102c4565b3480156105d857600080fd5b506105ec6105e736600461467e565b6110b8565b6040516102c49190614ccb565b34801561060557600080fd5b5061061961061436600461467e565b611234565b60405190516001600160a01b031681526020016102c4565b34801561063d57600080fd5b506103c161064c3660046146b0565b611265565b34801561065d57600080fd5b506033546001600160a01b03166105b4565b34801561067b57600080fd5b506102ed61068a3660046145c1565b6112b7565b34801561069b57600080fd5b506102ed6106aa3660046145c1565b611338565b3480156106bb57600080fd5b506106c46113bd565b60405161ffff90911681526020016102c4565b3480156106e357600080fd5b506106ec611446565b6040516102c49190614a3f565b34801561070557600080fd5b506102ed6107143660046145f1565b6114b9565b6103a3610727366004614530565b6114ca565b34801561073857600080fd5b506102ed6107473660046145c1565b611508565b34801561075857600080fd5b506103806107673660046145c1565b600090815260d560205260409020546001600160401b0316151590565b34801561079057600080fd5b5061029761079f366004614612565b61151c565b6102976107b236600461449b565b611836565b3480156107c357600080fd5b506107d76107d23660046145c1565b61192d565b6040516102c49190614c82565b3480156107f057600080fd5b5060cf546103c1565b34801561080557600080fd5b506103c161081436600461445c565b6119fb565b34801561082557600080fd5b5061084561083436600461467e565b604080516020810190915290815290565b6040516102c49190614beb565b34801561085e57600080fd5b506103c161086d3660046145c1565b611ba2565b34801561087e57600080fd5b506103c1611bc3565b34801561089357600080fd5b506397a6f30461051b565b6102976108ac36600461445c565b611bce565b3480156108bd57600080fd5b506102976108cc366004614337565b611c59565b600054610100900460ff16158080156108f15750600054600160ff909116105b8061090b5750303b15801561090b575060005460ff166001145b6109735760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610996576000805461ff0019166101001790555b61099e611cde565b6109a6611d0d565b6109b88b8b8b8b8b8b8b8b8b8b611d34565b6109c0611076565b8015610a06576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050505050565b6040805160208101909152600081526000610a2e8382611f1c565b6001600160401b03168252610a44600882614df4565b905080835114610a67576040516397363b3560e01b815260040160405180910390fd5b50919050565b610a7561400d565b610a8182610714611bc3565b92915050565b306001600160a01b037f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b5729161415610ad05760405162461bcd60e51b815260040161096a90614b08565b7f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b57296001600160a01b0316610b02611f79565b6001600160a01b031614610b285760405162461bcd60e51b815260040161096a90614b54565b610b3181611f95565b610b6a8160005b6040519080825280601f01601f191660200182016040528015610b62576020820181803683370190505b506000611f9d565b50565b6040805160f09390931b6001600160f01b0319166020808501919091526022808501939093528151808503909301835260429093018152815191830191909120600090815260cd90925290205460ff1690565b6060610bfe878787876040518060600160405280896001600160401b03168152602001886001600160401b031681526020016000151581525061211c565b979650505050505050565b604080516020810190915260008152600080610c258482611f1c565b9050610c32600883614df4565b91506000610c408584611f1c565b9050610c4d600884614df4565b9250610c636001600160401b038216600a614e4f565b610c76906001600160401b038416614ef7565b845284518314610c99576040516397363b3560e01b815260040160405180910390fd5b505050919050565b306001600160a01b037f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b5729161415610cea5760405162461bcd60e51b815260040161096a90614b08565b7f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b57296001600160a01b0316610d1c611f79565b6001600160a01b031614610d425760405162461bcd60e51b815260040161096a90614b54565b610d4b82611f95565b610d5782826001611f9d565b5050565b6000306001600160a01b037f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b57291614610dfb5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840161096a565b50600080516020614fdc83398151915290565b60d05460009061ffff8481169116148015610e2a575060d15482145b9392505050565b610e5d604080516080810190915280600081526020016000815260006020820152606060409091015290565b600080610e6a8482612477565b905063ffffffff8116635054474d14610e96576040516397363b3560e01b815260040160405180910390fd5b610ea1600483614df4565b91506000610eaf85846124d4565b90508060ff166003811115610ed457634e487b7160e01b600052602160045260246000fd5b84906003811115610ef557634e487b7160e01b600052602160045260246000fd5b90816003811115610f1657634e487b7160e01b600052602160045260246000fd5b905250610f24600184614df4565b9250600184516003811115610f4957634e487b7160e01b600052602160045260246000fd5b14610f67576040516363daeb7760e01b815260040160405180910390fd5b6000610f7386856124d4565b90508060ff166006811115610f9857634e487b7160e01b600052602160045260246000fd5b85602001906006811115610fbc57634e487b7160e01b600052602160045260246000fd5b90816006811115610fdd57634e487b7160e01b600052602160045260246000fd5b905250610feb600185614df4565b9350610ff78685612530565b61ffff16604086015261100b600285614df4565b93506110268485885161101e9190614f16565b88919061258d565b60608601525092949350505050565b61103d61400d565b611046836112b7565b90508161105742836060015161269a565b1115610a8157604051630cd5fa0760e11b815260040160405180910390fd5b61107e6126bf565b6110886000612719565b565b60408051602081019091526000815260006110a58382612477565b63ffffffff168252610a44600482614df4565b6040805160208101909152606081526000806110d484826124d4565b90506110e1600183614df4565b91508060ff166001600160401b0381111561110c57634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561115157816020015b604080518082019091526000808252602082015281526020019060019003908161112a5790505b50835260005b8160ff1681101561120b5761116c8584612530565b845180518390811061118e57634e487b7160e01b600052603260045260246000fd5b602090810291909101015161ffff90911690526111ac600284614df4565b92506111b8858461276b565b84518051839081106111da57634e487b7160e01b600052603260045260246000fd5b602002602001015160200181815250506020836111f79190614df4565b92508061120381614f59565b915050611157565b508184511461122d576040516397363b3560e01b815260040160405180910390fd5b5050919050565b604080516020810190915260008152600061124f83826127c9565b6001600160a01b03168252610a44601482614df4565b60008160000151826020015160405160200161129a92919060f09290921b6001600160f01b0319168252600282015260220190565b604051602081830303815290604052805190602001209050919050565b6112bf61400d565b600082815260d5602090815260409182902080546001600160401b0380821660608701819052600160401b92839004600390810b810b900b958701959095526001830154600781810b810b900b875291909104169184019190915290610a6757604051630295d7cd60e31b815260040160405180910390fd5b61134061400d565b600082815260d5602090815260409182902080546001600160401b0380821660608701819052600160401b8304600390810b810b900b95870195909552600160601b8204600790810b810b900b8652600160a01b909104169184019190915290610a6757604051630295d7cd60e31b815260040160405180910390fd5b60006113d160c9546001600160a01b031690565b6001600160a01b0316639a8a05926040518163ffffffff1660e01b815260040160206040518083038186803b15801561140957600080fd5b505afa15801561141d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114419190614873565b905090565b606060c9600301805480602002602001604051908101604052809291908181526020016000905b828210156114b05760008481526020908190206040805180820190915260028502909101805461ffff16825260019081015482840152908352909201910161146d565b50505050905090565b6114c161400d565b61104683611338565b6060610bfe878787876040518060600160405280896001600160401b03168152602001886001600160401b031681526020016001151581525061211c565b61151061400d565b610a818261054b611bc3565b600061155d83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061282e92505050565b9050600061156e8260e00151610e31565b90506115786113bd565b61ffff16816040015161ffff161415801561159a5750604081015161ffff1615155b156115b8576040516363daeb7760e01b815260040160405180910390fd5b6000816020015160068111156115de57634e487b7160e01b600052602160045260246000fd5b141561162457604081015161ffff1661160a576040516363daeb7760e01b815260040160405180910390fd5b61161f61161a8260600151611234565b612971565b611830565b60018160200151600681111561164a57634e487b7160e01b600052602160045260246000fd5b14156116715761161f61166c8260600151604080516020810190915290815290565b61297a565b60028160200151600681111561169757634e487b7160e01b600052602160045260246000fd5b14156116b25761161f6116ad82606001516110b8565b612c56565b6003816020015160068111156116d857634e487b7160e01b600052602160045260246000fd5b14156116f35761161f6116ee8260600151610c09565b612dff565b60048160200151600681111561171957634e487b7160e01b600052602160045260246000fd5b14156117345761161f61172f8260600151610a13565b612e51565b60058160200151600681111561175a57634e487b7160e01b600052602160045260246000fd5b1415611779576040516397363b3560e01b815260040160405180910390fd5b60068160200151600681111561179f57634e487b7160e01b600052602160045260246000fd5b141561181757604081015161ffff166117cb576040516363daeb7760e01b815260040160405180910390fd5b61161f6117db8260600151611234565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612e8e92505050565b6040516397363b3560e01b815260040160405180910390fd5b50505050565b8281146118565760405163a9cb9e0d60e01b815260040160405180910390fd5b60005b8381101561190b5782828281811061188157634e487b7160e01b600052603260045260246000fd5b905060200201602081019061189691906148d4565b6001600160401b03166118e48686848181106118c257634e487b7160e01b600052603260045260246000fd5b90506020020135600090815260d560205260409020546001600160401b031690565b6001600160401b03161015611903576118fd8787611bce565b50611925565b600101611859565b50604051636f162bfd60e11b815260040160405180910390fd5b505050505050565b611935614034565b6000611940836130c2565b80519091506001600160401b031661196b57604051630295d7cd60e31b815260040160405180910390fd5b91815260408083015160208084018051600793840b840b905260608087015182516001600160401b039182169085015283880180518451600391820b820b9089015289519451948316948401949094526080890151878901805191880b90970b905260a089015186519083169501949094529251845190830b90920b919094015293519051931692019190915290565b600080805b83811015611b90576004858583818110611a2a57634e487b7160e01b600052603260045260246000fd5b9050602002810190611a3c9190614ce6565b9050118015611a90575063504e4155611a88868684818110611a6e57634e487b7160e01b600052603260045260246000fd5b9050602002810190611a809190614ce6565b503560e01c90565b63ffffffff16145b15611b6557600080611ad2878785818110611abb57634e487b7160e01b600052603260045260246000fd5b9050602002810190611acd9190614ce6565b613154565b90925090506000818015611af657634e487b7160e01b600052602160045260246000fd5b14611b145760405163734fff6760e11b815260040160405180910390fd5b611b4f878785818110611b3757634e487b7160e01b600052603260045260246000fd5b9050602002810190611b499190614ce6565b8461321b565b611b5c9060ff1685614df4565b93505050611b7e565b60405163734fff6760e11b815260040160405180910390fd5b80611b8881614f59565b915050611a00565b50611b9a81613252565b949350505050565b600081611bae60ce5490565b611bb99060ff614ef7565b610a819190614ef7565b600061144160cf5490565b6000805b82811015611c2b57611c14848483818110611bfd57634e487b7160e01b600052603260045260246000fd5b9050602002810190611c0f9190614ce6565b613267565b611c219060ff1683614df4565b9150600101611bd2565b506000611c3782613252565b9050803410156118305760405162976f7560e21b815260040160405180910390fd5b611c616126bf565b6001600160a01b038116611cc65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161096a565b610b6a81612719565b6001600160a01b03163b151590565b600054610100900460ff16611d055760405162461bcd60e51b815260040161096a90614ba0565b611088613348565b600054610100900460ff166110885760405162461bcd60e51b815260040161096a90614ba0565b611d3d8a613378565b878614611d5d5760405163a9cb9e0d60e01b815260040160405180910390fd5b60005b88811015611ec757600060405180604001604052808c8c85818110611d9557634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611daa9190614857565b61ffff1681526020018a8a85818110611dd357634e487b7160e01b600052603260045260246000fd5b905060200201358152509050611df181600001518260200151610b6d565b15611e0f5760405163a9cb9e0d60e01b815260040160405180910390fd5b600160cd6000611e1e84611265565b81526020808201929092526040016000908120805460ff19169315159390931790925560cc8054600181018255925282517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebe6002909302928301805461ffff191661ffff90921691909117905591909101517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebf9091015580611ebf81614f59565b915050611d60565b506040805180820190915261ffff86168082526020820186905260d0805461ffff1916909117905560d1859055611efd8461339a565b50611f078260cf55565b611f108160ce55565b50505050505050505050565b6000611f29826008614df4565b83511015611f705760405162461bcd60e51b8152602060048201526014602482015273746f55696e7436345f6f75744f66426f756e647360601b604482015260640161096a565b50016008015190565b600080516020614fdc833981519152546001600160a01b031690565b610b6a6126bf565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611fd557611fd0836133bd565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561200e57600080fd5b505afa92505050801561203e575060408051601f3d908101601f1916820190925261203b918101906145d9565b60015b6120a15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840161096a565b600080516020614fdc83398151915281146121105760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840161096a565b50611fd0838383613459565b6060600061212a87876119fb565b90508034101561214c5760405162976f7560e21b815260040160405180910390fd5b50826001600160401b0381111561217357634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156121ac57816020015b612199614034565b8152602001906001900390816121915790505b50905060005b858110156124105760048787838181106121dc57634e487b7160e01b600052603260045260246000fd5b90506020028101906121ee9190614ce6565b9050118015612228575063504e4155612220888884818110611a6e57634e487b7160e01b600052603260045260246000fd5b63ffffffff16145b15611b6557600080612253898985818110611abb57634e487b7160e01b600052603260045260246000fd5b9092509050600081801561227757634e487b7160e01b600052602160045260246000fd5b146122955760405163734fff6760e11b815260040160405180910390fd5b506000803660006122d78c8c888181106122bf57634e487b7160e01b600052603260045260246000fd5b90506020028101906122d19190614ce6565b8761347e565b93985091965094509250905060005b8360ff168110156123e2576122f9614061565b6000806123088887878c6135c0565b929b509094509250905061231c8284613696565b60006123298f8f856137d8565b90508d81148061236357508b818151811061235457634e487b7160e01b600052603260045260246000fd5b60209081029190910101515115155b1561237157505050506123da565b83518d516001600160401b039182169116811080159061239e57508d602001516001600160401b03168111155b80156123c257508d6040015115806123c257508d516001600160401b038085169116115b156123d4576123d48d83868885613829565b50505050505b6001016122e6565b508481146124035760405163734fff6760e11b815260040160405180910390fd5b50505050506001016121b2565b5060005b8381101561246d5781818151811061243c57634e487b7160e01b600052603260045260246000fd5b602090810291909101015151612465576040516345805f5d60e01b815260040160405180910390fd5b600101612414565b5095945050505050565b6000612484826004614df4565b835110156124cb5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7433325f6f75744f66426f756e647360601b604482015260640161096a565b50016004015190565b60006124e1826001614df4565b835110156125275760405162461bcd60e51b8152602060048201526013602482015272746f55696e74385f6f75744f66426f756e647360681b604482015260640161096a565b50016001015190565b600061253d826002614df4565b835110156125845760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b604482015260640161096a565b50016002015190565b60608161259b81601f614df4565b10156125da5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015260640161096a565b6125e48284614df4565b845110156126285760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015260640161096a565b6060821580156126475760405191506000825260208201604052612691565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612680578051835260209283019201612668565b5050858452601f01601f1916604052505b50949350505050565b6000818311156126b5576126ae8284614f16565b9050610a81565b6126ae8383614f16565b6033546001600160a01b031633146110885760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161096a565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000612778826020614df4565b835110156127c05760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b604482015260640161096a565b50016020015190565b60006127d6826014614df4565b8351101561281e5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b604482015260640161096a565b500160200151600160601b900490565b612836614096565b60008061284b60c9546001600160a01b031690565b6001600160a01b031663c0fd8bde856040518263ffffffff1660e01b81526004016128769190614af5565b60006040518083038186803b15801561288e57600080fd5b505afa1580156128a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128ca9190810190614706565b5091509150806128ed57604051632acbe91560e01b815260040160405180910390fd5b6128ff82606001518360800151610e0e565b61291c5760405163360f2d8760e01b815260040160405180910390fd5b60d2546001600160401b03166001600160401b03168260a001516001600160401b03161161295d576040516388d1b84760e01b815260040160405180910390fd5b61296a8260a0015161339a565b5092915050565b610b6a81613a69565b60006129ae6040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015290565b90506000806129c560c9546001600160a01b031690565b845160405163607ec5ef60e11b81526001600160a01b03929092169163c0fd8bde916129f391600401614af5565b60006040518083038186803b158015612a0b57600080fd5b505afa158015612a1f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a479190810190614706565b509150915080612a6a57604051632acbe91560e01b815260040160405180910390fd5b6000612a798360e00151610e31565b9050612a836113bd565b61ffff16816040015161ffff1614158015612aa55750604081015161ffff1615155b15612ac3576040516363daeb7760e01b815260040160405180910390fd5b600581602001516006811115612ae957634e487b7160e01b600052602160045260246000fd5b14612b07576040516397363b3560e01b815260040160405180910390fd5b6000612b16826060015161108a565b805190915063ffffffff16612b3060d45463ffffffff1690565b63ffffffff1610612b54576040516388d1b84760e01b815260040160405180910390fd5b805160d4805463ffffffff191663ffffffff90921691909117905560408051808201909152606085015161ffff1680825260808601516020830181905260d0805461ffff191690921790915560d155612bb08560a0015161339a565b7f6bce23ef3d34e51710fe4700b43ba5f1733a6215c883f384671a4ece3ea8aa2086612c046040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015290565b60d25460408051845161ffff90811682526020958601518683015284511691810191909152929091015160608301526001600160401b0316608082015260a0015b60405180910390a150505050505050565b6000612c60611446565b905060005b8151811015612cd857600060c96004016000612ca7858581518110612c9a57634e487b7160e01b600052603260045260246000fd5b6020026020010151611265565b81526020810191909152604001600020805460ff1916911515919091179055612cd1600182614df4565b9050612c65565b50612ce560cc60006140f1565b60005b825151811015612dba578251805160cc919083908110612d1857634e487b7160e01b600052603260045260246000fd5b60209081029190910181015182546001808201855560009485528385208351600290930201805461ffff191661ffff90931692909217825591909201519181019190915584518051919260cd929091612d899186908110612c9a57634e487b7160e01b600052603260045260246000fd5b81526020810191909152604001600020805460ff191691151591909117905580612db281614f59565b915050612ce8565b507fd451e0fcb7c5b9e13de533604d158069dad159841c45f39f09d379bfc423080d81612de5611446565b604051612df3929190614a52565b60405180910390a15050565b6000612e0a60ce5490565b825160ce5590507f74dbbbe280ef27b79a8a0c449d5ae2ba7a31849103241d0f98df70bbc9d03e3781612e3c60ce5490565b60408051928352602083019190915201612df3565b6000612e5c60cf5490565b825160cf5590507fcdb88a22f82ddd76115ab7c66cf08eb1e40afe80c9b31017eb2cbdb1570b33ae81612e3c60cf5490565b6000612ea260c9546001600160a01b031690565b9050612eb18360000151613378565b600080612ec660c9546001600160a01b031690565b6001600160a01b031663c0fd8bde856040518263ffffffff1660e01b8152600401612ef19190614af5565b60006040518083038186803b158015612f0957600080fd5b505afa158015612f1d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f459190810190614706565b509150915080612f68576040516397363b3560e01b815260040160405180910390fd5b612f7a82606001518360800151610e0e565b612f97576040516397363b3560e01b815260040160405180910390fd5b60d2546001600160401b03166001600160401b03168260a001516001600160401b031614612fd8576040516309e9f6c160e11b815260040160405180910390fd5b6000612fe78360e00151610e31565b905060068160200151600681111561300f57634e487b7160e01b600052602160045260246000fd5b1461302d576040516309e9f6c160e11b815260040160405180910390fd5b600061303c8260600151611234565b875181519192506001600160a01b0391821691161461306e576040516309e9f6c160e11b815260040160405180910390fd5b7fd495c4e5b386d59bccca38a2277b5d70a0f5e47d7b6587a45a6f5aca221a3125856130a260c9546001600160a01b031690565b604080516001600160a01b03938416815292909116602083015201612c45565b6130ca614061565b50600090815260d56020908152604091829020825160c08101845281546001600160401b038082168352600160401b808304600390810b810b900b95840195909552600160601b8204600790810b810b810b96840196909652600160a01b9091048116606083015260019092015480850b850b90940b60808201529190920490911660a082015290565b60046000833560e01c63504e415581146131815760405163734fff6760e11b815260040160405180910390fd5b60018084019386013560f81c9081146131ad5760405163734fff6760e11b815260040160405180910390fd5b50508184016001013560f890811c9092016002818101939186010135901c60ff1680156131ea57634e487b7160e01b600052602160045260246000fd5b600192909201919050818310156132145760405163734fff6760e11b815260040160405180910390fd5b9250929050565b60008382013560f01c61322f600284614df4565b925061323f61ffff821684614df4565b92508483013560f81c5b95945050505050565b600061325d60ce5490565b610a819083614ef7565b60008060006132768585613154565b9092509050600081801561329a57634e487b7160e01b600052602160045260246000fd5b146132b85760405163734fff6760e11b815260040160405180910390fd5b6000803660006132c989898861347e565b919a50929650909450909250905060005b8760ff1681101561331b576132ed614061565b6000806132fc8787878b6135c0565b929a50909450925090506133108284613696565b5050506001016132da565b5083811461333c5760405163734fff6760e11b815260040160405180910390fd5b50505050505092915050565b600054610100900460ff1661336f5760405162461bcd60e51b815260040161096a90614ba0565b61108833612719565b60c980546001600160a01b0319166001600160a01b0392909216919091179055565b60d2805467ffffffffffffffff19166001600160401b0392909216919091179055565b6001600160a01b0381163b61342a5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161096a565b600080516020614fdc83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61346283613b67565b60008251118061346f5750805b15611fd0576118308383613ba7565b600080803681613492888888808203613c92565b600296509092509050813560f01c606060006134b86134b386868b87613c92565b613cbc565b60e0015160048082015161ffff86169a909a01999193509150634155575663ffffffff8216146134fb5760405163734fff6760e11b815260040160405180910390fd5b8183016001015160009060ff16801561352457634e487b7160e01b600052602160045260246000fd5b6001909301929050600081801561354b57634e487b7160e01b600052602160045260246000fd5b146135695760405163734fff6760e11b815260040160405180910390fd5b602c84840101518451600160601b90910460601b99506020909301928311156135a55760405163734fff6760e11b815260040160405180910390fd5b5050600188019b969a505050509381013560f81c9550935050565b60006135ca614061565b600283019260009081903690829089013560f01c6135ea8a8a8a84613c92565b925092508061ffff168801975060006136078b8b8b8f8888613dad565b98509050806136295760405163734fff6760e11b815260040160405180910390fd5b6000843560f81c801561364c57634e487b7160e01b600052602160045260246000fd5b9050600081801561366d57634e487b7160e01b600052602160045260246000fd5b1415611b655761367f85856001613e55565b919950975095505050505050945094509450949050565b600082815260d5602052604090205481516001600160401b039182169116811015611fd057600083815260d560209081526040918290208451815486840151878601516060808a01516001600160401b039586166001600160601b03199095168517600160401b63ffffffff60039690960b959095168502176fffffffffffffffffffffffffffffffff60601b1916600160601b600794850b8089169190910267ffffffffffffffff60a01b191691909117600160a01b92881692830217885560808c01516001909801805460a08e01519990950b88166fffffffffffffffffffffffffffffffff1990951694909417979096169093029590951790558551918252938101919091529283019190915284917fd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec910160405180910390a2505050565b6000805b83811015611b9a578285858381811061380557634e487b7160e01b600052603260045260246000fd5b90506020020135141561381757611b9a565b8061382181614f59565b9150506137dc565b8285858151811061384a57634e487b7160e01b600052603260045260246000fd5b60200260200101516000018181525050816040015185858151811061387f57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516000019060070b908160070b8152505081606001518585815181106138c057634e487b7160e01b600052603260045260246000fd5b602002602001015160200151602001906001600160401b031690816001600160401b031681525050816020015185858151811061390d57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516040019060030b908160030b815250508085858151811061394a57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516060018181525050816080015185858151811061398357634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516000019060070b908160070b815250508160a001518585815181106139c457634e487b7160e01b600052603260045260246000fd5b602002602001015160400151602001906001600160401b031690816001600160401b0316815250508160200151858581518110613a1157634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516040019060030b908160030b8152505080858581518110613a4e57634e487b7160e01b600052603260045260246000fd5b60200260200101516040015160600181815250505050505050565b6000613a73611f79565b8251909150613a83906000610b38565b306001600160a01b031663e3795cc16040518163ffffffff1660e01b815260040160206040518083038186803b158015613abc57600080fd5b505afa158015613ad0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613af491906148ba565b63ffffffff166397a6f30414613b1d576040516397363b3560e01b815260040160405180910390fd5b7f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a4981613b47611f79565b604080516001600160a01b03938416815292909116602083015201612df3565b613b70816133bd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b613c0f5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161096a565b600080846001600160a01b031684604051613c2a91906149f4565b600060405180830381855af49150503d8060008114613c65576040519150601f19603f3d011682016040523d82523d6000602084013e613c6a565b606091505b50915091506132498282604051806060016040528060278152602001614ffc60279139613f43565b366000858486613ca28683614df4565b92613caf93929190614dcc565b9150915094509492505050565b613cc4614096565b6000613cd860c9546001600160a01b031690565b6001600160a01b031663c0fd8bde85856040518363ffffffff1660e01b8152600401613d05929190614ac6565b60006040518083038186803b158015613d1d57600080fd5b505afa158015613d31573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613d599190810190614706565b50909250905080613d7d57604051632acbe91560e01b815260040160405180910390fd5b50613d9081606001518260800151610b6d565b610a815760405163e60dce7160e01b815260040160405180910390fd5b6000806000613df185858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613f5c92505050565b600188019790915089013560f81c60005b8160ff16811015613e345760148901988b01356001600160601b031916613e298482613f8f565b935050600101613e02565b50506001600160601b03199081169516949094149794965093945050505050565b613e5d614061565b60208483018181013560c090811c600790810b900b6040858101919091526028830135821c6060860152603083013560e01c600390810b900b85850152603483013590911c84528051601f8701849004840281018401909152858152603c90940193903591600091613eeb918890889081908401838280828437600092019190915250889250613fdb915050565b868501600881013560c090811c600790810b900b6080870152601090910135901c60a0850152601890940193905084841115613f3a5760405163734fff6760e11b815260040160405180910390fd5b93509350939050565b60608315613f52575081610e2a565b610e2a8383613fe3565b6000610a81600083604051602001613f75929190614a10565b604051602081830303815290604052805160209091012090565b60006001600160601b03198083169084161115613faa579091905b604051600160f81b60208201526001600160601b0319808516602183015283166035820152610e2a90604901613f75565b016008015190565b815115613ff35781518083602001fd5b8060405162461bcd60e51b815260040161096a9190614af5565b60408051608081018252600080825260208201819052918101829052606081019190915290565b6040805160608101909152600081526020810161404f61400d565b815260200161405c61400d565b905290565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201819052610100820183905261012082015261014081019190915290565b5080546000825560020290600052602060002090810190610b6a91905b8082111561412e57805461ffff191681556000600182015560020161410e565b5090565b80356001600160a01b038116811461414957600080fd5b919050565b60008083601f84011261415f578182fd5b5081356001600160401b03811115614175578182fd5b6020830191508360208260051b850101111561321457600080fd5b600082601f8301126141a0578081fd5b815160206001600160401b038211156141bb576141bb614fa0565b6141c9818360051b01614d75565b80838252828201915082860187848660071b89010111156141e8578586fd5b855b8581101561424b57608080838b031215614202578788fd5b61420a614d2a565b8351815286840151878201526040614223818601614326565b908201526060614234858201614326565b9082015285529385019391909101906001016141ea565b5090979650505050505050565b8051801515811461414957600080fd5b600082601f830112614278578081fd5b813561428b61428682614da5565b614d75565b81815284602083860101111561429f578283fd5b816020850160208301379081016020019190915292915050565b600082601f8301126142c9578081fd5b81516142d761428682614da5565b8181528460208386010111156142eb578283fd5b611b9a826020830160208701614f2d565b805161414981614fb6565b805163ffffffff8116811461414957600080fd5b805161414981614fc6565b805160ff8116811461414957600080fd5b600060208284031215614348578081fd5b610e2a82614132565b6000806000806000806000806000806101008b8d031215614370578586fd5b6143798b614132565b995060208b01356001600160401b0380821115614394578788fd5b6143a08e838f0161414e565b909b50995060408d01359150808211156143b8578788fd5b506143c58d828e0161414e565b90985096505060608b01356143d981614fb6565b945060808b0135935060a08b01356143f081614fc6565b8093505060c08b0135915060e08b013590509295989b9194979a5092959850565b60008060408385031215614423578182fd5b61442c83614132565b915060208301356001600160401b03811115614446578182fd5b61445285828601614268565b9150509250929050565b6000806020838503121561446e578182fd5b82356001600160401b03811115614483578283fd5b61448f8582860161414e565b90969095509350505050565b600080600080600080606087890312156144b3578384fd5b86356001600160401b03808211156144c9578586fd5b6144d58a838b0161414e565b909850965060208901359150808211156144ed578586fd5b6144f98a838b0161414e565b90965094506040890135915080821115614511578384fd5b5061451e89828a0161414e565b979a9699509497509295939492505050565b60008060008060008060808789031215614548578384fd5b86356001600160401b038082111561455e578586fd5b61456a8a838b0161414e565b90985096506020890135915080821115614582578586fd5b5061458f89828a0161414e565b90955093505060408701356145a381614fc6565b915060608701356145b381614fc6565b809150509295509295509295565b6000602082840312156145d2578081fd5b5035919050565b6000602082840312156145ea578081fd5b5051919050565b60008060408385031215614603578182fd5b50508035926020909101359150565b60008060208385031215614624578182fd5b82356001600160401b038082111561463a578384fd5b818501915085601f83011261464d578384fd5b81358181111561465b578485fd5b86602082850101111561466c578485fd5b60209290920196919550909350505050565b60006020828403121561468f578081fd5b81356001600160401b038111156146a4578182fd5b611b9a84828501614268565b6000604082840312156146c1578081fd5b604051604081018181106001600160401b03821117156146e3576146e3614fa0565b60405282356146f181614fb6565b81526020928301359281019290925250919050565b60008060006060848603121561471a578081fd5b83516001600160401b0380821115614730578283fd5b908501906101608288031215614744578283fd5b61474c614d52565b61475583614326565b815261476360208401614307565b602082015261477460408401614307565b6040820152614785606084016142fc565b6060820152608083015160808201526147a060a0840161431b565b60a08201526147b160c08401614326565b60c082015260e0830151828111156147c7578485fd5b6147d3898286016142b9565b60e0830152506101006147e7818501614307565b9082015261012083810151838111156147fe578586fd5b61480a8a828701614190565b91830191909152506101408381015190820152945061482b60208701614258565b93506040860151915080821115614840578283fd5b5061484d868287016142b9565b9150509250925092565b600060208284031215614868578081fd5b8135610e2a81614fb6565b600060208284031215614884578081fd5b8151610e2a81614fb6565b600080604083850312156148a1578182fd5b82356148ac81614fb6565b946020939093013593505050565b6000602082840312156148cb578081fd5b610e2a82614307565b6000602082840312156148e5578081fd5b8135610e2a81614fc6565b6000815180845260208085019450808401835b8381101561493757614924878351805161ffff168252602090810151910152565b6040969096019590820190600101614903565b509495945050505050565b6000815180845261495a816020860160208601614f2d565b601f01601f19169290920160200192915050565b8051825260208101516149b46020840182805160070b82526001600160401b036020820151166020830152604081015160030b6040830152606081015160608301525050565b50604081810151805160070b60a085015260208101516001600160401b031660c08501529081015160030b60e08401526060810151610100840152611fd0565b60008251614a06818460208701614f2d565b9190910192915050565b60ff60f81b8360f81b16815260008251614a31816001850160208701614f2d565b919091016001019392505050565b602081526000610e2a60208301846148f0565b604081526000614a6560408301856148f0565b828103602084015261324981856148f0565b6020808252825182820181905260009190848201906040850190845b81811015614aba57614aa683855161496e565b928401926101209290920191600101614a93565b50909695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b602081526000610e2a6020830184614942565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020815260008251602080840152611b9a6040840182614942565b815161ffff1681526020808301519082015260408101610a81565b602081526000825160048110614c3957614c39614f8a565b80602084015250602083015160078110614c5557614c55614f8a565b8060408401525061ffff60408401511660608301526060830151608080840152611b9a60a0840182614942565b6101208101610a81828461496e565b815160070b81526020808301516001600160401b03169082015260408083015160030b908201526060808301519082015260808101610a81565b6020815260008251602080840152611b9a60408401826148f0565b6000808335601e19843603018112614cfc578283fd5b8301803591506001600160401b03821115614d15578283fd5b60200191503681900382131561321457600080fd5b604051608081016001600160401b0381118282101715614d4c57614d4c614fa0565b60405290565b60405161016081016001600160401b0381118282101715614d4c57614d4c614fa0565b604051601f8201601f191681016001600160401b0381118282101715614d9d57614d9d614fa0565b604052919050565b60006001600160401b03821115614dbe57614dbe614fa0565b50601f01601f191660200190565b60008085851115614ddb578182fd5b83861115614de7578182fd5b5050820193919092039150565b60008219821115614e0757614e07614f74565b500190565b600181815b80851115614e47578160001904821115614e2d57614e2d614f74565b80851615614e3a57918102915b93841c9390800290614e11565b509250929050565b6000610e2a8383600082614e6557506001610a81565b81614e7257506000610a81565b8160018114614e885760028114614e9257614eae565b6001915050610a81565b60ff841115614ea357614ea3614f74565b50506001821b610a81565b5060208310610133831016604e8410600b8410161715614ed1575081810a610a81565b614edb8383614e0c565b8060001904821115614eef57614eef614f74565b029392505050565b6000816000190483118215151615614f1157614f11614f74565b500290565b600082821015614f2857614f28614f74565b500390565b60005b83811015614f48578181015183820152602001614f30565b838111156118305750506000910152565b6000600019821415614f6d57614f6d614f74565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b61ffff81168114610b6a57600080fd5b6001600160401b0381168114610b6a57600080fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212209f7afb5640a4e9f94c48fcacfc59de055292f6e8f069b525f3a290f54ac4d50c64736f6c63430008040033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BLAST | 100.00% | $2,140.11 | 0.266 | $569.27 | |
MANTLE | <0.01% | $0.709177 | 0.0001001 | $0.000071 | |
LINEA | <0.01% | $2,139.49 | 0.000000001 | $0.000002 | |
BTTC | <0.01% | $0.000001 | 1 | $0.000001 | |
ETH | <0.01% | $2,140.26 | 0.0000000001 | <$0.000001 | |
SCROLL | <0.01% | $2,139.49 | 0.0000000000000341 | <$0.000001 | |
WEMIX | <0.01% | $0.475501 | 0.0000000000007559 | <$0.000001 | |
BASE | <0.01% | $2,140.23 | 0.000000000000000018 | <$0.000001 | |
OPBNB | <0.01% | $597.43 | 0.000000000000000001 | <$0.000001 |
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.