Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
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 Source Code Verified (Exact Match)
Contract Name:
CometblsClient
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 1000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.8.27; import "@openzeppelin-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgradeable/utils/PausableUpgradeable.sol"; import "./ICS23MembershipVerifier.sol"; import "./Verifier.sol"; import "../core/02-client/ILightClient.sol"; import "../core/24-host/IBCStore.sol"; import "../core/24-host/IBCCommitment.sol"; import "../lib/Common.sol"; import "../lib/ICS23.sol"; struct SignedHeader { uint64 height; uint64 secs; uint64 nanos; bytes32 validatorsHash; bytes32 nextValidatorsHash; bytes32 appHash; } struct Header { SignedHeader signedHeader; uint64 trustedHeight; bytes zeroKnowledgeProof; } struct ClientState { bytes31 chainId; uint64 trustingPeriod; uint64 maxClockDrift; uint64 frozenHeight; uint64 latestHeight; bytes32 contractAddress; } struct ConsensusState { uint64 timestamp; bytes32 appHash; bytes32 nextValidatorsHash; } struct Misbehaviour { Header headerA; Header headerB; } library CometblsClientLib { error ErrNotIBC(); error ErrTrustedConsensusStateNotFound(); error ErrUntrustedHeightLTETrustedHeight(); error ErrUntrustedTimestampLTETrustedTimestamp(); error ErrHeaderExpired(); error ErrMaxClockDriftExceeded(); error ErrInvalidZKP(); error ErrInvalidUntrustedValidatorsHash(); error ErrInvalidMisbehaviourHeadersSequence(); error ErrInvalidMisbehaviour(); error ErrClientFrozen(); error ErrInvalidInitialConsensusState(); function isExpired( uint64 headerTime, uint64 trustingPeriod, uint64 currentTime ) internal pure returns (bool) { return uint256(currentTime) > (uint256(headerTime) + uint256(trustingPeriod)); } function encodeMemory( Header memory header ) internal pure returns (bytes memory) { return abi.encode( header.signedHeader, header.trustedHeight, header.zeroKnowledgeProof ); } function encode( Header calldata header ) internal pure returns (bytes memory) { return abi.encode( header.signedHeader, header.trustedHeight, header.zeroKnowledgeProof ); } function decodeHeader( bytes calldata bz ) internal pure returns (Header calldata) { Header calldata header; assembly { header := bz.offset } return header; } function decodeMisbehaviour( bytes calldata bz ) internal pure returns (Misbehaviour calldata) { Misbehaviour calldata misbehaviour; assembly { misbehaviour := bz.offset } return misbehaviour; } function encodeMemory( ClientState memory clientState ) internal pure returns (bytes memory) { return abi.encode( clientState.chainId, clientState.trustingPeriod, clientState.maxClockDrift, clientState.frozenHeight, clientState.latestHeight, clientState.contractAddress ); } function decodeClientState( bytes calldata bz ) internal pure returns (ClientState calldata) { ClientState calldata clientState; assembly { clientState := bz.offset } return clientState; } function encodeMemory( ConsensusState memory consensusState ) internal pure returns (bytes memory) { return abi.encode( consensusState.timestamp, consensusState.appHash, consensusState.nextValidatorsHash ); } function decodeConsensusState( bytes calldata bz ) internal pure returns (ConsensusState calldata) { ConsensusState calldata consensusState; assembly { consensusState := bz.offset } return consensusState; } function decodeConsensusStateMemory( bytes memory bz ) internal pure returns (ConsensusState memory) { ConsensusState memory consensusState; (uint64 timestamp, bytes32 appHash, bytes32 nextValidatorsHash) = abi.decode(bz, (uint64, bytes32, bytes32)); consensusState.timestamp = timestamp; consensusState.appHash = appHash; consensusState.nextValidatorsHash = nextValidatorsHash; return consensusState; } function commit( ConsensusState memory consensusState ) internal pure returns (bytes32) { return keccak256(encodeMemory(consensusState)); } function commit( ClientState memory clientState ) internal pure returns (bytes32) { return keccak256(encodeMemory(clientState)); } } contract CometblsClient is ILightClient, Initializable, UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeable { using CometblsClientLib for *; address private ibcHandler; mapping(uint32 => ClientState) private clientStates; mapping(uint32 => mapping(uint64 => ConsensusState)) private consensusStates; mapping(uint32 => mapping(uint64 => ProcessedMoment)) private processedMoments; constructor() { _disableInitializers(); } function initialize( address _ibcHandler, address admin ) public initializer { __Ownable_init(admin); ibcHandler = _ibcHandler; } function createClient( uint32 clientId, bytes calldata clientStateBytes, bytes calldata consensusStateBytes ) external override onlyIBC returns (ConsensusStateUpdate memory update) { ClientState calldata clientState = clientStateBytes.decodeClientState(); ConsensusState calldata consensusState = consensusStateBytes.decodeConsensusState(); if (clientState.latestHeight == 0 || consensusState.timestamp == 0) { revert CometblsClientLib.ErrInvalidInitialConsensusState(); } clientStates[clientId] = clientState; consensusStates[clientId][clientState.latestHeight] = consensusState; return ConsensusStateUpdate({ clientStateCommitment: clientState.commit(), consensusStateCommitment: consensusState.commit(), height: clientState.latestHeight }); } function misbehaviour( uint32 clientId, bytes calldata clientMessageBytes ) external override onlyIBC { Misbehaviour calldata m = clientMessageBytes.decodeMisbehaviour(); ClientState storage clientState = clientStates[clientId]; bool fraud = checkMisbehaviour(clientId, clientState, m.headerA, m.headerB); if (!fraud) { revert CometblsClientLib.ErrInvalidMisbehaviour(); } // Similar to tendermint https://github.com/cosmos/ibc-go/blob/bbdcc8c6e965c8a2f607dfb2b61cd13712dd966a/modules/light-clients/07-tendermint/misbehaviour.go#L19 clientState.frozenHeight = 1; } function checkMisbehaviour( uint32 clientId, ClientState storage clientState, Header calldata headerA, Header calldata headerB ) internal returns (bool) { // Ensures that A > B to simplify the misbehaviour of time violation check if (headerA.signedHeader.height < headerB.signedHeader.height) { revert CometblsClientLib.ErrInvalidMisbehaviourHeadersSequence(); } ConsensusState storage consensusStateA = consensusStates[clientId][headerA.trustedHeight]; ConsensusState storage consensusStateB = consensusStates[clientId][headerB.trustedHeight]; // Check that the headers would have been accepted in an update (, uint64 untrustedTimestampA,) = verifyHeader(headerA, consensusStateA, clientState); (, uint64 untrustedTimestampB,) = verifyHeader(headerB, consensusStateB, clientState); if (headerA.signedHeader.height == headerB.signedHeader.height) { bytes32 hashA = keccak256(abi.encode(headerA.signedHeader)); bytes32 hashB = keccak256(abi.encode(headerB.signedHeader)); if (hashA != hashB) { // Misbehaviour of a fork return true; } } else { // Guarantee that A > B if (untrustedTimestampA <= untrustedTimestampB) { // Misbehaviour of time violation return true; } } return false; } function verifyHeader( Header calldata header, ConsensusState storage consensusState, ClientState storage clientState ) internal returns (uint64, uint64, bytes32) { if (consensusState.timestamp == 0) { revert CometblsClientLib.ErrTrustedConsensusStateNotFound(); } uint64 untrustedHeightNumber = header.signedHeader.height; uint64 trustedHeightNumber = header.trustedHeight; if (untrustedHeightNumber <= trustedHeightNumber) { revert CometblsClientLib.ErrUntrustedHeightLTETrustedHeight(); } uint64 trustedTimestamp = consensusState.timestamp; // Normalize to nanosecond because ibc-go recvPacket expects nanos... uint64 untrustedTimestamp = header.signedHeader.secs * 1e9 + header.signedHeader.nanos; if (untrustedTimestamp <= trustedTimestamp) { revert CometblsClientLib.ErrUntrustedTimestampLTETrustedTimestamp(); } // Normalize to nanosecond because ibc-go recvPacket expects nanos... uint64 currentTime = uint64(block.timestamp * 1e9); if ( CometblsClientLib.isExpired( untrustedTimestamp, clientState.trustingPeriod, currentTime ) ) { revert CometblsClientLib.ErrHeaderExpired(); } uint64 maxClockDrift = currentTime + clientState.maxClockDrift; if (untrustedTimestamp >= maxClockDrift) { revert CometblsClientLib.ErrMaxClockDriftExceeded(); } /* We want to verify that 1/3 of trusted valset & 2/3 of untrusted valset signed. In adjacent verification, trusted vals = untrusted vals. In non adjacent verification, untrusted vals are coming from the untrusted header. */ bytes32 trustedValidatorsHash = consensusState.nextValidatorsHash; bytes32 untrustedValidatorsHash; bool adjacent = untrustedHeightNumber == trustedHeightNumber + 1; if (adjacent) { if (header.signedHeader.validatorsHash != trustedValidatorsHash) { revert CometblsClientLib.ErrInvalidUntrustedValidatorsHash(); } } bool ok = internalVerifyZKP( header.zeroKnowledgeProof, clientState.chainId, trustedValidatorsHash, header.signedHeader ); if (!ok) { revert CometblsClientLib.ErrInvalidZKP(); } return (untrustedHeightNumber, untrustedTimestamp, untrustedValidatorsHash); } function updateClient( uint32 clientId, bytes calldata clientMessageBytes ) external override onlyIBC returns (ConsensusStateUpdate memory) { ClientState storage clientState = clientStates[clientId]; if (clientState.frozenHeight > 0) { revert CometblsClientLib.ErrClientFrozen(); } Header calldata header = clientMessageBytes.decodeHeader(); ConsensusState storage consensusState = consensusStates[clientId][header.trustedHeight]; (uint64 untrustedHeightNumber, uint64 untrustedTimestamp,) = verifyHeader(header, consensusState, clientState); // Update states if (untrustedHeightNumber > clientState.latestHeight) { clientState.latestHeight = untrustedHeightNumber; } consensusState = consensusStates[clientId][untrustedHeightNumber]; consensusState.timestamp = untrustedTimestamp; consensusState.appHash = header.signedHeader.appHash; consensusState.nextValidatorsHash = header.signedHeader.nextValidatorsHash; return ConsensusStateUpdate({ clientStateCommitment: clientState.commit(), consensusStateCommitment: consensusState.commit(), height: untrustedHeightNumber }); } function verifyMembership( uint32 clientId, uint64 height, bytes calldata proof, bytes calldata path, bytes calldata value ) external virtual returns (bool) { if (isFrozenImpl(clientId)) { revert CometblsClientLib.ErrClientFrozen(); } bytes32 contractAddress = clientStates[clientId].contractAddress; bytes32 appHash = consensusStates[clientId][height].appHash; return ICS23MembershipVerifier.verifyMembership( appHash, proof, abi.encodePacked(IBCStoreLib.COMMITMENT_PREFIX), abi.encodePacked( IBCStoreLib.COMMITMENT_PREFIX_PATH, contractAddress, path ), value ); } function verifyNonMembership( uint32 clientId, uint64 height, bytes calldata proof, bytes calldata path ) external virtual returns (bool) { if (isFrozenImpl(clientId)) { revert CometblsClientLib.ErrClientFrozen(); } bytes32 contractAddress = clientStates[clientId].contractAddress; bytes32 appHash = consensusStates[clientId][height].appHash; return ICS23MembershipVerifier.verifyNonMembership( appHash, proof, abi.encodePacked(IBCStoreLib.COMMITMENT_PREFIX), abi.encodePacked( IBCStoreLib.COMMITMENT_PREFIX_PATH, contractAddress, path ) ); } function getClientState( uint32 clientId ) external view returns (bytes memory) { return clientStates[clientId].encodeMemory(); } function getConsensusState( uint32 clientId, uint64 height ) external view returns (bytes memory) { return consensusStates[clientId][height].encodeMemory(); } function getTimestampAtHeight( uint32 clientId, uint64 height ) external view override returns (uint64) { return consensusStates[clientId][height].timestamp; } function getLatestHeight( uint32 clientId ) external view override returns (uint64) { return clientStates[clientId].latestHeight; } function isFrozen( uint32 clientId ) external view virtual returns (bool) { return isFrozenImpl(clientId); } function isFrozenImpl( uint32 clientId ) internal view returns (bool) { return clientStates[clientId].frozenHeight > 0; } // ZKP VERIFICATION uint256 constant PRIME_R = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 constant PRIME_R_MINUS_ONE = PRIME_R - 1; bytes constant HMAC_I = hex"75595B5342747A653636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636"; bytes constant HMAC_O = hex"1F333139281E100F5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C"; function hmac_keccak( bytes memory message ) internal pure returns (bytes32) { return keccak256( abi.encodePacked( HMAC_O, keccak256(abi.encodePacked(HMAC_I, message)) ) ); } // Union whitepaper: (1) H_{hmac_r} function hashToField( bytes memory message ) internal pure returns (uint256) { return (uint256(hmac_keccak(message)) % PRIME_R_MINUS_ONE) + 1; } struct ZKP { uint256[8] proof; uint256[2] proofCommitment; uint256[2] proofCommitmentPOK; } function verifyZKP( bytes calldata zkpBytes, bytes31 chainId, bytes32 trustedValidatorsHash, SignedHeader calldata header ) public virtual returns (bool) { return internalVerifyZKP(zkpBytes, chainId, trustedValidatorsHash, header); } function internalVerifyZKP( bytes calldata zkpBytes, bytes31 chainId, bytes32 trustedValidatorsHash, SignedHeader calldata header ) internal virtual returns (bool) { ZKP calldata zkp; assembly { zkp := zkpBytes.offset } uint256 commitmentHash = hashToField(abi.encodePacked(zkp.proofCommitment)); // Drop the most significant byte to fit in F_r bytes32 inputsHash = sha256( abi.encodePacked( bytes32(uint256(uint248(chainId))), bytes32(uint256(header.height)), bytes32(uint256(header.secs)), bytes32(uint256(header.nanos)), header.validatorsHash, header.nextValidatorsHash, header.appHash, trustedValidatorsHash ) ) & 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; uint256[2] memory publicInputs = [ uint256(inputsHash), // Gnark commitment API extend internal inputs with the following commitment hash and proof commitment // See https://github.com/ConsenSys/gnark/issues/652 commitmentHash ]; return Verifier.verifyProof( zkp.proof, zkp.proofCommitment, zkp.proofCommitmentPOK, publicInputs ); } function _authorizeUpgrade( address newImplementation ) internal override onlyOwner {} function _onlyIBC() internal view { if (msg.sender != ibcHandler) { revert CometblsClientLib.ErrNotIBC(); } } modifier onlyIBC() { _onlyIBC(); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "@openzeppelin/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./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. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @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() { _checkProxy(); _; } /** * @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() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @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 notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC1967-compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../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. * * The initial owner is set to the address provided by the deployer. 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 { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling 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 { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Pausable struct PausableStorage { bool _paused; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300; function _getPausableStorage() private pure returns (PausableStorage storage $) { assembly { $.slot := PausableStorageLocation } } /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { PausableStorage storage $ = _getPausableStorage(); $._paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { PausableStorage storage $ = _getPausableStorage(); return $._paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = false; emit Unpaused(_msgSender()); } }
pragma solidity ^0.8.27; import "../lib/ICS23.sol"; import "../lib/UnionICS23.sol"; library ICS23MembershipVerifier { function verifyMembership( bytes32 root, bytes calldata proof, bytes memory prefix, bytes memory path, bytes calldata value ) internal pure returns (bool) { UnionIcs23.ExistenceProof[2] calldata existenceProof; assembly { existenceProof := proof.offset } return Ics23.verifyChainedMembership( existenceProof, root, prefix, path, value ) == Ics23.VerifyChainedMembershipError.None; } struct NonMembershipProof { UnionIcs23.NonExistenceProof nonexist; UnionIcs23.ExistenceProof exist; } function verifyNonMembership( bytes32 root, bytes calldata proof, bytes memory prefix, bytes memory path ) internal pure returns (bool) { NonMembershipProof calldata nonexistenceProof; assembly { nonexistenceProof := proof.offset } return Ics23.verifyChainedNonMembership( nonexistenceProof.nonexist, nonexistenceProof.exist, root, prefix, path ) == Ics23.VerifyChainedNonMembershipError.None; } }
pragma solidity ^0.8.27; /// @title Groth16 verifier template. /// @author Remco Bloemen /// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed /// (256 bytes) and compressed (128 bytes) format. library Verifier { // Addresses of precompiles uint256 constant PRECOMPILE_MODEXP = 0x05; uint256 constant PRECOMPILE_ADD = 0x06; uint256 constant PRECOMPILE_MUL = 0x07; uint256 constant PRECOMPILE_VERIFY = 0x08; // Base field Fp order P and scalar field Fr order R. // For BN254 these are computed as follows: // t = 4965661367192848881 // P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1 // R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1 uint256 constant P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47; uint256 constant R = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001; // Extension field Fp2 = Fp[i] / (i² + 1) // Note: This is the complex extension field of Fp with i² = -1. // Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i. // Note: The order of Fp2 elements is *opposite* that of the pairing contract, which // expects Fp2 elements in order (a₁, a₀). This is also the order in which // Fp2 elements are encoded in the public interface as this became convention. // Constants in Fp uint256 constant FRACTION_1_2_FP = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea4; uint256 constant FRACTION_27_82_FP = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5; uint256 constant FRACTION_3_82_FP = 0x2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775; // Exponents for inversions and square roots mod P uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2 uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4; // Verifying key uint256 constant ALPHA_X = 0x245229d9b076b3c0e8a4d70bde8c1cccffa08a9fae7557b165b3b0dbd653e2c7; uint256 constant ALPHA_Y = 0x253ec85988dbb84e46e94b5efa3373b47a000b4ac6c86b2d4b798d274a182302; uint256 constant BETA_NEG_X_0 = 0x2424bcc1f60a5472685fd50705b2809626e170120acaf441e133a2bd5e61d244; uint256 constant BETA_NEG_X_1 = 0x07090a82e8fabbd39299be24705b92cf208ee8b3487f6f2b39ff27978a29a1db; uint256 constant BETA_NEG_Y_0 = 0x04ddc8d30d5c438ca34091c5d2c6ded571382cba2b3c4fdc4222df2938b4e51e; uint256 constant BETA_NEG_Y_1 = 0x25833b15e156ae01f2741f4f4120ddb466c52eb83a959f79eb99b23caa7fbf1d; uint256 constant GAMMA_NEG_X_0 = 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed; uint256 constant GAMMA_NEG_X_1 = 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2; uint256 constant GAMMA_NEG_Y_0 = 0x1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d; uint256 constant GAMMA_NEG_Y_1 = 0x275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec; uint256 constant DELTA_NEG_X_0 = 0x02aca5d2a73f8d34e4b26eee3932365e6526c8d5e2f3347d679c2cb1867104dc; uint256 constant DELTA_NEG_X_1 = 0x07b8dbefa90bde075a26318e5066db729155514e3c06b888d4e03c56d82c97e6; uint256 constant DELTA_NEG_Y_0 = 0x1696ccafaefe49a5d8bad8e79630e19b25e5392a203aff0042d0216f254806f5; uint256 constant DELTA_NEG_Y_1 = 0x2edb19cbb2b6ad0c98fdd7d1845500c26e497dc35e4cdc1cb02cc65dc4ba1bf2; uint256 constant CONSTANT_X = 0x2f5d8a3817f21d3e453573c90c3cc47b7ff235fad7bdfbd59bbd6ae5d153273e; uint256 constant CONSTANT_Y = 0x147fa22142b1fd86ce75fc87230a0feac8765d02938784dcfc828d17d7e7c432; uint256 constant PUB_0_X = 0x2a81b98e1c997bd01a20893a08a46c6804493e838c1a0ff6c8c069ef5ab66b9a; uint256 constant PUB_0_Y = 0x276938ada8075cec20d4d6a1f157ec94cc7ba6207c98576e98c1ad9d6378fb6f; uint256 constant PUB_1_X = 0x179496ce140df89ce35c5ee7fb496efdffda5e5d3b95ff9116e2e5df96b36ab7; uint256 constant PUB_1_Y = 0x0326e7d44688ce5903676b7d646e46a5938c8e5fd8cd54e4d5aa3300649f3cfc; uint256 constant PEDERSEN_G_X_0 = 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed; uint256 constant PEDERSEN_G_X_1 = 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2; uint256 constant PEDERSEN_G_Y_0 = 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa; uint256 constant PEDERSEN_G_Y_1 = 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b; uint256 constant PEDERSEN_G_ROOT_SIGMA_NEG_X_0 = 0x02aca5d2a73f8d34e4b26eee3932365e6526c8d5e2f3347d679c2cb1867104dc; uint256 constant PEDERSEN_G_ROOT_SIGMA_NEG_X_1 = 0x07b8dbefa90bde075a26318e5066db729155514e3c06b888d4e03c56d82c97e6; uint256 constant PEDERSEN_G_ROOT_SIGMA_NEG_Y_0 = 0x1696ccafaefe49a5d8bad8e79630e19b25e5392a203aff0042d0216f254806f5; uint256 constant PEDERSEN_G_ROOT_SIGMA_NEG_Y_1 = 0x2edb19cbb2b6ad0c98fdd7d1845500c26e497dc35e4cdc1cb02cc65dc4ba1bf2; /// Compute the public input linear combination. /// @notice Reverts with PublicInputNotInField if the input is not in the field. /// @notice Computes the multi-scalar-multiplication of the public input /// elements and the verification key including the constant term. /// @param input The public inputs. These are elements of the scalar field Fr. /// @return success the result of the msm. /// @return x The X coordinate of the resulting G1 point. /// @return y The Y coordinate of the resulting G1 point. function publicInputMSM( uint256[2] calldata proofCommitment, uint256[2] memory input ) internal view returns (bool success, uint256 x, uint256 y) { // Note: The ECMUL precompile does not reject unreduced values, so we check this. // Note: Unrolling this loop does not cost much extra in code-size, the bulk of the // code-size is in the PUB_ constants. // ECMUL has input (x, y, scalar) and output (x', y'). // ECADD has input (x1, y1, x2, y2) and output (x', y'). // We call them such that ecmul output is already in the second point // argument to ECADD so we can have a tight loop. success = true; assembly ("memory-safe") { let f := mload(0x40) let g := add(f, 0x40) let s mstore(f, CONSTANT_X) mstore(add(f, 0x20), CONSTANT_Y) // Add the proof commitment calldatacopy(g, proofCommitment, 0x40) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) mstore(g, PUB_0_X) mstore(add(g, 0x20), PUB_0_Y) s := mload(input) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) mstore(g, PUB_1_X) mstore(add(g, 0x20), PUB_1_Y) s := mload(add(input, 32)) mstore(add(g, 0x40), s) success := and(success, lt(s, R)) success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) x := mload(f) y := mload(add(f, 0x20)) } } function verifyProofCommitmentPOK( uint256[2] calldata proofCommitment, uint256[2] calldata proofCommitmentPOK ) internal view returns (bool) { bool success = true; assembly ("memory-safe") { let f := mload(0x40) calldatacopy(f, proofCommitment, 0x40) mstore(add(f, 0x40), PEDERSEN_G_X_1) mstore(add(f, 0x60), PEDERSEN_G_X_0) mstore(add(f, 0x80), PEDERSEN_G_Y_1) mstore(add(f, 0xA0), PEDERSEN_G_Y_0) calldatacopy(add(f, 0xC0), proofCommitmentPOK, 0x40) mstore(add(f, 0x100), PEDERSEN_G_ROOT_SIGMA_NEG_X_1) mstore(add(f, 0x120), PEDERSEN_G_ROOT_SIGMA_NEG_X_0) mstore(add(f, 0x140), PEDERSEN_G_ROOT_SIGMA_NEG_Y_1) mstore(add(f, 0x160), PEDERSEN_G_ROOT_SIGMA_NEG_Y_0) success := staticcall(gas(), PRECOMPILE_VERIFY, f, 0x180, f, 0x20) success := and(success, mload(f)) } return success; } /// Verify an uncompressed Groth16 proof. /// @notice Reverts with InvalidProof if the proof is invalid or /// with PublicInputNotInField the public input is not reduced. /// @notice There is no return value. If the function does not revert, the /// proof was successfully verified. /// @param proof the points (A, B, C) in EIP-197 format matching the output /// of compressProof. /// @param input the public input field elements in the scalar field Fr. /// Elements must be reduced. function verifyProof( uint256[8] calldata proof, uint256[2] calldata proofCommitment, uint256[2] calldata proofCommitmentPOK, uint256[2] memory input ) internal view returns (bool) { (bool success, uint256 x, uint256 y) = publicInputMSM(proofCommitment, input); if (!success) { return false; } if (!verifyProofCommitmentPOK(proofCommitment, proofCommitmentPOK)) { return false; } // Note: The precompile expects the F2 coefficients in big-endian order. // Note: The pairing precompile rejects unreduced values, so we won't check that here. assembly ("memory-safe") { let f := mload(0x40) // Free memory pointer. // Copy points (A, B, C) to memory. They are already in correct encoding. // This is pairing e(A, B) and G1 of e(C, -δ). calldatacopy(f, proof, 0x100) // Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory. // OPT: This could be better done using a single codecopy, but // Solidity (unlike standalone Yul) doesn't provide a way to // to do this. mstore(add(f, 0x100), DELTA_NEG_X_1) mstore(add(f, 0x120), DELTA_NEG_X_0) mstore(add(f, 0x140), DELTA_NEG_Y_1) mstore(add(f, 0x160), DELTA_NEG_Y_0) mstore(add(f, 0x180), ALPHA_X) mstore(add(f, 0x1a0), ALPHA_Y) mstore(add(f, 0x1c0), BETA_NEG_X_1) mstore(add(f, 0x1e0), BETA_NEG_X_0) mstore(add(f, 0x200), BETA_NEG_Y_1) mstore(add(f, 0x220), BETA_NEG_Y_0) mstore(add(f, 0x240), x) mstore(add(f, 0x260), y) mstore(add(f, 0x280), GAMMA_NEG_X_1) mstore(add(f, 0x2a0), GAMMA_NEG_X_0) mstore(add(f, 0x2c0), GAMMA_NEG_Y_1) mstore(add(f, 0x2e0), GAMMA_NEG_Y_0) // Check pairing equation. success := staticcall(gas(), PRECOMPILE_VERIFY, f, 0x300, f, 0x20) // Also check returned value (both are either 1 or 0). success := and(success, mload(f)) } return success; } }
pragma solidity ^0.8.27; import "../Types.sol"; struct ConsensusStateUpdate { bytes32 clientStateCommitment; bytes32 consensusStateCommitment; uint64 height; } /** * @dev This defines an interface for Light Client contract can be integrated with ibc-solidity. * You can register the Light Client contract that implements this through `registerClient` on IBCHandler. */ interface ILightClient { /** * @dev createClient creates a new client with the given state. * If succeeded, it returns a commitment for the initial state. */ function createClient( uint32 clientId, bytes calldata clientStateBytes, bytes calldata consensusStateBytes ) external returns (ConsensusStateUpdate memory update); /** * @dev getTimestampAtHeight returns the timestamp of the consensus state at the given height. */ function getTimestampAtHeight( uint32 clientId, uint64 height ) external view returns (uint64); /** * @dev getLatestHeight returns the latest height of the client state corresponding to `clientId`. */ function getLatestHeight( uint32 clientId ) external view returns (uint64 height); /** * @dev updateClient updates the client corresponding to `clientId`. * If succeeded, it returns a commitment for the updated state. * If there are no updates for consensus state, this function should returns an empty array as `updates`. * * NOTE: updateClient is intended to perform the followings: * 1. verify a given client message(e.g. header) * 2. check misbehaviour such like duplicate block height * 3. if misbehaviour is found, update state accordingly and return * 4. update state(s) with the client message * 5. persist the state(s) on the host */ function updateClient( uint32 clientId, bytes calldata clientMessageBytes ) external returns (ConsensusStateUpdate memory update); /** * @dev misbehaviour is used for submitting a misbehaviour to `clientId`. * If succeeded, the client should freeze itself to prevent getting further updates. */ function misbehaviour( uint32 clientId, bytes calldata clientMessageBytes ) external; /** * @dev verifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. * The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). */ function verifyMembership( uint32 clientId, uint64 height, bytes calldata proof, bytes calldata path, bytes calldata value ) external returns (bool); /** * @dev verifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. * The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). */ function verifyNonMembership( uint32 clientId, uint64 height, bytes calldata proof, bytes calldata path ) external returns (bool); /** * @dev getClientState returns the clientState corresponding to `clientId`. */ function getClientState( uint32 clientId ) external view returns (bytes memory); /** * @dev getConsensusState returns the consensusState corresponding to `clientId` and `height`. */ function getConsensusState( uint32 clientId, uint64 height ) external view returns (bytes memory); /** * @dev isFrozen returns whether the `clientId` is frozen or not. */ function isFrozen( uint32 clientId ) external view returns (bool); }
pragma solidity ^0.8.27; import "../02-client/ILightClient.sol"; import "../05-port/IIBCModule.sol"; import "../Types.sol"; library IBCStoreLib { string public constant COMMITMENT_PREFIX = "wasm"; bytes1 public constant COMMITMENT_PREFIX_PATH = 0x03; } abstract contract IBCStore { // Commitments // keccak256(IBC-compatible-store-path) => keccak256(IBC-compatible-commitment) mapping(bytes32 => bytes32) public commitments; // ClientType -> Address mapping(string => address) public clientRegistry; // ClientId -> ClientType mapping(uint32 => string) public clientTypes; // ClientId -> Address mapping(uint32 => address) public clientImpls; // ConnectionId -> Connection mapping(uint32 => IBCConnection) public connections; // ChannelId -> Channel mapping(uint32 => IBCChannel) public channels; // ChannelId -> PortId mapping(uint32 => address) public channelOwner; // Sequences for identifier bytes32 constant nextClientSequencePath = keccak256("nextClientSequence"); bytes32 constant nextConnectionSequencePath = keccak256("nextConnectionSequence"); bytes32 constant nextChannelSequencePath = keccak256("nextChannelSequence"); function getClient( uint32 clientId ) public view returns (ILightClient) { return getClientInternal(clientId); } function getClientInternal( uint32 clientId ) internal view returns (ILightClient) { address clientImpl = clientImpls[clientId]; if (clientImpl == address(0)) { revert IBCErrors.ErrClientNotFound(); } return ILightClient(clientImpl); } function lookupModuleByChannel( uint32 channelId ) internal view virtual returns (IIBCModule) { address module = channelOwner[channelId]; if (module == address(0)) { revert IBCErrors.ErrModuleNotFound(); } return IIBCModule(module); } function claimChannel(address portId, uint32 channelId) internal { channelOwner[channelId] = portId; } function authenticateChannelOwner( uint32 channelId ) internal view returns (bool) { return msg.sender == channelOwner[channelId]; } function ensureConnectionState( uint32 connectionId ) internal view returns (uint32) { IBCConnection storage connection = connections[connectionId]; if (connection.state != IBCConnectionState.Open) { revert IBCErrors.ErrInvalidConnectionState(); } return connection.clientId; } function ensureChannelState( uint32 channelId ) internal view returns (IBCChannel storage) { IBCChannel storage channel = channels[channelId]; if (channel.state != IBCChannelState.Open) { revert IBCErrors.ErrInvalidChannelState(); } return channel; } }
pragma solidity ^0.8.27; library IBCCommitment { uint256 public constant CLIENT_STATE = 0x00; uint256 public constant CONSENSUS_STATE = 0x01; uint256 public constant CONNECTIONS = 0x02; uint256 public constant CHANNELS = 0x03; uint256 public constant PACKETS = 0x04; uint256 public constant PACKET_ACKS = 0x05; function clientStatePath( uint32 clientId ) internal pure returns (bytes memory) { return abi.encode(CLIENT_STATE, clientId); } function consensusStatePath( uint32 clientId, uint64 height ) internal pure returns (bytes memory) { return abi.encode(CONSENSUS_STATE, clientId, height); } function connectionPath( uint32 connectionId ) internal pure returns (bytes memory) { return abi.encode(CONNECTIONS, connectionId); } function channelPath( uint32 channelId ) internal pure returns (bytes memory) { return abi.encode(CHANNELS, channelId); } function batchPacketsCommitmentPath( uint32 channelId, bytes32 batchHash ) internal pure returns (bytes memory) { return abi.encode(PACKETS, channelId, batchHash); } function batchReceiptsCommitmentPath( uint32 channelId, bytes32 batchHash ) internal pure returns (bytes memory) { return abi.encode(PACKET_ACKS, channelId, batchHash); } // Key generators for Commitment mapping function clientStateCommitmentKey( uint32 clientId ) internal pure returns (bytes32) { return keccak256(clientStatePath(clientId)); } function consensusStateCommitmentKey( uint32 clientId, uint64 height ) internal pure returns (bytes32) { return keccak256(consensusStatePath(clientId, height)); } function connectionCommitmentKey( uint32 connectionId ) internal pure returns (bytes32) { return keccak256(connectionPath(connectionId)); } function channelCommitmentKey( uint32 channelId ) internal pure returns (bytes32) { return keccak256(channelPath(channelId)); } function batchPacketsCommitmentKey( uint32 channelId, bytes32 batchHash ) internal pure returns (bytes32) { return keccak256(batchPacketsCommitmentPath(channelId, batchHash)); } function batchReceiptsCommitmentKey( uint32 channelId, bytes32 batchHash ) internal pure returns (bytes32) { return keccak256(batchReceiptsCommitmentPath(channelId, batchHash)); } }
pragma solidity ^0.8.27; struct ProcessedMoment { uint256 timestamp; uint256 height; }
pragma solidity ^0.8.27; import {Math} from "@openzeppelin/utils/math/Math.sol"; import "./UnionICS23.sol"; library Ics23 { enum VerifyChainedNonMembershipError { None, NonExistenceProofIsNil, ExistenceProofIsNil, InvalidProofRoot, KeyMismatch, ValueMismatch, InvalidSpec, InvalidIntermediateProofRoot, IntermateProofRootMismatch, RootMismatch, VerifyLeft, VerifyRight, LeftAndRightKeyEmpty, RightKeyRange, LeftKeyRange, RightProofLeftMost, LeftProofRightMost, IsLeftNeighbor } function verifyChainedNonMembership( UnionIcs23.NonExistenceProof calldata nonExistProof, UnionIcs23.ExistenceProof calldata existProof, bytes32 root, bytes memory prefix, bytes memory key ) internal pure returns (VerifyChainedNonMembershipError) { (bytes32 subroot, Proof.CalculateRootError rCode) = Proof.calculateRoot(nonExistProof); if (rCode != Proof.CalculateRootError.None) { return VerifyChainedNonMembershipError.InvalidProofRoot; } Proof.VerifyNonExistenceError vCode = Proof.verify( nonExistProof, UnionIcs23.getIavlProofSpec(), subroot, key ); // Map non existence error to non membership error if (vCode != Proof.VerifyNonExistenceError.None) { if (vCode == Proof.VerifyNonExistenceError.VerifyLeft) { return VerifyChainedNonMembershipError.VerifyLeft; } else if ( vCode == Proof.VerifyNonExistenceError.LeftAndRightKeyEmpty ) { return VerifyChainedNonMembershipError.LeftAndRightKeyEmpty; } else if (vCode == Proof.VerifyNonExistenceError.RightKeyRange) { return VerifyChainedNonMembershipError.RightKeyRange; } else if (vCode == Proof.VerifyNonExistenceError.LeftKeyRange) { return VerifyChainedNonMembershipError.LeftKeyRange; } else if ( vCode == Proof.VerifyNonExistenceError.RightProofLeftMost ) { return VerifyChainedNonMembershipError.RightProofLeftMost; } else if ( vCode == Proof.VerifyNonExistenceError.LeftProofRightMost ) { return VerifyChainedNonMembershipError.LeftProofRightMost; } else if (vCode == Proof.VerifyNonExistenceError.IsLeftNeighbor) { return VerifyChainedNonMembershipError.IsLeftNeighbor; } revert( "verifyChainedNonMembership: non exhaustive pattern matching on VerifyNonExistenceError" ); } bytes32 subroot2; (subroot2, rCode) = Proof.calculateRoot(existProof); if (rCode != Proof.CalculateRootError.None) { return VerifyChainedNonMembershipError.InvalidProofRoot; } // We don't want the above root calculation to be done again. Since we calculated it, we also don't // need to check it against anything. Proof.VerifyExistenceError mCode = Proof.verifyNoRootCheck( existProof, UnionIcs23.getTendermintProofSpec(), prefix, abi.encodePacked(subroot) ); if (mCode != Proof.VerifyExistenceError.None) { if (mCode == Proof.VerifyExistenceError.KeyNotMatching) { return VerifyChainedNonMembershipError.KeyMismatch; } else if (mCode == Proof.VerifyExistenceError.ValueNotMatching) { return VerifyChainedNonMembershipError.ValueMismatch; } else if (mCode == Proof.VerifyExistenceError.CheckSpec) { return VerifyChainedNonMembershipError.InvalidSpec; } else if (mCode == Proof.VerifyExistenceError.CalculateRoot) { return VerifyChainedNonMembershipError.InvalidIntermediateProofRoot; } else if (mCode == Proof.VerifyExistenceError.RootNotMatching) { return VerifyChainedNonMembershipError.IntermateProofRootMismatch; } revert( "verifyChainedNonMembership: non exhaustive pattern matching on VerifyNonExistenceError" ); } if (root != subroot2) { return VerifyChainedNonMembershipError.RootMismatch; } return VerifyChainedNonMembershipError.None; } enum VerifyChainedMembershipError { None, ExistenceProofIsNil, InvalidProofRoot, KeyMismatch, ValueMismatch, InvalidSpec, InvalidIntermediateProofRoot, IntermateProofRootMismatch, RootMismatch } function verifyChainedMembership( UnionIcs23.ExistenceProof[2] calldata proofs, bytes32 root, bytes memory prefix, bytes memory key, bytes calldata value ) internal pure returns (VerifyChainedMembershipError) { (bytes32 subroot, Proof.CalculateRootError rCode) = Proof.calculateRoot(proofs[0]); if (rCode != Proof.CalculateRootError.None) { return VerifyChainedMembershipError.InvalidProofRoot; } // We don't want the above root calculation to be done again. Since we calculated it, we also don't // need to check it against anything. Proof.VerifyExistenceError vCode = Proof.verifyNoRootCheck( proofs[0], UnionIcs23.getIavlProofSpec(), key, value ); if (vCode != Proof.VerifyExistenceError.None) { return convertExistenceError(vCode); } // This will check whether the calculated root of `proofs[1]` matches the `root` vCode = Proof.verify( proofs[1], UnionIcs23.getTendermintProofSpec(), root, prefix, abi.encodePacked(subroot) ); if (vCode != Proof.VerifyExistenceError.None) { return convertExistenceError(vCode); } return VerifyChainedMembershipError.None; } function convertExistenceError( Proof.VerifyExistenceError vCode ) internal pure returns (VerifyChainedMembershipError) { if (vCode == Proof.VerifyExistenceError.KeyNotMatching) { return VerifyChainedMembershipError.KeyMismatch; } else if (vCode == Proof.VerifyExistenceError.ValueNotMatching) { return VerifyChainedMembershipError.ValueMismatch; } else if (vCode == Proof.VerifyExistenceError.CheckSpec) { return VerifyChainedMembershipError.InvalidSpec; } else if (vCode == Proof.VerifyExistenceError.CalculateRoot) { return VerifyChainedMembershipError.InvalidIntermediateProofRoot; } else if (vCode == Proof.VerifyExistenceError.RootNotMatching) { return VerifyChainedMembershipError.IntermateProofRootMismatch; } revert( "verifyChainedMembership: non exhaustive pattern matching on VerifyExistenceError" ); } function isLeft( UnionIcs23.ExistenceProof calldata left, bytes calldata key ) private pure returns (bool) { // CosmosIcs23V1ExistenceProof.isNil does not work return UnionIcs23.empty(left) || Ops.compare(left.key, key) < 0; } function isRight( UnionIcs23.ExistenceProof calldata right, bytes calldata key ) private pure returns (bool) { // CosmosIcs23V1ExistenceProof.isNil does not work return UnionIcs23.empty(right) || Ops.compare(right.key, key) > 0; } } library Ops { enum ApplyLeafOpError { None, KeyLength, ValueLength } function _sz_varint( uint256 i ) internal pure returns (uint256) { uint256 count = 1; assembly { i := shr(7, i) for {} gt(i, 0) {} { i := shr(7, i) count := add(count, 1) } } return count; } function _encode_varint( uint256 x, uint256 p, bytes memory bs ) internal pure returns (uint256) { /** * Refer to https://developers.google.com/protocol-buffers/docs/encoding */ uint256 sz = 0; assembly { let bsptr := add(bs, p) let byt := and(x, 0x7f) for {} gt(shr(7, x), 0) {} { mstore8(bsptr, or(0x80, byt)) bsptr := add(bsptr, 1) sz := add(sz, 1) x := shr(7, x) byt := and(x, 0x7f) } mstore8(bsptr, byt) sz := add(sz, 1) } return sz; } // LeafOp operations function applyLeafOp( bytes calldata prefix, bytes calldata key, bytes calldata value ) internal pure returns (bytes32, ApplyLeafOpError) { //require(key.length > 0); // dev: Leaf op needs key if (key.length == 0) return ("", ApplyLeafOpError.KeyLength); //require(value.length > 0); // dev: Leaf op needs value if (value.length == 0) return ("", ApplyLeafOpError.ValueLength); // tm/iavl specs set hashOp for prehash_key to NOOP and lengthOp to VAR_PROTO bytes memory encodedKey = new bytes(_sz_varint(key.length)); _encode_varint(key.length, 32, encodedKey); // tm/iavl specs set hashOp for prehash_value to SHA256 and lengthOp to VAR_PROTO bytes32 hashedValue = sha256(value); bytes memory encodedValue = new bytes(_sz_varint(32)); _encode_varint(32, 32, encodedValue); bytes32 data = sha256( abi.encodePacked(prefix, encodedKey, key, encodedValue, hashedValue) ); return (data, ApplyLeafOpError.None); } enum CheckAgainstSpecError { None, MinPrefixLength, HasPrefix, MaxPrefixLength } enum ApplyInnerOpError { None, ChildLength, DoHash } // InnerOp operations function applyOp( UnionIcs23.InnerOp calldata innerOp, bytes32 child ) internal pure returns (bytes32, ApplyInnerOpError) { //require(child.length > 0); // dev: Inner op needs child value if (child.length == 0) return ("", ApplyInnerOpError.ChildLength); bytes memory preImage = abi.encodePacked(innerOp.prefix, child, innerOp.suffix); // inner_spec.hash is always SHA256 in the tm/iavl specs return (sha256(preImage), ApplyInnerOpError.None); } function compare( bytes memory a, bytes calldata b ) internal pure returns (int256) { uint256 minLen = Math.min(a.length, b.length); for (uint256 i; i < minLen; i++) { bytes1 ai = a[i]; bytes1 bi = b[i]; if (ai < bi) { return -1; } else if (ai > bi) { return 1; } } if (a.length > minLen) { return 1; } if (b.length > minLen) { return -1; } return 0; } } library Proof { bytes constant empty = new bytes(0); enum VerifyExistenceError { None, KeyNotMatching, ValueNotMatching, CheckSpec, CalculateRoot, RootNotMatching } function verifyNoRootCheck( UnionIcs23.ExistenceProof calldata proof, UnionIcs23.ProofSpec memory spec, bytes memory key, bytes memory value ) internal pure returns (VerifyExistenceError) { //require(BytesLib.equal(proof.key, key)); // dev: Provided key doesn't match proof if (keccak256(proof.key) != keccak256(key)) { return VerifyExistenceError.KeyNotMatching; } //require(BytesLib.equal(proof.value, value)); // dev: Provided value doesn't match proof if (keccak256(proof.value) != keccak256(value)) { return VerifyExistenceError.ValueNotMatching; } CheckAgainstSpecError cCode = checkAgainstSpec(proof, spec); if (cCode != CheckAgainstSpecError.None) { return VerifyExistenceError.CheckSpec; } return VerifyExistenceError.None; } // ExistenceProof function verify( UnionIcs23.ExistenceProof calldata proof, UnionIcs23.ProofSpec memory spec, bytes32 commitmentRoot, bytes memory key, bytes memory value ) internal pure returns (VerifyExistenceError) { //require(BytesLib.equal(proof.key, key)); // dev: Provided key doesn't match proof if (keccak256(proof.key) != keccak256(key)) { return VerifyExistenceError.KeyNotMatching; } //require(BytesLib.equal(proof.value, value)); // dev: Provided value doesn't match proof if (keccak256(proof.value) != keccak256(value)) { return VerifyExistenceError.ValueNotMatching; } CheckAgainstSpecError cCode = checkAgainstSpec(proof, spec); if (cCode != CheckAgainstSpecError.None) { return VerifyExistenceError.CheckSpec; } (bytes32 root, CalculateRootError rCode) = calculateRoot(proof); if (rCode != CalculateRootError.None) { return VerifyExistenceError.CalculateRoot; } //require(BytesLib.equal(root, commitmentRoot)); // dev: Calculcated root doesn't match provided root if (root != commitmentRoot) { return VerifyExistenceError.RootNotMatching; } return VerifyExistenceError.None; } enum CalculateRootError { None, LeafNil, LeafOp, PathOp, EmptyProof } function calculateRoot( UnionIcs23.ExistenceProof calldata proof ) internal pure returns (bytes32, CalculateRootError) { //require(LeafOp.isNil(proof.leaf) == false); // dev: Existence Proof needs defined LeafOp if (proof.leafPrefix.length == 0) { return ("", CalculateRootError.LeafNil); } (bytes32 root, Ops.ApplyLeafOpError lCode) = Ops.applyLeafOp(proof.leafPrefix, proof.key, proof.value); if (lCode != Ops.ApplyLeafOpError.None) { return ("", CalculateRootError.LeafOp); } uint256 proofPathLength = proof.path.length; for (uint256 i; i < proofPathLength; i++) { Ops.ApplyInnerOpError iCode; (root, iCode) = Ops.applyOp(proof.path[i], root); if (iCode != Ops.ApplyInnerOpError.None) { return ("", CalculateRootError.PathOp); } } return (root, CalculateRootError.None); } enum CheckAgainstSpecError { None, EmptyLeaf, OpsCheckAgainstSpec, InnerOpsDepthTooShort, InnerOpsDepthTooLong } function checkAgainstSpec( UnionIcs23.ExistenceProof calldata proof, UnionIcs23.ProofSpec memory spec ) internal pure returns (CheckAgainstSpecError) { // LeafOp.isNil does not work //require(LeafOp._empty(proof.leaf) == false); // dev: Existence Proof needs defined LeafOp // TODO(aeryz): check if there is isempty function in solidity if (proof.leafPrefix.length == 0) { return CheckAgainstSpecError.EmptyLeaf; } // LeafOp's checkAgainstSpec is inlined here since we only need to check the prefix here //require(hasprefix); // dev: checkAgainstSpec for LeafOp - Leaf Prefix doesn't start with // Both specs have the prefix 0x00 if (proof.leafPrefix[0] != 0) { return CheckAgainstSpecError.OpsCheckAgainstSpec; } // we don't do any checks regarding min_depth, max_depth since they both are 0 in both specs uint256 max = spec.maxPrefixLength + spec.childSize; uint256 proofPathLength = proof.path.length; for (uint256 i; i < proofPathLength; i++) { UnionIcs23.InnerOp calldata innerOp = proof.path[i]; // innerOp.prefix is hardcoded to be 0 in both specs if ( innerOp.prefix.length < spec.minPrefixLength || innerOp.prefix[0] == 0 || innerOp.prefix.length > max ) { return CheckAgainstSpecError.OpsCheckAgainstSpec; } } return CheckAgainstSpecError.None; } enum VerifyNonExistenceError { None, VerifyLeft, VerifyRight, LeftAndRightKeyEmpty, RightKeyRange, LeftKeyRange, RightProofLeftMost, LeftProofRightMost, IsLeftNeighbor } // CosmosIcs23V1NonExistenceProof function verify( UnionIcs23.NonExistenceProof calldata proof, UnionIcs23.ProofSpec memory spec, bytes32 commitmentRoot, bytes memory key ) internal pure returns (VerifyNonExistenceError) { bytes calldata leftKey = proof.left.key; bytes calldata rightKey = proof.right.key; // CosmosIcs23V1ExistenceProof.isNil does not work if (!UnionIcs23.empty(proof.left)) { VerifyExistenceError eCode = verify( proof.left, spec, commitmentRoot, proof.left.key, proof.left.value ); if (eCode != VerifyExistenceError.None) { return VerifyNonExistenceError.VerifyLeft; } } if (!UnionIcs23.empty(proof.right)) { VerifyExistenceError eCode = verify( proof.right, spec, commitmentRoot, proof.right.key, proof.right.value ); if (eCode != VerifyExistenceError.None) { return VerifyNonExistenceError.VerifyRight; } } // If both proofs are missing, this is not a valid proof //require(leftKey.length > 0 || rightKey.length > 0); // dev: both left and right proofs missing if (leftKey.length == 0 && rightKey.length == 0) { return VerifyNonExistenceError.LeftAndRightKeyEmpty; } // Ensure in valid range if (rightKey.length > 0 && Ops.compare(key, rightKey) >= 0) { //require(Ops.compare(key, rightKey) < 0); // dev: key is not left of right proof return VerifyNonExistenceError.RightKeyRange; } if (leftKey.length > 0 && Ops.compare(key, leftKey) <= 0) { //require(Ops.compare(key, leftKey) > 0); // dev: key is not right of left proof return VerifyNonExistenceError.LeftKeyRange; } if (leftKey.length == 0) { //require(isLeftMost(spec, proof.right.path, proof.right.path.length)); // dev: left proof missing, right proof must be left-most if (!isLeftMost(spec, proof.right.path, proof.right.path.length)) { return VerifyNonExistenceError.RightProofLeftMost; } } else if (rightKey.length == 0) { //require(isRightMost(spec, proof.left.path, proof.left.path.length)); // dev: isRightMost: right proof missing, left proof must be right-most if (!isRightMost(spec, proof.left.path, proof.left.path.length)) { return VerifyNonExistenceError.LeftProofRightMost; } } else { //require(isLeftNeighbor(spec, proof.left.path, proof.right.path)); // dev: isLeftNeighbor: right proof missing, left proof must be right-most bool isLeftNeigh = isLeftNeighbor(spec, proof.left.path, proof.right.path); if (!isLeftNeigh) { return VerifyNonExistenceError.IsLeftNeighbor; } } return VerifyNonExistenceError.None; } function calculateRoot( UnionIcs23.NonExistenceProof calldata proof ) internal pure returns (bytes32, CalculateRootError) { if (!UnionIcs23.empty(proof.left)) { return calculateRoot(proof.left); } if (!UnionIcs23.empty(proof.right)) { return calculateRoot(proof.right); } //revert(); // dev: Nonexistence proof has empty Left and Right proof return ("", CalculateRootError.EmptyProof); } // private // length must be <= path.length function isLeftMost( UnionIcs23.ProofSpec memory spec, UnionIcs23.InnerOp[] calldata path, uint256 length ) private pure returns (bool) { (uint256 minPrefix, uint256 maxPrefix, uint256 suffix) = getPadding(spec, 0); for (uint256 i; i < length; i++) { if (!hasPadding(path[i], minPrefix, maxPrefix, suffix)) { return false; } } return true; } // length must be <= path.length function isRightMost( UnionIcs23.ProofSpec memory spec, UnionIcs23.InnerOp[] calldata path, uint256 length ) private pure returns (bool) { (uint256 minPrefix, uint256 maxPrefix, uint256 suffix) = getPadding(spec, 1); for (uint256 i; i < length; i++) { if (!hasPadding(path[i], minPrefix, maxPrefix, suffix)) { return false; } } return true; } function isLeftStep( UnionIcs23.ProofSpec memory spec, UnionIcs23.InnerOp calldata left, UnionIcs23.InnerOp calldata right ) private pure returns (bool) { (uint256 leftIdx, OrderFromPaddingError lCode) = orderFromPadding(spec, left); if (lCode != OrderFromPaddingError.None) return false; (uint256 rightIdx, OrderFromPaddingError rCode) = orderFromPadding(spec, right); if (lCode != OrderFromPaddingError.None) return false; if (rCode != OrderFromPaddingError.None) return false; return rightIdx == leftIdx + 1; } function isLeftNeighbor( UnionIcs23.ProofSpec memory spec, UnionIcs23.InnerOp[] calldata left, UnionIcs23.InnerOp[] calldata right ) private pure returns (bool) { uint256 leftIdx = left.length - 1; uint256 rightIdx = right.length - 1; while (leftIdx >= 0 && rightIdx >= 0) { if ( keccak256(left[leftIdx].prefix) == keccak256(right[rightIdx].prefix) && keccak256(left[leftIdx].suffix) == keccak256(right[rightIdx].suffix) ) { leftIdx -= 1; rightIdx -= 1; continue; } break; } if (!isLeftStep(spec, left[leftIdx], right[rightIdx])) { return false; } // slicing does not work for ``memory`` types if (!isRightMost(spec, left, leftIdx)) { return false; } if (!isLeftMost(spec, right, rightIdx)) { return false; } return true; } enum OrderFromPaddingError { None, NotFound } function orderFromPadding( UnionIcs23.ProofSpec memory spec, UnionIcs23.InnerOp calldata op ) private pure returns (uint256, OrderFromPaddingError) { for (uint256 branch; branch < 2; branch++) { (uint256 minp, uint256 maxp, uint256 suffix) = getPadding(spec, branch); if (hasPadding(op, minp, maxp, suffix) == true) { return (branch, OrderFromPaddingError.None); } } //revert(); // dev: Cannot find any valid spacing for this node return (0, OrderFromPaddingError.NotFound); } function getPadding( UnionIcs23.ProofSpec memory spec, uint256 branch ) private pure returns (uint256 minPrefix, uint256 maxPrefix, uint256 suffix) { uint256 prefix = branch * spec.childSize; minPrefix = prefix + spec.minPrefixLength; maxPrefix = prefix + spec.maxPrefixLength; suffix = (1 - branch) * spec.childSize; return (minPrefix, maxPrefix, suffix); } function hasPadding( UnionIcs23.InnerOp calldata op, uint256 minPrefix, uint256 maxPrefix, uint256 suffix ) private pure returns (bool) { if (op.prefix.length < minPrefix || op.prefix.length > maxPrefix) { return false; } return op.suffix.length == suffix; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @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 (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.20; import {IBeacon} from "../beacon/IBeacon.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. */ library ERC1967Utils { // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. // This will be fixed in Solidity 0.8.21. At that point we should remove these events. /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @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 { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ 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 { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @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 { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
pragma solidity ^0.8.27; library UnionIcs23 { struct ExistenceProof { bytes key; bytes value; bytes leafPrefix; InnerOp[] path; } struct NonExistenceProof { bytes key; ExistenceProof left; ExistenceProof right; } struct InnerOp { bytes prefix; bytes suffix; } struct ProofSpec { uint256 childSize; uint256 minPrefixLength; uint256 maxPrefixLength; } // Original spec is as follows, we trimmed the common parts: // int32[] memory childOrder = new int32[](2); // childOrder[0] = 0; // childOrder[1] = 1; // iavlProofSpec = CosmosIcs23V1ProofSpec.Data({ // leaf_spec: CosmosIcs23V1LeafOp.Data({ // prefix: hex"00", // prehash_key: CosmosIcs23V1GlobalEnums.HashOp.NO_HASH, // hash: CosmosIcs23V1GlobalEnums.HashOp.SHA256, // prehash_value: CosmosIcs23V1GlobalEnums.HashOp.SHA256, // length: CosmosIcs23V1GlobalEnums.LengthOp.VAR_PROTO // }), // inner_spec: CosmosIcs23V1InnerSpec.Data({ // child_order: childOrder, // child_size: 33, // min_prefix_length: 4, // max_prefix_length: 12, // empty_child: abi.encodePacked(), // hash: CosmosIcs23V1GlobalEnums.HashOp.SHA256 // }), // min_depth: 0, // max_depth: 0 // }); function getIavlProofSpec() internal pure returns (ProofSpec memory) { return ProofSpec({childSize: 33, minPrefixLength: 4, maxPrefixLength: 12}); } // Original spec is as follows, we trimmed the common parts: // int32[] memory childOrder = new int32[](2); // childOrder[0] = 0; // childOrder[1] = 1; // tendermintProofSpec = CosmosIcs23V1ProofSpec.Data({ // leaf_spec: CosmosIcs23V1LeafOp.Data({ // prefix: hex"00", // prehash_key: CosmosIcs23V1GlobalEnums.HashOp.NO_HASH, // hash: CosmosIcs23V1GlobalEnums.HashOp.SHA256, // prehash_value: CosmosIcs23V1GlobalEnums.HashOp.SHA256, // length: CosmosIcs23V1GlobalEnums.LengthOp.VAR_PROTO // }), // inner_spec: CosmosIcs23V1InnerSpec.Data({ // child_order: childOrder, // child_size: 32, // min_prefix_length: 1, // max_prefix_length: 1, // empty_child: abi.encodePacked(), // hash: CosmosIcs23V1GlobalEnums.HashOp.SHA256 // }), // min_depth: 0, // max_depth: 0 // }); function getTendermintProofSpec() internal pure returns (ProofSpec memory) { return ProofSpec({childSize: 32, minPrefixLength: 1, maxPrefixLength: 1}); } function empty( NonExistenceProof calldata proof ) internal pure returns (bool) { if (proof.key.length != 0) { return false; } return empty(proof.left) && empty(proof.right); } function empty( ExistenceProof calldata proof ) internal pure returns (bool) { if (proof.key.length != 0) { return false; } if (proof.value.length != 0) { return false; } if (proof.leafPrefix.length != 0) { return false; } if (proof.path.length != 0) { return false; } return true; } }
pragma solidity ^0.8.27; enum IBCConnectionState { Unspecified, Init, TryOpen, Open } struct IBCConnection { IBCConnectionState state; uint32 clientId; uint32 counterpartyClientId; uint32 counterpartyConnectionId; } enum IBCChannelState { Unspecified, Init, TryOpen, Open, Closed } struct IBCChannel { IBCChannelState state; uint32 connectionId; uint32 counterpartyChannelId; bytes counterpartyPortId; string version; } struct IBCPacket { uint32 sourceChannel; uint32 destinationChannel; bytes data; uint64 timeoutHeight; uint64 timeoutTimestamp; } library IBCErrors { error ErrClientTypeAlreadyExists(); error ErrClientTypeNotFound(); error ErrInvalidProof(); error ErrInvalidConnectionState(); error ErrInvalidChannelState(); error ErrUnauthorized(); error ErrLatestTimestampNotFound(); error ErrTimeoutMustBeSet(); error ErrHeightTimeout(); error ErrTimestampTimeout(); error ErrAcknowledgementIsEmpty(); error ErrPacketNotReceived(); error ErrAcknowledgementAlreadyExists(); error ErrPacketCommitmentNotFound(); error ErrTimeoutHeightNotReached(); error ErrTimeoutTimestampNotReached(); error ErrNotEnoughPackets(); error ErrCommittedAckNotPresent(); error ErrClientNotFound(); error ErrModuleNotFound(); error ErrPacketAlreadyExist(); }
pragma solidity ^0.8.27; import "../Types.sol"; // IIBCModule defines an interface that implements all the callbacks // that modules must define as specified in ICS-26 // https://github.com/cosmos/ibc/blob/2921c5cec7b18e4ef77677e16a6b693051ae3b35/spec/core/ics-026-routing-module/README.md interface IIBCModule { function onChanOpenInit( uint32 connectionId, uint32 channelId, string calldata version, address relayer ) external; function onChanOpenTry( uint32 connectionId, uint32 channelId, uint32 counterpartyChannelId, string calldata version, string calldata counterpartyVersion, address relayer ) external; function onChanOpenAck( uint32 channelId, uint32 counterpartyChannelId, string calldata counterpartyVersion, address relayer ) external; function onChanOpenConfirm(uint32 channelId, address relayer) external; function onChanCloseInit(uint32 channelId, address relayer) external; function onChanCloseConfirm(uint32 channelId, address relayer) external; function onRecvIntentPacket( IBCPacket calldata packet, address marketMaker, bytes calldata marketMakerMsg ) external returns (bytes memory); function onRecvPacket( IBCPacket calldata packet, address relayer, bytes calldata relayerMsg ) external returns (bytes memory); function onAcknowledgementPacket( IBCPacket calldata packet, bytes calldata acknowledgement, address relayer ) external; function onTimeoutPacket(IBCPacket calldata, address relayer) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @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. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @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 or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * 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. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @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`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) 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 FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @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: * ```solidity * 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(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes 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 } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
{ "remappings": [ "@openzeppelin-foundry-upgradeable/=libs/@openzeppelin-foundry-upgradeable/", "@openzeppelin-upgradeable/=libs/@openzeppelin-upgradeable/", "@openzeppelin/=libs/@openzeppelin/", "forge-std/=libs/forge-std/", "solady/=libs/solady/", "solidity-bytes-utils/=libs/solidity-bytes-utils/contracts/", "solidity-stringutils/=libs/solidity-stringutils/" ], "optimizer": { "enabled": true, "runs": 1000, "details": { "cse": true, "constantOptimizer": true, "yul": true } }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": true, "libraries": {} }
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ErrClientFrozen","type":"error"},{"inputs":[],"name":"ErrHeaderExpired","type":"error"},{"inputs":[],"name":"ErrInvalidInitialConsensusState","type":"error"},{"inputs":[],"name":"ErrInvalidMisbehaviour","type":"error"},{"inputs":[],"name":"ErrInvalidMisbehaviourHeadersSequence","type":"error"},{"inputs":[],"name":"ErrInvalidUntrustedValidatorsHash","type":"error"},{"inputs":[],"name":"ErrInvalidZKP","type":"error"},{"inputs":[],"name":"ErrMaxClockDriftExceeded","type":"error"},{"inputs":[],"name":"ErrNotIBC","type":"error"},{"inputs":[],"name":"ErrTrustedConsensusStateNotFound","type":"error"},{"inputs":[],"name":"ErrUntrustedHeightLTETrustedHeight","type":"error"},{"inputs":[],"name":"ErrUntrustedTimestampLTETrustedTimestamp","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"clientStateBytes","type":"bytes"},{"internalType":"bytes","name":"consensusStateBytes","type":"bytes"}],"name":"createClient","outputs":[{"components":[{"internalType":"bytes32","name":"clientStateCommitment","type":"bytes32"},{"internalType":"bytes32","name":"consensusStateCommitment","type":"bytes32"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct ConsensusStateUpdate","name":"update","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"}],"name":"getClientState","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"uint64","name":"height","type":"uint64"}],"name":"getConsensusState","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"}],"name":"getLatestHeight","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"uint64","name":"height","type":"uint64"}],"name":"getTimestampAtHeight","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ibcHandler","type":"address"},{"internalType":"address","name":"admin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"}],"name":"isFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"clientMessageBytes","type":"bytes"}],"name":"misbehaviour","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","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":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bytes","name":"clientMessageBytes","type":"bytes"}],"name":"updateClient","outputs":[{"components":[{"internalType":"bytes32","name":"clientStateCommitment","type":"bytes32"},{"internalType":"bytes32","name":"consensusStateCommitment","type":"bytes32"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct ConsensusStateUpdate","name":"","type":"tuple"}],"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":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"bytes","name":"value","type":"bytes"}],"name":"verifyMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"bytes","name":"path","type":"bytes"}],"name":"verifyNonMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"zkpBytes","type":"bytes"},{"internalType":"bytes31","name":"chainId","type":"bytes31"},{"internalType":"bytes32","name":"trustedValidatorsHash","type":"bytes32"},{"components":[{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"uint64","name":"secs","type":"uint64"},{"internalType":"uint64","name":"nanos","type":"uint64"},{"internalType":"bytes32","name":"validatorsHash","type":"bytes32"},{"internalType":"bytes32","name":"nextValidatorsHash","type":"bytes32"},{"internalType":"bytes32","name":"appHash","type":"bytes32"}],"internalType":"struct SignedHeader","name":"header","type":"tuple"}],"name":"verifyZKP","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a080604052346100ea57306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c166100d9576002600160401b03196001600160401b03821601610073575b604051613c2590816100f082396080518181816106ea01526108950152f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a13880610054565b63f92ee8a960e01b60005260046000fd5b600080fdfe6080604052600436101561001257600080fd5b60003560e01c80632886a3a3146101475780633fd413de14610142578063485cc9551461013d5780634f1ef2861461013857806352d1902d146101335780635c975abb1461012e5780636659c7ac146101295780636d6f212014610124578063715018a61461011f5780638da5cb5b1461011a578063a4479b1114610115578063a9f9396e14610110578063ad3cb1cc1461010b578063ae3fee3514610106578063b4b5250814610101578063b6719c89146100fc578063e9946fc3146100f7578063f2fde38b146100f25763f67f54fa146100ed57600080fd5b61111a565b6110f1565b61108a565b61103a565b610fd3565b610e18565b610db9565b610d23565b610c66565b610be0565b610b3a565b610ae7565b610933565b6108e5565b61087a565b61069b565b610390565b6101df565b610164565b6004359063ffffffff8216820361015f57565b600080fd5b3461015f57602036600319011261015f5763ffffffff61018261014c565b166000526001602052602060016040600020015460c01c604051908152f35b6001600160401b0381160361015f57565b9181601f8401121561015f578235916001600160401b03831161015f576020838186019501011161015f57565b3461015f57608036600319011261015f576101f861014c565b602435610204816101a1565b6044356001600160401b03811161015f576102239036906004016101b2565b506064356001600160401b03811161015f576102439036906004016101b2565b9390916102728263ffffffff1660005260016020526001600160401b0360016040600020015460801c16151590565b61033a576103369461031f8361031160016102d66103249963ffffffff6102f49916600052826020526102be6002604060002001549563ffffffff166000526002602052604060002090565b906001600160401b0316600052602052604060002090565b0154936103026102e4611297565b60405198899160208301906112d2565b03601f198101895288610609565b604051978893602085016112f7565b03601f198101865285610609565b611879565b60405190151581529081906020820190565b0390f35b7fb3e346700000000000000000000000000000000000000000000000000000000060005260046000fd5b600435906001600160a01b038216820361015f57565b602435906001600160a01b038216820361015f57565b3461015f57604036600319011261015f576103a9610364565b6103b161037a565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005491906001600160401b036103ff60ff604086901c16156103f2565b1590565b946001600160401b031690565b16801590816105b0575b60011490816105a6575b15908161059d575b5061057357610484918361047b60016001600160401b03197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b61050e57611333565b61048a57005b6104df68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b61056e6801000000000000000068ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b611333565b7ff92ee8a90000000000000000000000000000000000000000000000000000000060005260046000fd5b9050153861041b565b303b159150610413565b849150610409565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b038211176105e957604052565b6105b8565b606081019081106001600160401b038211176105e957604052565b90601f801991011681019081106001600160401b038211176105e957604052565b60405190610639606083610609565b565b906106396040519283610609565b6001600160401b0381116105e957601f01601f191660200190565b92919261067082610649565b9161067e6040519384610609565b82948184528183011161015f578281602093846000960137010152565b604036600319011261015f576106af610364565b6024356001600160401b03811161015f573660238201121561015f576106df903690602481600401359101610664565b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803014908115610845575b5061081b57610722611a3e565b604051917f52d1902d0000000000000000000000000000000000000000000000000000000083526020836004816001600160a01b0386165afa600093816107ea575b5061078757634c9c8ce360e01b6000526001600160a01b03821660045260246000fd5b907f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc83036107bb576107b99250612391565b005b7faa1d49a400000000000000000000000000000000000000000000000000000000600052600483905260246000fd5b61080d91945060203d602011610814575b6108058183610609565b8101906118b7565b9238610764565b503d6107fb565b7fe07c8dba0000000000000000000000000000000000000000000000000000000060005260046000fd5b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416141538610715565b3461015f57600036600319011261015f576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361081b5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b3461015f57600036600319011261015f57602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b60ff1981160361015f57565b3461015f5761012036600319011261015f576004356001600160401b03811161015f576109649036906004016101b2565b5060243561097181610927565b6044359060c036606319011261015f5760206000610a45610100860194610a396109ba6040516109b5816109a78b8a83016118d2565b03601f198101835282610609565b6124d3565b956109a76109d56109c96114d6565b6001600160401b031690565b936109e16109c96114e2565b6109ec6109c96114ee565b60c43560e435916101043593604051998a9860081c8e8a019694929091610100989694928852602088015260408701526060860152608085015260a084015260c083015260e08201520190565b604051918280926112d2565b039060025afa15610a9a5761033692610324927effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000511692610a87604061063b565b938452602084015261014082019161261d565b6118c6565b60005b838110610ab25750506000910152565b8181015183820152602001610aa2565b90602091610adb81518092818552858086019101610a9f565b601f01601f1916010190565b3461015f57602036600319011261015f5763ffffffff610b0561014c565b166000526001602052610336610b26610b216040600020611370565b6119c6565b604051918291602083526020830190610ac2565b3461015f57600036600319011261015f57610b53611a3e565b60006001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005473ffffffffffffffffffffffffffffffffffffffff1981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461015f57600036600319011261015f5760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b90604060031983011261015f5760043563ffffffff8116810361015f5791602435906001600160401b03821161015f57610c62916004016101b2565b9091565b3461015f57610cb6610c7736610c26565b509190610c82611a9f565b63ffffffff8116600052600160205260406000209283610cb0610ca583806113ed565b9260208101906113ed565b92611b51565b15610cf95760010180547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16700100000000000000000000000000000000179055005b7fb1333bc80000000000000000000000000000000000000000000000000000000060005260046000fd5b3461015f5760a036600319011261015f57610d3c61014c565b602435610d48816101a1565b6044356001600160401b03811161015f57610d679036906004016101b2565b9190926064356001600160401b03811161015f57610d899036906004016101b2565b90608435946001600160401b03861161015f5761033696610db16103249736906004016101b2565b969095611402565b3461015f57600036600319011261015f576103366040805190610ddc8183610609565b600582527f352e302e30000000000000000000000000000000000000000000000000000000602083015251918291602083526020830190610ac2565b3461015f57606036600319011261015f57610e3161014c565b6024356001600160401b03811161015f57610e509036906004016101b2565b506044356001600160401b03811161015f57610e709036906004016101b2565b5090610e7a6114b7565b50610e83611a9f565b608081016001600160401b038135610e9a816101a1565b16158015610fbe575b610f9457610f46610f40610f3b610f33610f2e86610f2789610f22610f028d610eec6103369f9d610ee7610f679f63ffffffff166000526001602052604060002090565b611504565b63ffffffff166000526002602052604060002090565b610f0b8b6114fa565b6001600160401b0316600052602052604060002090565b611657565b3690611699565b611ca4565b953690611716565b611cb7565b916114fa565b90610f4f61062a565b93845260208401526001600160401b03166040830152565b604080518251815260208084015190820152918101516001600160401b0316908201529081906060820190565b7f920ed63f0000000000000000000000000000000000000000000000000000000060005260046000fd5b50610fcd83356109c9816101a1565b15610ea3565b3461015f57604036600319011261015f57610336610b26611035611030610ff861014c565b63ffffffff6024359161100a836101a1565b1660005260026020526040600020906001600160401b0316600052602052604060002090565b611751565b611cbc565b3461015f57602036600319011261015f57602061108061105861014c565b63ffffffff1660005260016020526001600160401b0360016040600020015460801c16151590565b6040519015158152f35b3461015f57604036600319011261015f5760206001600160401b036110e76110b061014c565b63ffffffff602435916110c2836101a1565b16600052600284526040600020906001600160401b0316600052602052604060002090565b5416604051908152f35b3461015f57602036600319011261015f576107b961110d610364565b611115611a3e565b611782565b3461015f5761112836610c26565b50906111326114b7565b5061113b611a9f565b6111558163ffffffff166000526001602052604060002090565b9160018301546001600160401b03611177826001600160401b039060801c1690565b1661033a57610f676111e2611240610f3b61123a610f2e896080610336996112246112076109c99b6102be8f6111d6886111d06111c48463ffffffff166000526002602052604060002090565b610f0b60c08b016114fa565b88611dd3565b509f819e919460c01c90565b6001600160401b038416116112485763ffffffff166000526002602052604060002090565b9a8b906001600160401b03166001600160401b0319825416179055565b60a081013560018b015501356002890155611370565b94611751565b610f4f61062a565b60018801805477ffffffffffffffffffffffffffffffffffffffffffffffff1660c085901b7fffffffffffffffff00000000000000000000000000000000000000000000000016179055610eec565b604051906112a6604083610609565b600482527f7761736d000000000000000000000000000000000000000000000000000000006020830152565b906112e560209282815194859201610a9f565b0190565b908092918237016000815290565b909280926021947f0300000000000000000000000000000000000000000000000000000000000000845260018401528483013701016000815290565b61134f6001600160a01b0392611347612338565b611115612338565b1673ffffffffffffffffffffffffffffffffffffffff196000541617600055565b9060405161137d816105ce565b60a06002829460ff19815460081b1684526113e66113d660018301546001600160401b03811660208801526001600160401b03808260401c161660408801526001600160401b03808260801c1616606088015260c01c90565b6001600160401b03166080860152565b0154910152565b90359060fe198136030182121561015f570190565b92509594936114338363ffffffff1660005260016020526001600160401b0360016040600020015460801c16151590565b61033a576114af8361031160016114796114b49b63ffffffff602099166000528289526102be6002604060002001549563ffffffff166000526002602052604060002090565b015493610302611487611297565b6040519889916114a08284019182815194859201610a9f565b0103601f198101895288610609565b611c8e565b90565b604051906114c4826105ee565b60006040838281528260208201520152565b6064356114b4816101a1565b6084356114b4816101a1565b60a4356114b4816101a1565b356114b4816101a1565b9060a0600291803561151581610927565b60081c6001600160f81b03198554161784556116506001850161155c602084013561153f816101a1565b825467ffffffffffffffff19166001600160401b03909116178255565b604083013561156a816101a1565b7fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff6fffffffffffffffff000000000000000083549260401b16911617815560608301356115b6816101a1565b7fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff77ffffffffffffffff0000000000000000000000000000000083549260801b169116178155611608608084016114fa565b77ffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffff00000000000000000000000000000000000000000000000083549260c01b169116179055565b0135910155565b906040600291611688813561166b816101a1565b855467ffffffffffffffff19166001600160401b03909116178555565b602081013560018501550135910155565b91908260c091031261015f576040516116b1816105ce565b60a080829480356116c181610927565b845260208101356116d1816101a1565b602085015260408101356116e4816101a1565b604085015260608101356116f7816101a1565b6060850152608081013561170a816101a1565b60808501520135910152565b919082606091031261015f5760405161172e816105ee565b6040808294803561173e816101a1565b8452602081013560208501520135910152565b9060405161175e816105ee565b6040600282946001600160401b038154168452600181015460208501520154910152565b6001600160a01b0316801561181f576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300548273ffffffffffffffffffffffffffffffffffffffff198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b903590607e198136030182121561015f570190565b634e487b7160e01b600052602160045260246000fd5b813593929136819003605e190185121561015f576118a59461189e602083018361184e565b9101612044565b60128110156118b2571590565b611863565b9081602091031261015f575190565b6040513d6000823e3d90fd5b6040809282370190565b90926000611988602092610a396101008601976109a761190a6109a76109b58c6040519283918c83016118d2565b986119176109c9866114fa565b946119266109c98a83016114fa565b906119366109c9604083016114fa565b60608201359060a0608084013593013593604051998a9860081c8e8a019694929091610100989694928852602088015260408701526060860152608085015260a084015260c083015260e08201520190565b039060025afa15610a9a576114b4927effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000511692610a87604061063b565b60ff19815116906001600160401b03602082015116906001600160401b036040820151166001600160401b036060830151169060a06001600160401b036080850151169301519360405195602087015260408601526060850152608084015260a083015260c082015260c081526114b460e082610609565b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303611a7157565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b6001600160a01b03600054163303611ab357565b7fe54f8f9d0000000000000000000000000000000000000000000000000000000060005260046000fd5b91909160a08060c08301946001600160401b038135611afb816101a1565b1684526001600160401b036020820135611b14816101a1565b1660208501526001600160401b036040820135611b30816101a1565b16604085015260608101356060850152608081013560808501520135910152565b90611b5b836114fa565b6001600160401b03611b6f6109c9876114fa565b911610611c5a5780611bcb611bd592611bc4611bb8611ba16111c48863ffffffff166000526002602052604060002090565b9663ffffffff166000526002602052604060002090565b610f0b60c08a016114fa565b9486611dd3565b5093905085611dd3565b509050611be1836114fa565b6001600160401b03611bf56109c9876114fa565b911603611c3e575050604051611c13816109a7602082019485611add565b51902090604051611c2c816109a7602082019485611add565b51902003611c3957600090565b600190565b6001600160401b039250829193501691161115611c3957600090565b7f635205340000000000000000000000000000000000000000000000000000000060005260046000fd5b600911156118b257565b611c9b95949392916128b3565b6103ee81611c84565b611cad906119c6565b6020815191012090565b611cad905b6001600160401b0381511690604060208201519101519060405192602084015260408301526060820152606081526114b4608082610609565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03633b9aca00911602906001600160401b038216918203611d2f57565b611cf5565b6001600160401b036001911601906001600160401b038211611d2f57565b906001600160401b03809116911601906001600160401b038211611d2f57565b90633b9aca00820291808304633b9aca001490151715611d2f57565b81810292918115918404141715611d2f57565b903590601e198136030182121561015f57018035906001600160401b03821161015f5760200191813603831361015f57565b9291906001600160401b03611def82546001600160401b031690565b1693841561200657611e00816114fa565b92611e0d60c083016114fa565b926001600160401b038516906001600160401b038516821115611fdc57611e53611e41611e3c602087016114fa565b611d0b565b611e4d604087016114fa565b90611d52565b976001600160401b03891690811115611fb257611e726109c942611d72565b6001850154611e8b826001600160401b0383168d612990565b611f8857611ea8916109c99160401c6001600160401b0316611e4d565b1115611f5e576109c96002611ebf92015495611d34565b14611f22575b90611eed926103ee92611ee7611ede60e0850185611da1565b50915460081b90565b906118dc565b611ef8579190600090565b7f396df4ec0000000000000000000000000000000000000000000000000000000060005260046000fd5b9082606082013503611f345790611ec5565b7f895cf0ce0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f4ccc303c0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f6c4c87b60000000000000000000000000000000000000000000000000000000060005260046000fd5b7f14a286e40000000000000000000000000000000000000000000000000000000060005260046000fd5b7ff97b09220000000000000000000000000000000000000000000000000000000060005260046000fd5b7f09128dc80000000000000000000000000000000000000000000000000000000060005260046000fd5b600511156118b257565b600611156118b257565b93919293612051816129b6565b61205d81959295612030565b61232d57836120749261206e612a0d565b90612a6c565b61207d81611c84565b806121f7575061208c81612d04565b61209881969296612030565b6121ed576120c892610311926120c36120af612dda565b926040519586916020830160209181520190565b612e04565b6120d18161203a565b806120e65750036120e157600090565b600990565b8092506120f3915061203a565b600181036121015750600490565b61210a8161203a565b600281036121185750600590565b6121218161203a565b6003810361212f5750600690565b6121388161203a565b600481036121465750600790565b8061215260059261203a565b146121e85760405162461bcd60e51b815260206004820152605660248201527f766572696679436861696e65644e6f6e4d656d626572736869703a206e6f6e2060448201527f65786861757374697665207061747465726e206d61746368696e67206f6e205660648201527f65726966794e6f6e4578697374656e63654572726f7200000000000000000000608482015260a490fd5b600890565b5050505050600390565b935050505061220581611c84565b600181036122135750600a90565b61221c81611c84565b6003810361222a5750600c90565b61223381611c84565b600481036122415750600d90565b61224a81611c84565b600581036122585750600e90565b61226181611c84565b6006810361226f5750600f90565b61227881611c84565b600781036122865750601090565b80612292600892611c84565b146123285760405162461bcd60e51b815260206004820152605660248201527f766572696679436861696e65644e6f6e4d656d626572736869703a206e6f6e2060448201527f65786861757374697665207061747465726e206d61746368696e67206f6e205660648201527f65726966794e6f6e4578697374656e63654572726f7200000000000000000000608482015260a490fd5b601190565b505050505050600390565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561236757565b7fd7e6bcf80000000000000000000000000000000000000000000000000000000060005260046000fd5b90813b1561246b576001600160a01b0382168073ffffffffffffffffffffffffffffffffffffffff197f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a28051156124385761243591612e82565b50565b50503461244157565b7fb398979f0000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160a01b0382634c9c8ce360e01b6000521660045260246000fd5b600019810191908211611d2f57565b81156124a2570690565b634e487b7160e01b600052601260045260246000fd5b9060018201809211611d2f57565b91908201809211611d2f57565b6126186114b4916109a76125ee604051926124ef60c085610609565b608884527f1f333139281e100f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c60208501527f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c60408501527f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c60608501527f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c60808501527f5c5c5c5c5c5c5c5c00000000000000000000000000000000000000000000000060a08501526109a76125da6125bf612ec8565b926040519283916125d46020840180976112d2565b906112d2565b519020604051928391602083019586612f9b565b5190207f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000090612498565b6124b8565b926126289082612fb9565b9391929092156128935761263f916103ee9161311a565b61288b576101006040519384377f07b8dbefa90bde075a26318e5066db729155514e3c06b888d4e03c56d82c97e66101008401527f02aca5d2a73f8d34e4b26eee3932365e6526c8d5e2f3347d679c2cb1867104dc6101208401527f2edb19cbb2b6ad0c98fdd7d1845500c26e497dc35e4cdc1cb02cc65dc4ba1bf26101408401527f1696ccafaefe49a5d8bad8e79630e19b25e5392a203aff0042d0216f254806f56101608401527f245229d9b076b3c0e8a4d70bde8c1cccffa08a9fae7557b165b3b0dbd653e2c76101808401527f253ec85988dbb84e46e94b5efa3373b47a000b4ac6c86b2d4b798d274a1823026101a08401527f07090a82e8fabbd39299be24705b92cf208ee8b3487f6f2b39ff27978a29a1db6101c08401527f2424bcc1f60a5472685fd50705b2809626e170120acaf441e133a2bd5e61d2446101e08401527f25833b15e156ae01f2741f4f4120ddb466c52eb83a959f79eb99b23caa7fbf1d6102008401527f04ddc8d30d5c438ca34091c5d2c6ded571382cba2b3c4fdc4222df2938b4e51e6102208401526102408301526102608201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26102808201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6102a08201527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec6102c08201527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d6102e08201526020816103008160085afa90511690565b505050600090565b5050505050600090565b634e487b7160e01b600052603260045260246000fd5b919490936128c96128c4848061184e565b612d04565b6128d581969296612030565b61298457612901926128fb6128ea868061184e565b936128f3612a0d565b923691610664565b92612e04565b61290a8161203a565b80612976575091612959939161292761294694602081019061184e565b612954612932612dda565b926040519687916020830160209181520190565b03601f198101875286610609565b61336b565b6129628161203a565b8061296d5750600090565b6114b49061326d565b925050506114b4915061326d565b50505050505050600290565b6001600160401b0380919392931692168201809211611d2f576001600160401b03161190565b602081016129cc6129c7828461184e565b613410565b15612a00575060408101906129e46129c7838361184e565b156129f3575050600090600490565b610c62916128c49161184e565b6128c490610c629261184e565b612a156114b7565b50604051612a22816105ee565b6021815260046020820152600c604082015290565b903590601e198136030182121561015f57018035906001600160401b03821161015f57602001918160051b3603831361015f57565b9092916020820190612a87612a81838561184e565b80611da1565b9190946040850195612a9c612a81888861184e565b949093612aaf6103ee6129c7898b61184e565b612c8c575b612ac46103ee6129c78b8b61184e565b612c16575b508015938480612c0e575b612bff5785159586159182612be7575b5050612bd95783159182612bc2575b50509050612bb75715612b47575050918183612b30612b1e612b28612b1e6103ee97612b389961184e565b6060810190612a37565b94909361184e565b9390506136c2565b612b42575b600090565b600690565b90929015612b825750918183612b6c612b1e612b28612b1e6103ee97612b749961184e565b939050613651565b612b7d57600090565b600790565b92612bad93612ba5612b1e612b9d612b1e6103ee978761184e565b93909561184e565b93909261354a565b15612b3d57600890565b505050505050600590565b612bcf925060009361348b565b1315803880612af3565b505050505050505050600490565b6000925090612bf6918661348b565b12153880612ae4565b50505050505050505050600390565b508515612ad4565b612c6b9088612c258b8261184e565b918c612c658d612c5d612c53612c49612c41612a81858a61184e565b94909861184e565b6020810190611da1565b9690923691610664565b943691610664565b9361336b565b612c748161203a565b612c7e5738612ac9565b505050505050505050600290565b612cb6612c99888a61184e565b89838d612c658c612c5d612c53612c49612c41612a81858a61184e565b612cbf8161203a565b15612ab45750505050505050505050600190565b600311156118b257565b9190811015612cff5760051b81013590603e198136030182121561015f570190565b61289d565b60408101612d128183611da1565b905015612dd057612d26612d479183611da1565b90612d318480611da1565b90612d3f6020870187611da1565b949093613785565b919091612d5381612cd3565b612dc65760608101612d658183612a37565b9190506000925b828410612d7d575050505090600090565b90919293612d9e90612d9986612d938686612a37565b90612cdd565b613839565b949094612daa81612cd3565b612db957600101929190612d6c565b5050505050600090600390565b5050600090600290565b5050600090600190565b612de26114b7565b50604051612def816105ee565b60208152600160208201526001604082015290565b929091612e1b612e148580611da1565b3691610664565b60208151910120906020815191012003612e7a57612e3f612e146020850185611da1565b60208151910120906020815191012003612e7357612e5c916138b7565b612e6581612030565b612e6e57600090565b600390565b5050600290565b505050600190565b6000806114b493602081519101845af43d15612ec0573d91612ea383610649565b92612eb16040519485610609565b83523d6000602085013e6139a3565b6060916139a3565b60405190612ed760c083610609565b608882527f363636363636363600000000000000000000000000000000000000000000000060a0837f75595b5342747a6536363636363636363636363636363636363636363636363660208201527f363636363636363636363636363636363636363636363636363636363636363660408201527f363636363636363636363636363636363636363636363636363636363636363660608201527f363636363636363636363636363636363636363636363636363636363636363660808201520152565b6020929190612fb1849282815194859201610a9f565b019081520190565b90916040519260408401907f2f5d8a3817f21d3e453573c90c3cc47b7ff235fad7bdfbd59bbd6ae5d153273e8552604060208601947f147fa22142b1fd86ce75fc87230a0feac8765d02938784dcfc828d17d7e7c432865283377f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016040808760808160065afa937f2a81b98e1c997bd01a20893a08a46c6804493e838c1a0ff6c8c069ef5ab66b9a8152602060608901947f276938ada8075cec20d4d6a1f157ec94cc7ba6207c98576e98c1ad9d6378fb6f86527f0326e7d44688ce5903676b7d646e46a5938c8e5fd8cd54e4d5aa3300649f3cfc6001825160808d0199818b5288888860608160075afa92101616868d60808160065afa1616967f179496ce140df89ce35c5ee7fb496efdffda5e5d3b95ff9116e2e5df96b36ab7855252015180955260608160075afa9210161660408460808160065afa169251915190565b906040908180519384377f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2828401527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60608401527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60808401527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60a084015260c08301377f07b8dbefa90bde075a26318e5066db729155514e3c06b888d4e03c56d82c97e66101008201527f02aca5d2a73f8d34e4b26eee3932365e6526c8d5e2f3347d679c2cb1867104dc6101208201527f2edb19cbb2b6ad0c98fdd7d1845500c26e497dc35e4cdc1cb02cc65dc4ba1bf26101408201527f1696ccafaefe49a5d8bad8e79630e19b25e5392a203aff0042d0216f254806f56101608201526020816101808160085afa90511690565b6132768161203a565b600181036132845750600390565b61328d8161203a565b6002810361329b5750600490565b6132a48161203a565b600381036132b25750600590565b6132bb8161203a565b600481036132c95750600690565b806132d560059261203a565b14612b7d5760405162461bcd60e51b815260206004820152605060248201527f766572696679436861696e65644d656d626572736869703a206e6f6e2065786860448201527f61757374697665207061747465726e206d61746368696e67206f6e205665726960648201527f66794578697374656e63654572726f7200000000000000000000000000000000608482015260a490fd5b929390919361337d612e148580611da1565b60208151910120906020815191012003613407576133a1612e146020850185611da1565b602081519101209060208151910120036133ff576133bf90826138b7565b6133c881612030565b6133f8576133d590612d04565b6133de81612030565b6133f157036133ec57600090565b600590565b5050600490565b5050600390565b505050600290565b50505050600190565b61341a8180611da1565b905061345f5761342d6020820182611da1565b905061345f576134406040820182611da1565b905061345f57806060613454920190612a37565b9050612b3d57600190565b50600090565b908151811015612cff570160200190565b9015612cff5790565b90821015612cff570190565b9190613498828451613a33565b92839160005b8381106134c457505051116134bd57116134b757600090565b60001990565b5050600190565b909192506134e36134d58285613465565b516001600160f81b03191690565b6001600160f81b031961351861350b6134fd85898861347f565b356001600160f81b03191690565b6001600160f81b03191690565b91168181101561352f575050505050505060001990565b11613540576001019084929161349e565b5050505050600190565b9293909161355781612489565b9261356183612489565b935b613574612e14612a81838686612cdd565b6020815191012061358c612e14612a8188888c612cdd565b60208151910120148061361a575b613602576135c16103ee6135af838686612cdd565b6135ba88888c612cdd565b9089613a4f565b6135f6576135d3926103ee9287613651565b6135ed576135e4936103ee936136c2565b612b3d57600190565b50505050600090565b50505050505050600090565b61360e61361491612489565b94612489565b93613563565b5061362c612e14612c49838686612cdd565b60208151910120613644612e14612c4988888c612cdd565b602081519101201461359a565b805160208201518101939291848211611d2f5760408101518201809211611d2f57511560011715611d2f5760009360005b8681106136955750505050505050600190565b6136ab8684846136a6858a8a612cdd565b613aa1565b156136b857600101613682565b5050505050905090565b9091600082511560011715611d2f5750602082015160408301519251929160005b8681106136f65750505050505050600190565b6137078585856136a685878c612cdd565b156135f6576001016136e3565b9061371e82610649565b61372b6040519182610609565b828152809261373c601f1991610649565b0190602036910137565b946020612fb19461376f85839b9a9895998597859b823701916000835282815194859201610a9f565b0191823701916000835282815194859201610a9f565b949390919293841561382b57801561381d5760006020916137ad6137a888613b03565b613714565b936137b88589613b22565b506137c8604051809381936112e9565b039060025afa15610a9a576020946109a761380b94610a39936000978851926137f26137a8613ae6565b926137fc84613b63565b506040519889978d8901613746565b039060025afa15610a9a576000805191565b505050505050600090600290565b505050505050600090600190565b6138a360009160209361389285613860816138548680611da1565b92909682810190611da1565b909581604051978589968688019b8c37860192858401526040830137010187838201520301601f198101835282610609565b604051928392839251928391610a9f565b8101039060025afa15610a9a576000805191565b90604082016138c68184611da1565b905015612e7a576138ec6134fd6138e66001600160f81b03199386611da1565b90613476565b16612e735761390160408201518251906124c6565b60608301926139108482612a37565b94905060005b85811061392857505050505050600090565b61393681612d938486612a37565b846139418280611da1565b9050602088015111918215613987575b8215613971575b505061396657600101613916565b505050505050600290565b61397d91925080611da1565b9050118438613958565b915061399c61350b6134fd6138e68580611da1565b1591613951565b906139e257508051156139b857805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580613a2a575b6139f3575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b156139eb565b9080821015613a40575090565b905090565b600211156118b257565b90613a5a9082613b74565b92909160028410156118b257836135ed57613a8091613a7891613b74565b919093613a45565b613a8981613a45565b613a9a57613a96906124b8565b1490565b5050600090565b9190613aad8380611da1565b905010908115613ad1575b50613a9a57806020613acb920190611da1565b90501490565b9050613add8280611da1565b90501138613ab8565b60016000805b613af4575090565b60019091019060071c80613aec565b60019060071c805b613b13575090565b60019091019060071c80613b0b565b919091602060009301607f8216915b60071c918215613b57576001918291608017815301930190607f81169093909193613b31565b90600193949250530190565b600091908290602090810190613b57565b60005b60028110613b8a57505050600090600190565b613b95825182611d8e565b60208301518101808211611d2f5760408401518201809211611d2f57826001039060018211611d2f57600192613bd0613bd793875190611d8e565b9187613aa1565b151514613be657600101613b77565b9150509060009056fea26469706673582212202a79c3296a89a4fc8af16dfc20586689525c4aeeade1b2ff44468ea6a02effba64736f6c634300081b0033
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c80632886a3a3146101475780633fd413de14610142578063485cc9551461013d5780634f1ef2861461013857806352d1902d146101335780635c975abb1461012e5780636659c7ac146101295780636d6f212014610124578063715018a61461011f5780638da5cb5b1461011a578063a4479b1114610115578063a9f9396e14610110578063ad3cb1cc1461010b578063ae3fee3514610106578063b4b5250814610101578063b6719c89146100fc578063e9946fc3146100f7578063f2fde38b146100f25763f67f54fa146100ed57600080fd5b61111a565b6110f1565b61108a565b61103a565b610fd3565b610e18565b610db9565b610d23565b610c66565b610be0565b610b3a565b610ae7565b610933565b6108e5565b61087a565b61069b565b610390565b6101df565b610164565b6004359063ffffffff8216820361015f57565b600080fd5b3461015f57602036600319011261015f5763ffffffff61018261014c565b166000526001602052602060016040600020015460c01c604051908152f35b6001600160401b0381160361015f57565b9181601f8401121561015f578235916001600160401b03831161015f576020838186019501011161015f57565b3461015f57608036600319011261015f576101f861014c565b602435610204816101a1565b6044356001600160401b03811161015f576102239036906004016101b2565b506064356001600160401b03811161015f576102439036906004016101b2565b9390916102728263ffffffff1660005260016020526001600160401b0360016040600020015460801c16151590565b61033a576103369461031f8361031160016102d66103249963ffffffff6102f49916600052826020526102be6002604060002001549563ffffffff166000526002602052604060002090565b906001600160401b0316600052602052604060002090565b0154936103026102e4611297565b60405198899160208301906112d2565b03601f198101895288610609565b604051978893602085016112f7565b03601f198101865285610609565b611879565b60405190151581529081906020820190565b0390f35b7fb3e346700000000000000000000000000000000000000000000000000000000060005260046000fd5b600435906001600160a01b038216820361015f57565b602435906001600160a01b038216820361015f57565b3461015f57604036600319011261015f576103a9610364565b6103b161037a565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005491906001600160401b036103ff60ff604086901c16156103f2565b1590565b946001600160401b031690565b16801590816105b0575b60011490816105a6575b15908161059d575b5061057357610484918361047b60016001600160401b03197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b61050e57611333565b61048a57005b6104df68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b61056e6801000000000000000068ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b611333565b7ff92ee8a90000000000000000000000000000000000000000000000000000000060005260046000fd5b9050153861041b565b303b159150610413565b849150610409565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b038211176105e957604052565b6105b8565b606081019081106001600160401b038211176105e957604052565b90601f801991011681019081106001600160401b038211176105e957604052565b60405190610639606083610609565b565b906106396040519283610609565b6001600160401b0381116105e957601f01601f191660200190565b92919261067082610649565b9161067e6040519384610609565b82948184528183011161015f578281602093846000960137010152565b604036600319011261015f576106af610364565b6024356001600160401b03811161015f573660238201121561015f576106df903690602481600401359101610664565b906001600160a01b037f000000000000000000000000664b8b7617998a4925098310d56b429c7c2f24bc16803014908115610845575b5061081b57610722611a3e565b604051917f52d1902d0000000000000000000000000000000000000000000000000000000083526020836004816001600160a01b0386165afa600093816107ea575b5061078757634c9c8ce360e01b6000526001600160a01b03821660045260246000fd5b907f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc83036107bb576107b99250612391565b005b7faa1d49a400000000000000000000000000000000000000000000000000000000600052600483905260246000fd5b61080d91945060203d602011610814575b6108058183610609565b8101906118b7565b9238610764565b503d6107fb565b7fe07c8dba0000000000000000000000000000000000000000000000000000000060005260046000fd5b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416141538610715565b3461015f57600036600319011261015f576001600160a01b037f000000000000000000000000664b8b7617998a4925098310d56b429c7c2f24bc16300361081b5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b3461015f57600036600319011261015f57602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b60ff1981160361015f57565b3461015f5761012036600319011261015f576004356001600160401b03811161015f576109649036906004016101b2565b5060243561097181610927565b6044359060c036606319011261015f5760206000610a45610100860194610a396109ba6040516109b5816109a78b8a83016118d2565b03601f198101835282610609565b6124d3565b956109a76109d56109c96114d6565b6001600160401b031690565b936109e16109c96114e2565b6109ec6109c96114ee565b60c43560e435916101043593604051998a9860081c8e8a019694929091610100989694928852602088015260408701526060860152608085015260a084015260c083015260e08201520190565b604051918280926112d2565b039060025afa15610a9a5761033692610324927effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000511692610a87604061063b565b938452602084015261014082019161261d565b6118c6565b60005b838110610ab25750506000910152565b8181015183820152602001610aa2565b90602091610adb81518092818552858086019101610a9f565b601f01601f1916010190565b3461015f57602036600319011261015f5763ffffffff610b0561014c565b166000526001602052610336610b26610b216040600020611370565b6119c6565b604051918291602083526020830190610ac2565b3461015f57600036600319011261015f57610b53611a3e565b60006001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005473ffffffffffffffffffffffffffffffffffffffff1981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461015f57600036600319011261015f5760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b90604060031983011261015f5760043563ffffffff8116810361015f5791602435906001600160401b03821161015f57610c62916004016101b2565b9091565b3461015f57610cb6610c7736610c26565b509190610c82611a9f565b63ffffffff8116600052600160205260406000209283610cb0610ca583806113ed565b9260208101906113ed565b92611b51565b15610cf95760010180547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16700100000000000000000000000000000000179055005b7fb1333bc80000000000000000000000000000000000000000000000000000000060005260046000fd5b3461015f5760a036600319011261015f57610d3c61014c565b602435610d48816101a1565b6044356001600160401b03811161015f57610d679036906004016101b2565b9190926064356001600160401b03811161015f57610d899036906004016101b2565b90608435946001600160401b03861161015f5761033696610db16103249736906004016101b2565b969095611402565b3461015f57600036600319011261015f576103366040805190610ddc8183610609565b600582527f352e302e30000000000000000000000000000000000000000000000000000000602083015251918291602083526020830190610ac2565b3461015f57606036600319011261015f57610e3161014c565b6024356001600160401b03811161015f57610e509036906004016101b2565b506044356001600160401b03811161015f57610e709036906004016101b2565b5090610e7a6114b7565b50610e83611a9f565b608081016001600160401b038135610e9a816101a1565b16158015610fbe575b610f9457610f46610f40610f3b610f33610f2e86610f2789610f22610f028d610eec6103369f9d610ee7610f679f63ffffffff166000526001602052604060002090565b611504565b63ffffffff166000526002602052604060002090565b610f0b8b6114fa565b6001600160401b0316600052602052604060002090565b611657565b3690611699565b611ca4565b953690611716565b611cb7565b916114fa565b90610f4f61062a565b93845260208401526001600160401b03166040830152565b604080518251815260208084015190820152918101516001600160401b0316908201529081906060820190565b7f920ed63f0000000000000000000000000000000000000000000000000000000060005260046000fd5b50610fcd83356109c9816101a1565b15610ea3565b3461015f57604036600319011261015f57610336610b26611035611030610ff861014c565b63ffffffff6024359161100a836101a1565b1660005260026020526040600020906001600160401b0316600052602052604060002090565b611751565b611cbc565b3461015f57602036600319011261015f57602061108061105861014c565b63ffffffff1660005260016020526001600160401b0360016040600020015460801c16151590565b6040519015158152f35b3461015f57604036600319011261015f5760206001600160401b036110e76110b061014c565b63ffffffff602435916110c2836101a1565b16600052600284526040600020906001600160401b0316600052602052604060002090565b5416604051908152f35b3461015f57602036600319011261015f576107b961110d610364565b611115611a3e565b611782565b3461015f5761112836610c26565b50906111326114b7565b5061113b611a9f565b6111558163ffffffff166000526001602052604060002090565b9160018301546001600160401b03611177826001600160401b039060801c1690565b1661033a57610f676111e2611240610f3b61123a610f2e896080610336996112246112076109c99b6102be8f6111d6886111d06111c48463ffffffff166000526002602052604060002090565b610f0b60c08b016114fa565b88611dd3565b509f819e919460c01c90565b6001600160401b038416116112485763ffffffff166000526002602052604060002090565b9a8b906001600160401b03166001600160401b0319825416179055565b60a081013560018b015501356002890155611370565b94611751565b610f4f61062a565b60018801805477ffffffffffffffffffffffffffffffffffffffffffffffff1660c085901b7fffffffffffffffff00000000000000000000000000000000000000000000000016179055610eec565b604051906112a6604083610609565b600482527f7761736d000000000000000000000000000000000000000000000000000000006020830152565b906112e560209282815194859201610a9f565b0190565b908092918237016000815290565b909280926021947f0300000000000000000000000000000000000000000000000000000000000000845260018401528483013701016000815290565b61134f6001600160a01b0392611347612338565b611115612338565b1673ffffffffffffffffffffffffffffffffffffffff196000541617600055565b9060405161137d816105ce565b60a06002829460ff19815460081b1684526113e66113d660018301546001600160401b03811660208801526001600160401b03808260401c161660408801526001600160401b03808260801c1616606088015260c01c90565b6001600160401b03166080860152565b0154910152565b90359060fe198136030182121561015f570190565b92509594936114338363ffffffff1660005260016020526001600160401b0360016040600020015460801c16151590565b61033a576114af8361031160016114796114b49b63ffffffff602099166000528289526102be6002604060002001549563ffffffff166000526002602052604060002090565b015493610302611487611297565b6040519889916114a08284019182815194859201610a9f565b0103601f198101895288610609565b611c8e565b90565b604051906114c4826105ee565b60006040838281528260208201520152565b6064356114b4816101a1565b6084356114b4816101a1565b60a4356114b4816101a1565b356114b4816101a1565b9060a0600291803561151581610927565b60081c6001600160f81b03198554161784556116506001850161155c602084013561153f816101a1565b825467ffffffffffffffff19166001600160401b03909116178255565b604083013561156a816101a1565b7fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff6fffffffffffffffff000000000000000083549260401b16911617815560608301356115b6816101a1565b7fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff77ffffffffffffffff0000000000000000000000000000000083549260801b169116178155611608608084016114fa565b77ffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffff00000000000000000000000000000000000000000000000083549260c01b169116179055565b0135910155565b906040600291611688813561166b816101a1565b855467ffffffffffffffff19166001600160401b03909116178555565b602081013560018501550135910155565b91908260c091031261015f576040516116b1816105ce565b60a080829480356116c181610927565b845260208101356116d1816101a1565b602085015260408101356116e4816101a1565b604085015260608101356116f7816101a1565b6060850152608081013561170a816101a1565b60808501520135910152565b919082606091031261015f5760405161172e816105ee565b6040808294803561173e816101a1565b8452602081013560208501520135910152565b9060405161175e816105ee565b6040600282946001600160401b038154168452600181015460208501520154910152565b6001600160a01b0316801561181f576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300548273ffffffffffffffffffffffffffffffffffffffff198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b903590607e198136030182121561015f570190565b634e487b7160e01b600052602160045260246000fd5b813593929136819003605e190185121561015f576118a59461189e602083018361184e565b9101612044565b60128110156118b2571590565b611863565b9081602091031261015f575190565b6040513d6000823e3d90fd5b6040809282370190565b90926000611988602092610a396101008601976109a761190a6109a76109b58c6040519283918c83016118d2565b986119176109c9866114fa565b946119266109c98a83016114fa565b906119366109c9604083016114fa565b60608201359060a0608084013593013593604051998a9860081c8e8a019694929091610100989694928852602088015260408701526060860152608085015260a084015260c083015260e08201520190565b039060025afa15610a9a576114b4927effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000511692610a87604061063b565b60ff19815116906001600160401b03602082015116906001600160401b036040820151166001600160401b036060830151169060a06001600160401b036080850151169301519360405195602087015260408601526060850152608084015260a083015260c082015260c081526114b460e082610609565b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303611a7157565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b6001600160a01b03600054163303611ab357565b7fe54f8f9d0000000000000000000000000000000000000000000000000000000060005260046000fd5b91909160a08060c08301946001600160401b038135611afb816101a1565b1684526001600160401b036020820135611b14816101a1565b1660208501526001600160401b036040820135611b30816101a1565b16604085015260608101356060850152608081013560808501520135910152565b90611b5b836114fa565b6001600160401b03611b6f6109c9876114fa565b911610611c5a5780611bcb611bd592611bc4611bb8611ba16111c48863ffffffff166000526002602052604060002090565b9663ffffffff166000526002602052604060002090565b610f0b60c08a016114fa565b9486611dd3565b5093905085611dd3565b509050611be1836114fa565b6001600160401b03611bf56109c9876114fa565b911603611c3e575050604051611c13816109a7602082019485611add565b51902090604051611c2c816109a7602082019485611add565b51902003611c3957600090565b600190565b6001600160401b039250829193501691161115611c3957600090565b7f635205340000000000000000000000000000000000000000000000000000000060005260046000fd5b600911156118b257565b611c9b95949392916128b3565b6103ee81611c84565b611cad906119c6565b6020815191012090565b611cad905b6001600160401b0381511690604060208201519101519060405192602084015260408301526060820152606081526114b4608082610609565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03633b9aca00911602906001600160401b038216918203611d2f57565b611cf5565b6001600160401b036001911601906001600160401b038211611d2f57565b906001600160401b03809116911601906001600160401b038211611d2f57565b90633b9aca00820291808304633b9aca001490151715611d2f57565b81810292918115918404141715611d2f57565b903590601e198136030182121561015f57018035906001600160401b03821161015f5760200191813603831361015f57565b9291906001600160401b03611def82546001600160401b031690565b1693841561200657611e00816114fa565b92611e0d60c083016114fa565b926001600160401b038516906001600160401b038516821115611fdc57611e53611e41611e3c602087016114fa565b611d0b565b611e4d604087016114fa565b90611d52565b976001600160401b03891690811115611fb257611e726109c942611d72565b6001850154611e8b826001600160401b0383168d612990565b611f8857611ea8916109c99160401c6001600160401b0316611e4d565b1115611f5e576109c96002611ebf92015495611d34565b14611f22575b90611eed926103ee92611ee7611ede60e0850185611da1565b50915460081b90565b906118dc565b611ef8579190600090565b7f396df4ec0000000000000000000000000000000000000000000000000000000060005260046000fd5b9082606082013503611f345790611ec5565b7f895cf0ce0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f4ccc303c0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f6c4c87b60000000000000000000000000000000000000000000000000000000060005260046000fd5b7f14a286e40000000000000000000000000000000000000000000000000000000060005260046000fd5b7ff97b09220000000000000000000000000000000000000000000000000000000060005260046000fd5b7f09128dc80000000000000000000000000000000000000000000000000000000060005260046000fd5b600511156118b257565b600611156118b257565b93919293612051816129b6565b61205d81959295612030565b61232d57836120749261206e612a0d565b90612a6c565b61207d81611c84565b806121f7575061208c81612d04565b61209881969296612030565b6121ed576120c892610311926120c36120af612dda565b926040519586916020830160209181520190565b612e04565b6120d18161203a565b806120e65750036120e157600090565b600990565b8092506120f3915061203a565b600181036121015750600490565b61210a8161203a565b600281036121185750600590565b6121218161203a565b6003810361212f5750600690565b6121388161203a565b600481036121465750600790565b8061215260059261203a565b146121e85760405162461bcd60e51b815260206004820152605660248201527f766572696679436861696e65644e6f6e4d656d626572736869703a206e6f6e2060448201527f65786861757374697665207061747465726e206d61746368696e67206f6e205660648201527f65726966794e6f6e4578697374656e63654572726f7200000000000000000000608482015260a490fd5b600890565b5050505050600390565b935050505061220581611c84565b600181036122135750600a90565b61221c81611c84565b6003810361222a5750600c90565b61223381611c84565b600481036122415750600d90565b61224a81611c84565b600581036122585750600e90565b61226181611c84565b6006810361226f5750600f90565b61227881611c84565b600781036122865750601090565b80612292600892611c84565b146123285760405162461bcd60e51b815260206004820152605660248201527f766572696679436861696e65644e6f6e4d656d626572736869703a206e6f6e2060448201527f65786861757374697665207061747465726e206d61746368696e67206f6e205660648201527f65726966794e6f6e4578697374656e63654572726f7200000000000000000000608482015260a490fd5b601190565b505050505050600390565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561236757565b7fd7e6bcf80000000000000000000000000000000000000000000000000000000060005260046000fd5b90813b1561246b576001600160a01b0382168073ffffffffffffffffffffffffffffffffffffffff197f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a28051156124385761243591612e82565b50565b50503461244157565b7fb398979f0000000000000000000000000000000000000000000000000000000060005260046000fd5b6001600160a01b0382634c9c8ce360e01b6000521660045260246000fd5b600019810191908211611d2f57565b81156124a2570690565b634e487b7160e01b600052601260045260246000fd5b9060018201809211611d2f57565b91908201809211611d2f57565b6126186114b4916109a76125ee604051926124ef60c085610609565b608884527f1f333139281e100f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c60208501527f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c60408501527f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c60608501527f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c60808501527f5c5c5c5c5c5c5c5c00000000000000000000000000000000000000000000000060a08501526109a76125da6125bf612ec8565b926040519283916125d46020840180976112d2565b906112d2565b519020604051928391602083019586612f9b565b5190207f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000090612498565b6124b8565b926126289082612fb9565b9391929092156128935761263f916103ee9161311a565b61288b576101006040519384377f07b8dbefa90bde075a26318e5066db729155514e3c06b888d4e03c56d82c97e66101008401527f02aca5d2a73f8d34e4b26eee3932365e6526c8d5e2f3347d679c2cb1867104dc6101208401527f2edb19cbb2b6ad0c98fdd7d1845500c26e497dc35e4cdc1cb02cc65dc4ba1bf26101408401527f1696ccafaefe49a5d8bad8e79630e19b25e5392a203aff0042d0216f254806f56101608401527f245229d9b076b3c0e8a4d70bde8c1cccffa08a9fae7557b165b3b0dbd653e2c76101808401527f253ec85988dbb84e46e94b5efa3373b47a000b4ac6c86b2d4b798d274a1823026101a08401527f07090a82e8fabbd39299be24705b92cf208ee8b3487f6f2b39ff27978a29a1db6101c08401527f2424bcc1f60a5472685fd50705b2809626e170120acaf441e133a2bd5e61d2446101e08401527f25833b15e156ae01f2741f4f4120ddb466c52eb83a959f79eb99b23caa7fbf1d6102008401527f04ddc8d30d5c438ca34091c5d2c6ded571382cba2b3c4fdc4222df2938b4e51e6102208401526102408301526102608201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26102808201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6102a08201527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec6102c08201527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d6102e08201526020816103008160085afa90511690565b505050600090565b5050505050600090565b634e487b7160e01b600052603260045260246000fd5b919490936128c96128c4848061184e565b612d04565b6128d581969296612030565b61298457612901926128fb6128ea868061184e565b936128f3612a0d565b923691610664565b92612e04565b61290a8161203a565b80612976575091612959939161292761294694602081019061184e565b612954612932612dda565b926040519687916020830160209181520190565b03601f198101875286610609565b61336b565b6129628161203a565b8061296d5750600090565b6114b49061326d565b925050506114b4915061326d565b50505050505050600290565b6001600160401b0380919392931692168201809211611d2f576001600160401b03161190565b602081016129cc6129c7828461184e565b613410565b15612a00575060408101906129e46129c7838361184e565b156129f3575050600090600490565b610c62916128c49161184e565b6128c490610c629261184e565b612a156114b7565b50604051612a22816105ee565b6021815260046020820152600c604082015290565b903590601e198136030182121561015f57018035906001600160401b03821161015f57602001918160051b3603831361015f57565b9092916020820190612a87612a81838561184e565b80611da1565b9190946040850195612a9c612a81888861184e565b949093612aaf6103ee6129c7898b61184e565b612c8c575b612ac46103ee6129c78b8b61184e565b612c16575b508015938480612c0e575b612bff5785159586159182612be7575b5050612bd95783159182612bc2575b50509050612bb75715612b47575050918183612b30612b1e612b28612b1e6103ee97612b389961184e565b6060810190612a37565b94909361184e565b9390506136c2565b612b42575b600090565b600690565b90929015612b825750918183612b6c612b1e612b28612b1e6103ee97612b749961184e565b939050613651565b612b7d57600090565b600790565b92612bad93612ba5612b1e612b9d612b1e6103ee978761184e565b93909561184e565b93909261354a565b15612b3d57600890565b505050505050600590565b612bcf925060009361348b565b1315803880612af3565b505050505050505050600490565b6000925090612bf6918661348b565b12153880612ae4565b50505050505050505050600390565b508515612ad4565b612c6b9088612c258b8261184e565b918c612c658d612c5d612c53612c49612c41612a81858a61184e565b94909861184e565b6020810190611da1565b9690923691610664565b943691610664565b9361336b565b612c748161203a565b612c7e5738612ac9565b505050505050505050600290565b612cb6612c99888a61184e565b89838d612c658c612c5d612c53612c49612c41612a81858a61184e565b612cbf8161203a565b15612ab45750505050505050505050600190565b600311156118b257565b9190811015612cff5760051b81013590603e198136030182121561015f570190565b61289d565b60408101612d128183611da1565b905015612dd057612d26612d479183611da1565b90612d318480611da1565b90612d3f6020870187611da1565b949093613785565b919091612d5381612cd3565b612dc65760608101612d658183612a37565b9190506000925b828410612d7d575050505090600090565b90919293612d9e90612d9986612d938686612a37565b90612cdd565b613839565b949094612daa81612cd3565b612db957600101929190612d6c565b5050505050600090600390565b5050600090600290565b5050600090600190565b612de26114b7565b50604051612def816105ee565b60208152600160208201526001604082015290565b929091612e1b612e148580611da1565b3691610664565b60208151910120906020815191012003612e7a57612e3f612e146020850185611da1565b60208151910120906020815191012003612e7357612e5c916138b7565b612e6581612030565b612e6e57600090565b600390565b5050600290565b505050600190565b6000806114b493602081519101845af43d15612ec0573d91612ea383610649565b92612eb16040519485610609565b83523d6000602085013e6139a3565b6060916139a3565b60405190612ed760c083610609565b608882527f363636363636363600000000000000000000000000000000000000000000000060a0837f75595b5342747a6536363636363636363636363636363636363636363636363660208201527f363636363636363636363636363636363636363636363636363636363636363660408201527f363636363636363636363636363636363636363636363636363636363636363660608201527f363636363636363636363636363636363636363636363636363636363636363660808201520152565b6020929190612fb1849282815194859201610a9f565b019081520190565b90916040519260408401907f2f5d8a3817f21d3e453573c90c3cc47b7ff235fad7bdfbd59bbd6ae5d153273e8552604060208601947f147fa22142b1fd86ce75fc87230a0feac8765d02938784dcfc828d17d7e7c432865283377f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016040808760808160065afa937f2a81b98e1c997bd01a20893a08a46c6804493e838c1a0ff6c8c069ef5ab66b9a8152602060608901947f276938ada8075cec20d4d6a1f157ec94cc7ba6207c98576e98c1ad9d6378fb6f86527f0326e7d44688ce5903676b7d646e46a5938c8e5fd8cd54e4d5aa3300649f3cfc6001825160808d0199818b5288888860608160075afa92101616868d60808160065afa1616967f179496ce140df89ce35c5ee7fb496efdffda5e5d3b95ff9116e2e5df96b36ab7855252015180955260608160075afa9210161660408460808160065afa169251915190565b906040908180519384377f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2828401527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60608401527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60808401527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60a084015260c08301377f07b8dbefa90bde075a26318e5066db729155514e3c06b888d4e03c56d82c97e66101008201527f02aca5d2a73f8d34e4b26eee3932365e6526c8d5e2f3347d679c2cb1867104dc6101208201527f2edb19cbb2b6ad0c98fdd7d1845500c26e497dc35e4cdc1cb02cc65dc4ba1bf26101408201527f1696ccafaefe49a5d8bad8e79630e19b25e5392a203aff0042d0216f254806f56101608201526020816101808160085afa90511690565b6132768161203a565b600181036132845750600390565b61328d8161203a565b6002810361329b5750600490565b6132a48161203a565b600381036132b25750600590565b6132bb8161203a565b600481036132c95750600690565b806132d560059261203a565b14612b7d5760405162461bcd60e51b815260206004820152605060248201527f766572696679436861696e65644d656d626572736869703a206e6f6e2065786860448201527f61757374697665207061747465726e206d61746368696e67206f6e205665726960648201527f66794578697374656e63654572726f7200000000000000000000000000000000608482015260a490fd5b929390919361337d612e148580611da1565b60208151910120906020815191012003613407576133a1612e146020850185611da1565b602081519101209060208151910120036133ff576133bf90826138b7565b6133c881612030565b6133f8576133d590612d04565b6133de81612030565b6133f157036133ec57600090565b600590565b5050600490565b5050600390565b505050600290565b50505050600190565b61341a8180611da1565b905061345f5761342d6020820182611da1565b905061345f576134406040820182611da1565b905061345f57806060613454920190612a37565b9050612b3d57600190565b50600090565b908151811015612cff570160200190565b9015612cff5790565b90821015612cff570190565b9190613498828451613a33565b92839160005b8381106134c457505051116134bd57116134b757600090565b60001990565b5050600190565b909192506134e36134d58285613465565b516001600160f81b03191690565b6001600160f81b031961351861350b6134fd85898861347f565b356001600160f81b03191690565b6001600160f81b03191690565b91168181101561352f575050505050505060001990565b11613540576001019084929161349e565b5050505050600190565b9293909161355781612489565b9261356183612489565b935b613574612e14612a81838686612cdd565b6020815191012061358c612e14612a8188888c612cdd565b60208151910120148061361a575b613602576135c16103ee6135af838686612cdd565b6135ba88888c612cdd565b9089613a4f565b6135f6576135d3926103ee9287613651565b6135ed576135e4936103ee936136c2565b612b3d57600190565b50505050600090565b50505050505050600090565b61360e61361491612489565b94612489565b93613563565b5061362c612e14612c49838686612cdd565b60208151910120613644612e14612c4988888c612cdd565b602081519101201461359a565b805160208201518101939291848211611d2f5760408101518201809211611d2f57511560011715611d2f5760009360005b8681106136955750505050505050600190565b6136ab8684846136a6858a8a612cdd565b613aa1565b156136b857600101613682565b5050505050905090565b9091600082511560011715611d2f5750602082015160408301519251929160005b8681106136f65750505050505050600190565b6137078585856136a685878c612cdd565b156135f6576001016136e3565b9061371e82610649565b61372b6040519182610609565b828152809261373c601f1991610649565b0190602036910137565b946020612fb19461376f85839b9a9895998597859b823701916000835282815194859201610a9f565b0191823701916000835282815194859201610a9f565b949390919293841561382b57801561381d5760006020916137ad6137a888613b03565b613714565b936137b88589613b22565b506137c8604051809381936112e9565b039060025afa15610a9a576020946109a761380b94610a39936000978851926137f26137a8613ae6565b926137fc84613b63565b506040519889978d8901613746565b039060025afa15610a9a576000805191565b505050505050600090600290565b505050505050600090600190565b6138a360009160209361389285613860816138548680611da1565b92909682810190611da1565b909581604051978589968688019b8c37860192858401526040830137010187838201520301601f198101835282610609565b604051928392839251928391610a9f565b8101039060025afa15610a9a576000805191565b90604082016138c68184611da1565b905015612e7a576138ec6134fd6138e66001600160f81b03199386611da1565b90613476565b16612e735761390160408201518251906124c6565b60608301926139108482612a37565b94905060005b85811061392857505050505050600090565b61393681612d938486612a37565b846139418280611da1565b9050602088015111918215613987575b8215613971575b505061396657600101613916565b505050505050600290565b61397d91925080611da1565b9050118438613958565b915061399c61350b6134fd6138e68580611da1565b1591613951565b906139e257508051156139b857805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580613a2a575b6139f3575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b156139eb565b9080821015613a40575090565b905090565b600211156118b257565b90613a5a9082613b74565b92909160028410156118b257836135ed57613a8091613a7891613b74565b919093613a45565b613a8981613a45565b613a9a57613a96906124b8565b1490565b5050600090565b9190613aad8380611da1565b905010908115613ad1575b50613a9a57806020613acb920190611da1565b90501490565b9050613add8280611da1565b90501138613ab8565b60016000805b613af4575090565b60019091019060071c80613aec565b60019060071c805b613b13575090565b60019091019060071c80613b0b565b919091602060009301607f8216915b60071c918215613b57576001918291608017815301930190607f81169093909193613b31565b90600193949250530190565b600091908290602090810190613b57565b60005b60028110613b8a57505050600090600190565b613b95825182611d8e565b60208301518101808211611d2f5760408401518201809211611d2f57826001039060018211611d2f57600192613bd0613bd793875190611d8e565b9187613aa1565b151514613be657600101613b77565b9150509060009056fea26469706673582212202a79c3296a89a4fc8af16dfc20586689525c4aeeade1b2ff44468ea6a02effba64736f6c634300081b0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.