Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 645 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Update Tree Root | 21795791 | 23 hrs ago | IN | 0 ETH | 0.0001463 | ||||
Update Tree Root | 21788622 | 47 hrs ago | IN | 0 ETH | 0.00040415 | ||||
Update Tree Root | 21781450 | 2 days ago | IN | 0 ETH | 0.00020131 | ||||
Update Tree Root | 21774291 | 3 days ago | IN | 0 ETH | 0.00024436 | ||||
Update Tree Root | 21767134 | 4 days ago | IN | 0 ETH | 0.00266391 | ||||
Update Tree Root | 21759978 | 5 days ago | IN | 0 ETH | 0.00031057 | ||||
Update Tree Root | 21752823 | 6 days ago | IN | 0 ETH | 0.00025562 | ||||
Update Tree Root | 21745657 | 7 days ago | IN | 0 ETH | 0.00155043 | ||||
Update Tree Root | 21738505 | 8 days ago | IN | 0 ETH | 0.00056025 | ||||
Update Tree Root | 21731334 | 9 days ago | IN | 0 ETH | 0.0005323 | ||||
Update Tree Root | 21724168 | 10 days ago | IN | 0 ETH | 0.00076334 | ||||
Update Tree Root | 21717005 | 11 days ago | IN | 0 ETH | 0.00142169 | ||||
Update Tree Root | 21709834 | 12 days ago | IN | 0 ETH | 0.00057684 | ||||
Update Tree Root | 21702660 | 13 days ago | IN | 0 ETH | 0.0009995 | ||||
Update Tree Root | 21695502 | 14 days ago | IN | 0 ETH | 0.00149198 | ||||
Update Tree Root | 21688330 | 15 days ago | IN | 0 ETH | 0.00206996 | ||||
Update Tree Root | 21688329 | 15 days ago | IN | 0 ETH | 0.00209475 | ||||
Update Tree Root | 21681164 | 16 days ago | IN | 0 ETH | 0.00135362 | ||||
Update Tree Root | 21673996 | 17 days ago | IN | 0 ETH | 0.00165201 | ||||
Update Tree Root | 21666835 | 18 days ago | IN | 0 ETH | 0.00520036 | ||||
Update Tree Root | 21659663 | 19 days ago | IN | 0 ETH | 0.00361351 | ||||
Update Tree Root | 21652504 | 20 days ago | IN | 0 ETH | 0.00308046 | ||||
Update Tree Root | 21645338 | 21 days ago | IN | 0 ETH | 0.00164861 | ||||
Update Tree Root | 21638171 | 22 days ago | IN | 0 ETH | 0.00162481 | ||||
Update Tree Root | 21631005 | 23 days ago | IN | 0 ETH | 0.00123791 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
19228593 | 359 days ago | Contract Creation | 0 ETH |
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:
Witness
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 10000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import { OwnableRoles } from "solady/auth/OwnableRoles.sol"; import { LibBit } from "solady/utils/LibBit.sol"; import { LibZip } from "solady/utils/LibZip.sol"; import { SafeCastLib } from "solady/utils/SafeCastLib.sol"; import { InvalidProofBadLeftRange, InvalidProofBadRightRange, InvalidProofLeafIdxOutOfBounds, InvalidProofUnrecognizedRoot, InvalidUpdateNewRangeMismatchWrongLength, InvalidUpdateOldRangeMismatchShouldBeEmpty, InvalidUpdateOldRangeMismatchWrongCurrentRoot, InvalidUpdateOldRangeMismatchWrongLength, InvalidUpdateTreeSizeMustGrow, IWitness, Proof, RootInfo } from "./interfaces/IWitness.sol"; import { getRangeSizeForNonZeroBeginningInterval, getRoot, getRootForMergedRange, merge, ProofError, validateProof } from "./WitnessUtils.sol"; /// @title Witness /// @author sina.eth /// @custom:coauthor runtheblocks.eth /// @notice The core Witness smart contract. /// @dev The Witness smart contract tracks a merkle mountain range and enforces /// that any newly posted merkle root is consistent with the previous root. contract Witness is IWitness, OwnableRoles { using SafeCastLib for uint256; using LibBit for uint256; /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ uint256 public constant UPDATER_ROLE = _ROLE_0; /*////////////////////////////////////////////////////////////////////////// MUTABLE STORAGE //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc IWitness bytes32 public currentRoot; mapping(bytes32 root => RootInfo cache) internal _rootInfo; /// @inheritdoc IWitness function rootInfo(bytes32 root) public view virtual returns (RootInfo memory) { return _rootInfo[root]; } /// @inheritdoc IWitness function rootCache(bytes32 root) public view virtual returns (uint256) { return _rootInfo[root].treeSize; } /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ /// @dev Emits an {OwnableRoles.OwnershipTransferred} event. /// @param owner The address that should be set as the initial contract owner. constructor(address owner) { _initializeOwner(owner); _grantRoles(owner, UPDATER_ROLE); } /*////////////////////////////////////////////////////////////// READ METHODS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IWitness function getCurrentTreeState() external view virtual returns (bytes32, uint256) { bytes32 _currentRoot = currentRoot; return (_currentRoot, _rootInfo[_currentRoot].treeSize); } /// @inheritdoc IWitness function getLastUpdateTime() external view virtual returns (uint256) { return _rootInfo[currentRoot].timestamp; } /// @inheritdoc IWitness function getLastUpdateBlock() external view virtual returns (uint256) { return _rootInfo[currentRoot].height; } /// @inheritdoc IWitness function verifyProof(Proof calldata proof) external view virtual { ProofError e = validateProof(proof, _rootInfo[proof.targetRoot].treeSize); if (e == ProofError.NONE) { return; } if (e == ProofError.InvalidProofLeafIdxOutOfBounds) { revert InvalidProofLeafIdxOutOfBounds(); } if (e == ProofError.InvalidProofBadLeftRange) { revert InvalidProofBadLeftRange(); } if (e == ProofError.InvalidProofBadRightRange) { revert InvalidProofBadRightRange(); } if (e == ProofError.InvalidProofUnrecognizedRoot) { revert InvalidProofUnrecognizedRoot(); } } /// @inheritdoc IWitness function safeVerifyProof(Proof calldata proof) external view returns (bool isValid) { return validateProof(proof, _rootInfo[proof.targetRoot].treeSize) == ProofError.NONE; } /*////////////////////////////////////////////////////////////// WRITE METHODS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IWitness function updateTreeRoot( uint256 newSize, bytes32[] calldata oldRange, bytes32[] calldata newRange ) external virtual onlyRoles(UPDATER_ROLE) { bytes32 _currentRoot = currentRoot; // ---HANDLE EMPTY TREE CASE--- if (_currentRoot == bytes32(0)) { // Old range should be empty. if (oldRange.length != 0) { // Provided old range must be empty. revert InvalidUpdateOldRangeMismatchShouldBeEmpty(); } // Verify the size of newRange corresponds to the interval [0, newTreeSize). if (newSize.popCount() != newRange.length) { // Provided new range does not match expected size. revert InvalidUpdateNewRangeMismatchWrongLength(); } // Update the tree state. bytes32 root = getRoot(newRange); currentRoot = root; _rootInfo[root] = RootInfo(newSize.toUint176(), block.timestamp.toUint40(), block.number.toUint40()); emit RootUpdated(root, newSize); return; } // ---NON-EMPTY TREE CASE; VALIDATE OLD RANGE--- // Verify oldRange corresponds to the old root. if (_currentRoot != getRoot(oldRange)) { // Provided old range does not match current root. revert InvalidUpdateOldRangeMismatchWrongCurrentRoot(); } uint256 currentSize = _rootInfo[_currentRoot].treeSize; // Verify size of oldRange corresponds to the size of the old root. if (currentSize.popCount() != oldRange.length) { // Provided old range does not match current tree size. revert InvalidUpdateOldRangeMismatchWrongLength(); } // ---VALIDATE NEW RANGE--- // New range should grow the tree. if (newSize <= currentSize) { // New tree size must be greater than current tree size. revert InvalidUpdateTreeSizeMustGrow(); } // Verify the size of newRange corresponds to the interval [currentTreeSize, newTreeSize). if (getRangeSizeForNonZeroBeginningInterval(currentSize, newSize) != newRange.length) { // Provided new range does not match expected size. revert InvalidUpdateNewRangeMismatchWrongLength(); } // ---HANDLE UPDATE PT 1. MERGE RANGES & CALCULATE NEW ROOT--- // Merge oldRange with newRange to get the new combinedRange covering the new tree. // Merge starting with rightmost-entry in oldRange, which we call the seed. uint256 seedArrayIdx = oldRange.length - 1; bytes32 seed = oldRange[seedArrayIdx]; // seed may start at a non-zero height. // Since seed's size corresponds to the value expressed by lsb(currentTreeSize), // we can calculate the height of seed by finding the index of the lsb. uint256 seedHeight = currentSize.ffs(); // Tracker for the index of the seed node at its height as we merge the ranges. uint256 seedIndex = (currentSize - 1) >> seedHeight; (bytes32[] calldata mergedLeft, bytes32 newSeed, bytes32[] calldata mergedRight) = merge(oldRange[:seedArrayIdx], seed, seedHeight, seedIndex, newRange, newSize); bytes32 newRoot = getRootForMergedRange(mergedLeft, newSeed, mergedRight); // ---HANDLE UPDATE PT 2. UPDATE STATE & EMIT EVENTS--- currentRoot = newRoot; _rootInfo[newRoot] = RootInfo(newSize.toUint176(), block.timestamp.toUint40(), block.number.toUint40()); emit RootUpdated(newRoot, newSize); } /*////////////////////////////////////////////////////////////// L2 CALLDATA OPTIMIZATION //////////////////////////////////////////////////////////////*/ /// @dev Used for L2 calldata optimization. For efficiency, this function will directly return the results, /// terminating the context. If called internally, it must be called at the end of the function. fallback() external virtual { LibZip.cdFallback(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {Ownable} from "./Ownable.sol"; /// @notice Simple single owner and multiroles authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) /// for compatibility, the nomenclature for the 2-step ownership handover and roles /// may be unique to this codebase. abstract contract OwnableRoles is Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `user`'s roles is updated to `roles`. /// Each bit of `roles` represents whether the role is set. event RolesUpdated(address indexed user, uint256 indexed roles); /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) /// let roleSlot := keccak256(0x00, 0x20) /// ``` /// This automatically ignores the upper bits of the `user` in case /// they are not clean, as well as keep the `keccak256` under 32-bytes. /// /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`. uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Overwrite the roles directly without authorization guard. function _setRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Store the new value. sstore(keccak256(0x0c, 0x20), roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @dev Updates the roles directly without authorization guard. /// If `on` is true, each set bit of `roles` will be turned on, /// otherwise, each set bit of `roles` will be turned off. function _updateRoles(address user, uint256 roles, bool on) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value. let current := sload(roleSlot) // Compute the updated roles if `on` is true. let updated := or(current, roles) // Compute the updated roles if `on` is false. // Use `and` to compute the intersection of `current` and `roles`, // `xor` it with `current` to flip the bits in the intersection. if iszero(on) { updated := xor(current, and(current, roles)) } // Then, store the new value. sstore(roleSlot, updated) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) } } /// @dev Grants the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn on. function _grantRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, true); } /// @dev Removes the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn off. function _removeRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, false); } /// @dev Throws if the sender does not have any of the `roles`. function _checkRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Throws if the sender is not the owner, /// and does not have any of the `roles`. /// Checks for ownership first, then lazily checks for roles. function _checkOwnerOrRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Throws if the sender does not have any of the `roles`, /// and is not the owner. /// Checks for roles first, then lazily checks for ownership. function _checkRolesOrOwner(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { // We don't need to mask the values of `ordinals`, as Solidity // cleans dirty upper bits when storing variables into memory. roles := or(shl(mload(add(ordinals, i)), 1), roles) } } } /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { /// @solidity memory-safe-assembly assembly { // Grab the pointer to the free memory. ordinals := mload(0x40) let ptr := add(ordinals, 0x20) let o := 0 // The absence of lookup tables, De Bruijn, etc., here is intentional for // smaller bytecode, as this function is not meant to be called on-chain. for { let t := roles } 1 {} { mstore(ptr, o) // `shr` 5 is equivalent to multiplying by 0x20. // Push back into the ordinals array if the bit is set. ptr := add(ptr, shl(5, and(t, 1))) o := add(o, 1) t := shr(o, roles) if iszero(t) { break } } // Store the length of `ordinals`. mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) // Allocate the memory. mstore(0x40, ptr) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to grant `user` `roles`. /// If the `user` already has a role, then it will be an no-op for the role. function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { _grantRoles(user, roles); } /// @dev Allows the owner to remove `user` `roles`. /// If the `user` does not have a role, then it will be an no-op for the role. function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { _removeRoles(user, roles); } /// @dev Allow the caller to remove their own roles. /// If the caller does not have a role, then it will be an no-op for the role. function renounceRoles(uint256 roles) public payable virtual { _removeRoles(msg.sender, roles); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the roles of `user`. function rolesOf(address user) public view virtual returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Load the stored value. roles := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles != 0; } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles == roles; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by an account with `roles`. modifier onlyRoles(uint256 roles) virtual { _checkRoles(roles); _; } /// @dev Marks a function as only callable by the owner or by an account /// with `roles`. Checks for ownership first, then lazily checks for roles. modifier onlyOwnerOrRoles(uint256 roles) virtual { _checkOwnerOrRoles(roles); _; } /// @dev Marks a function as only callable by an account with `roles` /// or the owner. Checks for roles first, then lazily checks for ownership. modifier onlyRolesOrOwner(uint256 roles) virtual { _checkRolesOrOwner(roles); _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ROLE CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // IYKYK uint256 internal constant _ROLE_0 = 1 << 0; uint256 internal constant _ROLE_1 = 1 << 1; uint256 internal constant _ROLE_2 = 1 << 2; uint256 internal constant _ROLE_3 = 1 << 3; uint256 internal constant _ROLE_4 = 1 << 4; uint256 internal constant _ROLE_5 = 1 << 5; uint256 internal constant _ROLE_6 = 1 << 6; uint256 internal constant _ROLE_7 = 1 << 7; uint256 internal constant _ROLE_8 = 1 << 8; uint256 internal constant _ROLE_9 = 1 << 9; uint256 internal constant _ROLE_10 = 1 << 10; uint256 internal constant _ROLE_11 = 1 << 11; uint256 internal constant _ROLE_12 = 1 << 12; uint256 internal constant _ROLE_13 = 1 << 13; uint256 internal constant _ROLE_14 = 1 << 14; uint256 internal constant _ROLE_15 = 1 << 15; uint256 internal constant _ROLE_16 = 1 << 16; uint256 internal constant _ROLE_17 = 1 << 17; uint256 internal constant _ROLE_18 = 1 << 18; uint256 internal constant _ROLE_19 = 1 << 19; uint256 internal constant _ROLE_20 = 1 << 20; uint256 internal constant _ROLE_21 = 1 << 21; uint256 internal constant _ROLE_22 = 1 << 22; uint256 internal constant _ROLE_23 = 1 << 23; uint256 internal constant _ROLE_24 = 1 << 24; uint256 internal constant _ROLE_25 = 1 << 25; uint256 internal constant _ROLE_26 = 1 << 26; uint256 internal constant _ROLE_27 = 1 << 27; uint256 internal constant _ROLE_28 = 1 << 28; uint256 internal constant _ROLE_29 = 1 << 29; uint256 internal constant _ROLE_30 = 1 << 30; uint256 internal constant _ROLE_31 = 1 << 31; uint256 internal constant _ROLE_32 = 1 << 32; uint256 internal constant _ROLE_33 = 1 << 33; uint256 internal constant _ROLE_34 = 1 << 34; uint256 internal constant _ROLE_35 = 1 << 35; uint256 internal constant _ROLE_36 = 1 << 36; uint256 internal constant _ROLE_37 = 1 << 37; uint256 internal constant _ROLE_38 = 1 << 38; uint256 internal constant _ROLE_39 = 1 << 39; uint256 internal constant _ROLE_40 = 1 << 40; uint256 internal constant _ROLE_41 = 1 << 41; uint256 internal constant _ROLE_42 = 1 << 42; uint256 internal constant _ROLE_43 = 1 << 43; uint256 internal constant _ROLE_44 = 1 << 44; uint256 internal constant _ROLE_45 = 1 << 45; uint256 internal constant _ROLE_46 = 1 << 46; uint256 internal constant _ROLE_47 = 1 << 47; uint256 internal constant _ROLE_48 = 1 << 48; uint256 internal constant _ROLE_49 = 1 << 49; uint256 internal constant _ROLE_50 = 1 << 50; uint256 internal constant _ROLE_51 = 1 << 51; uint256 internal constant _ROLE_52 = 1 << 52; uint256 internal constant _ROLE_53 = 1 << 53; uint256 internal constant _ROLE_54 = 1 << 54; uint256 internal constant _ROLE_55 = 1 << 55; uint256 internal constant _ROLE_56 = 1 << 56; uint256 internal constant _ROLE_57 = 1 << 57; uint256 internal constant _ROLE_58 = 1 << 58; uint256 internal constant _ROLE_59 = 1 << 59; uint256 internal constant _ROLE_60 = 1 << 60; uint256 internal constant _ROLE_61 = 1 << 61; uint256 internal constant _ROLE_62 = 1 << 62; uint256 internal constant _ROLE_63 = 1 << 63; uint256 internal constant _ROLE_64 = 1 << 64; uint256 internal constant _ROLE_65 = 1 << 65; uint256 internal constant _ROLE_66 = 1 << 66; uint256 internal constant _ROLE_67 = 1 << 67; uint256 internal constant _ROLE_68 = 1 << 68; uint256 internal constant _ROLE_69 = 1 << 69; uint256 internal constant _ROLE_70 = 1 << 70; uint256 internal constant _ROLE_71 = 1 << 71; uint256 internal constant _ROLE_72 = 1 << 72; uint256 internal constant _ROLE_73 = 1 << 73; uint256 internal constant _ROLE_74 = 1 << 74; uint256 internal constant _ROLE_75 = 1 << 75; uint256 internal constant _ROLE_76 = 1 << 76; uint256 internal constant _ROLE_77 = 1 << 77; uint256 internal constant _ROLE_78 = 1 << 78; uint256 internal constant _ROLE_79 = 1 << 79; uint256 internal constant _ROLE_80 = 1 << 80; uint256 internal constant _ROLE_81 = 1 << 81; uint256 internal constant _ROLE_82 = 1 << 82; uint256 internal constant _ROLE_83 = 1 << 83; uint256 internal constant _ROLE_84 = 1 << 84; uint256 internal constant _ROLE_85 = 1 << 85; uint256 internal constant _ROLE_86 = 1 << 86; uint256 internal constant _ROLE_87 = 1 << 87; uint256 internal constant _ROLE_88 = 1 << 88; uint256 internal constant _ROLE_89 = 1 << 89; uint256 internal constant _ROLE_90 = 1 << 90; uint256 internal constant _ROLE_91 = 1 << 91; uint256 internal constant _ROLE_92 = 1 << 92; uint256 internal constant _ROLE_93 = 1 << 93; uint256 internal constant _ROLE_94 = 1 << 94; uint256 internal constant _ROLE_95 = 1 << 95; uint256 internal constant _ROLE_96 = 1 << 96; uint256 internal constant _ROLE_97 = 1 << 97; uint256 internal constant _ROLE_98 = 1 << 98; uint256 internal constant _ROLE_99 = 1 << 99; uint256 internal constant _ROLE_100 = 1 << 100; uint256 internal constant _ROLE_101 = 1 << 101; uint256 internal constant _ROLE_102 = 1 << 102; uint256 internal constant _ROLE_103 = 1 << 103; uint256 internal constant _ROLE_104 = 1 << 104; uint256 internal constant _ROLE_105 = 1 << 105; uint256 internal constant _ROLE_106 = 1 << 106; uint256 internal constant _ROLE_107 = 1 << 107; uint256 internal constant _ROLE_108 = 1 << 108; uint256 internal constant _ROLE_109 = 1 << 109; uint256 internal constant _ROLE_110 = 1 << 110; uint256 internal constant _ROLE_111 = 1 << 111; uint256 internal constant _ROLE_112 = 1 << 112; uint256 internal constant _ROLE_113 = 1 << 113; uint256 internal constant _ROLE_114 = 1 << 114; uint256 internal constant _ROLE_115 = 1 << 115; uint256 internal constant _ROLE_116 = 1 << 116; uint256 internal constant _ROLE_117 = 1 << 117; uint256 internal constant _ROLE_118 = 1 << 118; uint256 internal constant _ROLE_119 = 1 << 119; uint256 internal constant _ROLE_120 = 1 << 120; uint256 internal constant _ROLE_121 = 1 << 121; uint256 internal constant _ROLE_122 = 1 << 122; uint256 internal constant _ROLE_123 = 1 << 123; uint256 internal constant _ROLE_124 = 1 << 124; uint256 internal constant _ROLE_125 = 1 << 125; uint256 internal constant _ROLE_126 = 1 << 126; uint256 internal constant _ROLE_127 = 1 << 127; uint256 internal constant _ROLE_128 = 1 << 128; uint256 internal constant _ROLE_129 = 1 << 129; uint256 internal constant _ROLE_130 = 1 << 130; uint256 internal constant _ROLE_131 = 1 << 131; uint256 internal constant _ROLE_132 = 1 << 132; uint256 internal constant _ROLE_133 = 1 << 133; uint256 internal constant _ROLE_134 = 1 << 134; uint256 internal constant _ROLE_135 = 1 << 135; uint256 internal constant _ROLE_136 = 1 << 136; uint256 internal constant _ROLE_137 = 1 << 137; uint256 internal constant _ROLE_138 = 1 << 138; uint256 internal constant _ROLE_139 = 1 << 139; uint256 internal constant _ROLE_140 = 1 << 140; uint256 internal constant _ROLE_141 = 1 << 141; uint256 internal constant _ROLE_142 = 1 << 142; uint256 internal constant _ROLE_143 = 1 << 143; uint256 internal constant _ROLE_144 = 1 << 144; uint256 internal constant _ROLE_145 = 1 << 145; uint256 internal constant _ROLE_146 = 1 << 146; uint256 internal constant _ROLE_147 = 1 << 147; uint256 internal constant _ROLE_148 = 1 << 148; uint256 internal constant _ROLE_149 = 1 << 149; uint256 internal constant _ROLE_150 = 1 << 150; uint256 internal constant _ROLE_151 = 1 << 151; uint256 internal constant _ROLE_152 = 1 << 152; uint256 internal constant _ROLE_153 = 1 << 153; uint256 internal constant _ROLE_154 = 1 << 154; uint256 internal constant _ROLE_155 = 1 << 155; uint256 internal constant _ROLE_156 = 1 << 156; uint256 internal constant _ROLE_157 = 1 << 157; uint256 internal constant _ROLE_158 = 1 << 158; uint256 internal constant _ROLE_159 = 1 << 159; uint256 internal constant _ROLE_160 = 1 << 160; uint256 internal constant _ROLE_161 = 1 << 161; uint256 internal constant _ROLE_162 = 1 << 162; uint256 internal constant _ROLE_163 = 1 << 163; uint256 internal constant _ROLE_164 = 1 << 164; uint256 internal constant _ROLE_165 = 1 << 165; uint256 internal constant _ROLE_166 = 1 << 166; uint256 internal constant _ROLE_167 = 1 << 167; uint256 internal constant _ROLE_168 = 1 << 168; uint256 internal constant _ROLE_169 = 1 << 169; uint256 internal constant _ROLE_170 = 1 << 170; uint256 internal constant _ROLE_171 = 1 << 171; uint256 internal constant _ROLE_172 = 1 << 172; uint256 internal constant _ROLE_173 = 1 << 173; uint256 internal constant _ROLE_174 = 1 << 174; uint256 internal constant _ROLE_175 = 1 << 175; uint256 internal constant _ROLE_176 = 1 << 176; uint256 internal constant _ROLE_177 = 1 << 177; uint256 internal constant _ROLE_178 = 1 << 178; uint256 internal constant _ROLE_179 = 1 << 179; uint256 internal constant _ROLE_180 = 1 << 180; uint256 internal constant _ROLE_181 = 1 << 181; uint256 internal constant _ROLE_182 = 1 << 182; uint256 internal constant _ROLE_183 = 1 << 183; uint256 internal constant _ROLE_184 = 1 << 184; uint256 internal constant _ROLE_185 = 1 << 185; uint256 internal constant _ROLE_186 = 1 << 186; uint256 internal constant _ROLE_187 = 1 << 187; uint256 internal constant _ROLE_188 = 1 << 188; uint256 internal constant _ROLE_189 = 1 << 189; uint256 internal constant _ROLE_190 = 1 << 190; uint256 internal constant _ROLE_191 = 1 << 191; uint256 internal constant _ROLE_192 = 1 << 192; uint256 internal constant _ROLE_193 = 1 << 193; uint256 internal constant _ROLE_194 = 1 << 194; uint256 internal constant _ROLE_195 = 1 << 195; uint256 internal constant _ROLE_196 = 1 << 196; uint256 internal constant _ROLE_197 = 1 << 197; uint256 internal constant _ROLE_198 = 1 << 198; uint256 internal constant _ROLE_199 = 1 << 199; uint256 internal constant _ROLE_200 = 1 << 200; uint256 internal constant _ROLE_201 = 1 << 201; uint256 internal constant _ROLE_202 = 1 << 202; uint256 internal constant _ROLE_203 = 1 << 203; uint256 internal constant _ROLE_204 = 1 << 204; uint256 internal constant _ROLE_205 = 1 << 205; uint256 internal constant _ROLE_206 = 1 << 206; uint256 internal constant _ROLE_207 = 1 << 207; uint256 internal constant _ROLE_208 = 1 << 208; uint256 internal constant _ROLE_209 = 1 << 209; uint256 internal constant _ROLE_210 = 1 << 210; uint256 internal constant _ROLE_211 = 1 << 211; uint256 internal constant _ROLE_212 = 1 << 212; uint256 internal constant _ROLE_213 = 1 << 213; uint256 internal constant _ROLE_214 = 1 << 214; uint256 internal constant _ROLE_215 = 1 << 215; uint256 internal constant _ROLE_216 = 1 << 216; uint256 internal constant _ROLE_217 = 1 << 217; uint256 internal constant _ROLE_218 = 1 << 218; uint256 internal constant _ROLE_219 = 1 << 219; uint256 internal constant _ROLE_220 = 1 << 220; uint256 internal constant _ROLE_221 = 1 << 221; uint256 internal constant _ROLE_222 = 1 << 222; uint256 internal constant _ROLE_223 = 1 << 223; uint256 internal constant _ROLE_224 = 1 << 224; uint256 internal constant _ROLE_225 = 1 << 225; uint256 internal constant _ROLE_226 = 1 << 226; uint256 internal constant _ROLE_227 = 1 << 227; uint256 internal constant _ROLE_228 = 1 << 228; uint256 internal constant _ROLE_229 = 1 << 229; uint256 internal constant _ROLE_230 = 1 << 230; uint256 internal constant _ROLE_231 = 1 << 231; uint256 internal constant _ROLE_232 = 1 << 232; uint256 internal constant _ROLE_233 = 1 << 233; uint256 internal constant _ROLE_234 = 1 << 234; uint256 internal constant _ROLE_235 = 1 << 235; uint256 internal constant _ROLE_236 = 1 << 236; uint256 internal constant _ROLE_237 = 1 << 237; uint256 internal constant _ROLE_238 = 1 << 238; uint256 internal constant _ROLE_239 = 1 << 239; uint256 internal constant _ROLE_240 = 1 << 240; uint256 internal constant _ROLE_241 = 1 << 241; uint256 internal constant _ROLE_242 = 1 << 242; uint256 internal constant _ROLE_243 = 1 << 243; uint256 internal constant _ROLE_244 = 1 << 244; uint256 internal constant _ROLE_245 = 1 << 245; uint256 internal constant _ROLE_246 = 1 << 246; uint256 internal constant _ROLE_247 = 1 << 247; uint256 internal constant _ROLE_248 = 1 << 248; uint256 internal constant _ROLE_249 = 1 << 249; uint256 internal constant _ROLE_250 = 1 << 250; uint256 internal constant _ROLE_251 = 1 << 251; uint256 internal constant _ROLE_252 = 1 << 252; uint256 internal constant _ROLE_253 = 1 << 253; uint256 internal constant _ROLE_254 = 1 << 254; uint256 internal constant _ROLE_255 = 1 << 255; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for bit twiddling and boolean operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol) /// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html) library LibBit { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BIT TWIDDLING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Find last set. /// Returns the index of the most significant bit of `x`, /// counting from the least significant bit position. /// If `x` is zero, returns 256. function fls(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x))) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Count leading zeros. /// Returns the number of zeros preceding the most significant one bit. /// If `x` is zero, returns 256. function clz(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x)) } } /// @dev Find first set. /// Returns the index of the least significant bit of `x`, /// counting from the least significant bit position. /// If `x` is zero, returns 256. /// Equivalent to `ctz` (count trailing zeros), which gives /// the number of zeros following the least significant one bit. function ffs(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Isolate the least significant bit. let b := and(x, add(not(x), 1)) r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, b))) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, b)))) r := or(r, shl(5, lt(0xffffffff, shr(r, b)))) // For the remaining 32 bits, use a De Bruijn lookup. // forgefmt: disable-next-item r := or(r, byte(and(div(0xd76453e0, shr(r, b)), 0x1f), 0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405)) } } /// @dev Returns the number of set bits in `x`. function popCount(uint256 x) internal pure returns (uint256 c) { /// @solidity memory-safe-assembly assembly { let max := not(0) let isMax := eq(x, max) x := sub(x, and(shr(1, x), div(max, 3))) x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5))) x := and(add(x, shr(4, x)), div(max, 17)) c := or(shl(8, isMax), shr(248, mul(x, div(max, 255)))) } } /// @dev Returns whether `x` is a power of 2. function isPo2(uint256 x) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // Equivalent to `x && !(x & (x - 1))`. result := iszero(add(and(x, sub(x, 1)), iszero(x))) } } /// @dev Returns `x` reversed at the bit level. function reverseBits(uint256 x) internal pure returns (uint256 r) { uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f; uint256 m1 = m0 ^ (m0 << 2); uint256 m2 = m1 ^ (m1 << 1); r = reverseBytes(x); r = (m2 & (r >> 1)) | ((m2 & r) << 1); r = (m1 & (r >> 2)) | ((m1 & r) << 2); r = (m0 & (r >> 4)) | ((m0 & r) << 4); } /// @dev Returns `x` reversed at the byte level. function reverseBytes(uint256 x) internal pure returns (uint256 r) { unchecked { // Computing masks on-the-fly reduces bytecode size by about 200 bytes. uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == 0) >> 192); uint256 m1 = m0 ^ (m0 << 32); uint256 m2 = m1 ^ (m1 << 16); uint256 m3 = m2 ^ (m2 << 8); r = (m3 & (x >> 8)) | ((m3 & x) << 8); r = (m2 & (r >> 16)) | ((m2 & r) << 16); r = (m1 & (r >> 32)) | ((m1 & r) << 32); r = (m0 & (r >> 64)) | ((m0 & r) << 64); r = (r >> 128) | (r << 128); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BOOLEAN OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // A Solidity bool on the stack or memory is represented as a 256-bit word. // Non-zero values are true, zero is false. // A clean bool is either 0 (false) or 1 (true) under the hood. // Usually, if not always, the bool result of a regular Solidity expression, // or the argument of a public/external function will be a clean bool. // You can usually use the raw variants for more performance. // If uncertain, test (best with exact compiler settings). // Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s). /// @dev Returns `x & y`. Inputs must be clean. function rawAnd(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := and(x, y) } } /// @dev Returns `x & y`. function and(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := and(iszero(iszero(x)), iszero(iszero(y))) } } /// @dev Returns `x | y`. Inputs must be clean. function rawOr(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := or(x, y) } } /// @dev Returns `x | y`. function or(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := or(iszero(iszero(x)), iszero(iszero(y))) } } /// @dev Returns 1 if `b` is true, else 0. Input must be clean. function rawToUint(bool b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := b } } /// @dev Returns 1 if `b` is true, else 0. function toUint(bool b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for compressing and decompressing bytes. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibZip.sol) /// @author Calldata compression by clabby (https://github.com/clabby/op-kompressor) /// @author FastLZ by ariya (https://github.com/ariya/FastLZ) /// /// @dev Note: /// The accompanying solady.js library includes implementations of /// FastLZ and calldata operations for convenience. library LibZip { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FAST LZ OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // LZ77 implementation based on FastLZ. // Equivalent to level 1 compression and decompression at the following commit: // https://github.com/ariya/FastLZ/commit/344eb4025f9ae866ebf7a2ec48850f7113a97a42 // Decompression is backwards compatible. /// @dev Returns the compressed `data`. function flzCompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { function ms8(d_, v_) -> _d { mstore8(d_, v_) _d := add(d_, 1) } function u24(p_) -> _u { _u := mload(p_) _u := or(shl(16, byte(2, _u)), or(shl(8, byte(1, _u)), byte(0, _u))) } function cmp(p_, q_, e_) -> _l { for { e_ := sub(e_, q_) } lt(_l, e_) { _l := add(_l, 1) } { e_ := mul(iszero(byte(0, xor(mload(add(p_, _l)), mload(add(q_, _l))))), e_) } } function literals(runs_, src_, dest_) -> _o { for { _o := dest_ } iszero(lt(runs_, 0x20)) { runs_ := sub(runs_, 0x20) } { mstore(ms8(_o, 31), mload(src_)) _o := add(_o, 0x21) src_ := add(src_, 0x20) } if iszero(runs_) { leave } mstore(ms8(_o, sub(runs_, 1)), mload(src_)) _o := add(1, add(_o, runs_)) } function mt(l_, d_, o_) -> _o { for { d_ := sub(d_, 1) } iszero(lt(l_, 263)) { l_ := sub(l_, 262) } { o_ := ms8(ms8(ms8(o_, add(224, shr(8, d_))), 253), and(0xff, d_)) } if iszero(lt(l_, 7)) { _o := ms8(ms8(ms8(o_, add(224, shr(8, d_))), sub(l_, 7)), and(0xff, d_)) leave } _o := ms8(ms8(o_, add(shl(5, l_), shr(8, d_))), and(0xff, d_)) } function setHash(i_, v_) { let p_ := add(mload(0x40), shl(2, i_)) mstore(p_, xor(mload(p_), shl(224, xor(shr(224, mload(p_)), v_)))) } function getHash(i_) -> _h { _h := shr(224, mload(add(mload(0x40), shl(2, i_)))) } function hash(v_) -> _r { _r := and(shr(19, mul(2654435769, v_)), 0x1fff) } function setNextHash(ip_, ipStart_) -> _ip { setHash(hash(u24(ip_)), sub(ip_, ipStart_)) _ip := add(ip_, 1) } result := mload(0x40) codecopy(result, codesize(), 0x8000) // Zeroize the hashmap. let op := add(result, 0x8000) let a := add(data, 0x20) let ipStart := a let ipLimit := sub(add(ipStart, mload(data)), 13) for { let ip := add(2, a) } lt(ip, ipLimit) {} { let r := 0 let d := 0 for {} 1 {} { let s := u24(ip) let h := hash(s) r := add(ipStart, getHash(h)) setHash(h, sub(ip, ipStart)) d := sub(ip, r) if iszero(lt(ip, ipLimit)) { break } ip := add(ip, 1) if iszero(gt(d, 0x1fff)) { if eq(s, u24(r)) { break } } } if iszero(lt(ip, ipLimit)) { break } ip := sub(ip, 1) if gt(ip, a) { op := literals(sub(ip, a), a, op) } let l := cmp(add(r, 3), add(ip, 3), add(ipLimit, 9)) op := mt(l, d, op) ip := setNextHash(setNextHash(add(ip, l), ipStart), ipStart) a := ip } // Copy the result to compact the memory, overwriting the hashmap. let end := sub(literals(sub(add(ipStart, mload(data)), a), a, op), 0x7fe0) let o := add(result, 0x20) mstore(result, sub(end, o)) // Store the length. for {} iszero(gt(o, end)) { o := add(o, 0x20) } { mstore(o, mload(add(o, 0x7fe0))) } mstore(end, 0) // Zeroize the slot after the string. mstore(0x40, add(end, 0x20)) // Allocate the memory. } } /// @dev Returns the decompressed `data`. function flzDecompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let op := add(result, 0x20) let end := add(add(data, 0x20), mload(data)) for { data := add(data, 0x20) } lt(data, end) {} { let w := mload(data) let c := byte(0, w) let t := shr(5, c) if iszero(t) { mstore(op, mload(add(data, 1))) data := add(data, add(2, c)) op := add(op, add(1, c)) continue } for { let g := eq(t, 7) let l := add(2, xor(t, mul(g, xor(t, add(7, byte(1, w)))))) // M let s := add(add(shl(8, and(0x1f, c)), byte(add(1, g), w)), 1) // R let r := sub(op, s) let f := xor(s, mul(gt(s, 0x20), xor(s, 0x20))) let j := 0 } 1 {} { mstore(add(op, j), mload(add(r, j))) j := add(j, f) if lt(j, l) { continue } data := add(data, add(2, g)) op := add(op, l) break } } mstore(result, sub(op, add(result, 0x20))) // Store the length. mstore(op, 0) // Zeroize the slot after the string. mstore(0x40, add(op, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CALLDATA OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Calldata compression and decompression using selective run length encoding: // - Sequences of 0x00 (up to 128 consecutive). // - Sequences of 0xff (up to 32 consecutive). // // A run length encoded block consists of two bytes: // (0) 0x00 // (1) A control byte with the following bit layout: // - [7] `0: 0x00, 1: 0xff`. // - [0..6] `runLength - 1`. // // The first 4 bytes are bitwise negated so that the compressed calldata // can be dispatched into the `fallback` and `receive` functions. /// @dev Returns the compressed `data`. function cdCompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { function rle(v_, o_, d_) -> _o, _d { mstore(o_, shl(240, or(and(0xff, add(d_, 0xff)), and(0x80, v_)))) _o := add(o_, 2) } result := mload(0x40) let o := add(result, 0x20) let z := 0 // Number of consecutive 0x00. let y := 0 // Number of consecutive 0xff. for { let end := add(data, mload(data)) } iszero(eq(data, end)) {} { data := add(data, 1) let c := byte(31, mload(data)) if iszero(c) { if y { o, y := rle(0xff, o, y) } z := add(z, 1) if eq(z, 0x80) { o, z := rle(0x00, o, 0x80) } continue } if eq(c, 0xff) { if z { o, z := rle(0x00, o, z) } y := add(y, 1) if eq(y, 0x20) { o, y := rle(0xff, o, 0x20) } continue } if y { o, y := rle(0xff, o, y) } if z { o, z := rle(0x00, o, z) } mstore8(o, c) o := add(o, 1) } if y { o, y := rle(0xff, o, y) } if z { o, z := rle(0x00, o, z) } // Bitwise negate the first 4 bytes. mstore(add(result, 4), not(mload(add(result, 4)))) mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /// @dev Returns the decompressed `data`. function cdDecompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { if mload(data) { result := mload(0x40) let o := add(result, 0x20) let s := add(data, 4) let v := mload(s) let end := add(data, mload(data)) mstore(s, not(v)) // Bitwise negate the first 4 bytes. for {} lt(data, end) {} { data := add(data, 1) let c := byte(31, mload(data)) if iszero(c) { data := add(data, 1) let d := byte(31, mload(data)) // Fill with either 0xff or 0x00. mstore(o, not(0)) if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) } o := add(o, add(and(d, 0x7f), 1)) continue } mstore8(o, c) o := add(o, 1) } mstore(s, v) // Restore the first 4 bytes. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } } /// @dev To be called in the `fallback` function. /// ``` /// fallback() external payable { LibZip.cdFallback(); } /// receive() external payable {} // Silence compiler warning to add a `receive` function. /// ``` /// For efficiency, this function will directly return the results, terminating the context. /// If called internally, it must be called at the end of the function. function cdFallback() internal { assembly { if iszero(calldatasize()) { return(calldatasize(), calldatasize()) } let o := 0 let f := not(3) // For negating the first 4 bytes. for { let i := 0 } lt(i, calldatasize()) {} { let c := byte(0, xor(add(i, f), calldataload(i))) i := add(i, 1) if iszero(c) { let d := byte(0, xor(add(i, f), calldataload(i))) i := add(i, 1) // Fill with either 0xff or 0x00. mstore(o, not(0)) if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) } o := add(o, add(and(d, 0x7f), 1)) continue } mstore8(o, c) o := add(o, 1) } let success := delegatecall(gas(), address(), 0x00, o, codesize(), 0x00) returndatacopy(0x00, 0x00, returndatasize()) if iszero(success) { revert(0x00, returndatasize()) } return(0x00, returndatasize()) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe integer casting library that reverts on overflow. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeCastLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) library SafeCastLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error Overflow(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UNSIGNED INTEGER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function toUint8(uint256 x) internal pure returns (uint8) { if (x >= 1 << 8) _revertOverflow(); return uint8(x); } function toUint16(uint256 x) internal pure returns (uint16) { if (x >= 1 << 16) _revertOverflow(); return uint16(x); } function toUint24(uint256 x) internal pure returns (uint24) { if (x >= 1 << 24) _revertOverflow(); return uint24(x); } function toUint32(uint256 x) internal pure returns (uint32) { if (x >= 1 << 32) _revertOverflow(); return uint32(x); } function toUint40(uint256 x) internal pure returns (uint40) { if (x >= 1 << 40) _revertOverflow(); return uint40(x); } function toUint48(uint256 x) internal pure returns (uint48) { if (x >= 1 << 48) _revertOverflow(); return uint48(x); } function toUint56(uint256 x) internal pure returns (uint56) { if (x >= 1 << 56) _revertOverflow(); return uint56(x); } function toUint64(uint256 x) internal pure returns (uint64) { if (x >= 1 << 64) _revertOverflow(); return uint64(x); } function toUint72(uint256 x) internal pure returns (uint72) { if (x >= 1 << 72) _revertOverflow(); return uint72(x); } function toUint80(uint256 x) internal pure returns (uint80) { if (x >= 1 << 80) _revertOverflow(); return uint80(x); } function toUint88(uint256 x) internal pure returns (uint88) { if (x >= 1 << 88) _revertOverflow(); return uint88(x); } function toUint96(uint256 x) internal pure returns (uint96) { if (x >= 1 << 96) _revertOverflow(); return uint96(x); } function toUint104(uint256 x) internal pure returns (uint104) { if (x >= 1 << 104) _revertOverflow(); return uint104(x); } function toUint112(uint256 x) internal pure returns (uint112) { if (x >= 1 << 112) _revertOverflow(); return uint112(x); } function toUint120(uint256 x) internal pure returns (uint120) { if (x >= 1 << 120) _revertOverflow(); return uint120(x); } function toUint128(uint256 x) internal pure returns (uint128) { if (x >= 1 << 128) _revertOverflow(); return uint128(x); } function toUint136(uint256 x) internal pure returns (uint136) { if (x >= 1 << 136) _revertOverflow(); return uint136(x); } function toUint144(uint256 x) internal pure returns (uint144) { if (x >= 1 << 144) _revertOverflow(); return uint144(x); } function toUint152(uint256 x) internal pure returns (uint152) { if (x >= 1 << 152) _revertOverflow(); return uint152(x); } function toUint160(uint256 x) internal pure returns (uint160) { if (x >= 1 << 160) _revertOverflow(); return uint160(x); } function toUint168(uint256 x) internal pure returns (uint168) { if (x >= 1 << 168) _revertOverflow(); return uint168(x); } function toUint176(uint256 x) internal pure returns (uint176) { if (x >= 1 << 176) _revertOverflow(); return uint176(x); } function toUint184(uint256 x) internal pure returns (uint184) { if (x >= 1 << 184) _revertOverflow(); return uint184(x); } function toUint192(uint256 x) internal pure returns (uint192) { if (x >= 1 << 192) _revertOverflow(); return uint192(x); } function toUint200(uint256 x) internal pure returns (uint200) { if (x >= 1 << 200) _revertOverflow(); return uint200(x); } function toUint208(uint256 x) internal pure returns (uint208) { if (x >= 1 << 208) _revertOverflow(); return uint208(x); } function toUint216(uint256 x) internal pure returns (uint216) { if (x >= 1 << 216) _revertOverflow(); return uint216(x); } function toUint224(uint256 x) internal pure returns (uint224) { if (x >= 1 << 224) _revertOverflow(); return uint224(x); } function toUint232(uint256 x) internal pure returns (uint232) { if (x >= 1 << 232) _revertOverflow(); return uint232(x); } function toUint240(uint256 x) internal pure returns (uint240) { if (x >= 1 << 240) _revertOverflow(); return uint240(x); } function toUint248(uint256 x) internal pure returns (uint248) { if (x >= 1 << 248) _revertOverflow(); return uint248(x); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIGNED INTEGER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function toInt8(int256 x) internal pure returns (int8) { int8 y = int8(x); if (x != y) _revertOverflow(); return y; } function toInt16(int256 x) internal pure returns (int16) { int16 y = int16(x); if (x != y) _revertOverflow(); return y; } function toInt24(int256 x) internal pure returns (int24) { int24 y = int24(x); if (x != y) _revertOverflow(); return y; } function toInt32(int256 x) internal pure returns (int32) { int32 y = int32(x); if (x != y) _revertOverflow(); return y; } function toInt40(int256 x) internal pure returns (int40) { int40 y = int40(x); if (x != y) _revertOverflow(); return y; } function toInt48(int256 x) internal pure returns (int48) { int48 y = int48(x); if (x != y) _revertOverflow(); return y; } function toInt56(int256 x) internal pure returns (int56) { int56 y = int56(x); if (x != y) _revertOverflow(); return y; } function toInt64(int256 x) internal pure returns (int64) { int64 y = int64(x); if (x != y) _revertOverflow(); return y; } function toInt72(int256 x) internal pure returns (int72) { int72 y = int72(x); if (x != y) _revertOverflow(); return y; } function toInt80(int256 x) internal pure returns (int80) { int80 y = int80(x); if (x != y) _revertOverflow(); return y; } function toInt88(int256 x) internal pure returns (int88) { int88 y = int88(x); if (x != y) _revertOverflow(); return y; } function toInt96(int256 x) internal pure returns (int96) { int96 y = int96(x); if (x != y) _revertOverflow(); return y; } function toInt104(int256 x) internal pure returns (int104) { int104 y = int104(x); if (x != y) _revertOverflow(); return y; } function toInt112(int256 x) internal pure returns (int112) { int112 y = int112(x); if (x != y) _revertOverflow(); return y; } function toInt120(int256 x) internal pure returns (int120) { int120 y = int120(x); if (x != y) _revertOverflow(); return y; } function toInt128(int256 x) internal pure returns (int128) { int128 y = int128(x); if (x != y) _revertOverflow(); return y; } function toInt136(int256 x) internal pure returns (int136) { int136 y = int136(x); if (x != y) _revertOverflow(); return y; } function toInt144(int256 x) internal pure returns (int144) { int144 y = int144(x); if (x != y) _revertOverflow(); return y; } function toInt152(int256 x) internal pure returns (int152) { int152 y = int152(x); if (x != y) _revertOverflow(); return y; } function toInt160(int256 x) internal pure returns (int160) { int160 y = int160(x); if (x != y) _revertOverflow(); return y; } function toInt168(int256 x) internal pure returns (int168) { int168 y = int168(x); if (x != y) _revertOverflow(); return y; } function toInt176(int256 x) internal pure returns (int176) { int176 y = int176(x); if (x != y) _revertOverflow(); return y; } function toInt184(int256 x) internal pure returns (int184) { int184 y = int184(x); if (x != y) _revertOverflow(); return y; } function toInt192(int256 x) internal pure returns (int192) { int192 y = int192(x); if (x != y) _revertOverflow(); return y; } function toInt200(int256 x) internal pure returns (int200) { int200 y = int200(x); if (x != y) _revertOverflow(); return y; } function toInt208(int256 x) internal pure returns (int208) { int208 y = int208(x); if (x != y) _revertOverflow(); return y; } function toInt216(int256 x) internal pure returns (int216) { int216 y = int216(x); if (x != y) _revertOverflow(); return y; } function toInt224(int256 x) internal pure returns (int224) { int224 y = int224(x); if (x != y) _revertOverflow(); return y; } function toInt232(int256 x) internal pure returns (int232) { int232 y = int232(x); if (x != y) _revertOverflow(); return y; } function toInt240(int256 x) internal pure returns (int240) { int240 y = int240(x); if (x != y) _revertOverflow(); return y; } function toInt248(int256 x) internal pure returns (int248) { int248 y = int248(x); if (x != y) _revertOverflow(); return y; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function toInt256(uint256 x) internal pure returns (int256) { if (x >= 1 << 255) _revertOverflow(); return int256(x); } function toUint256(int256 x) internal pure returns (uint256) { if (x < 0) _revertOverflow(); return uint256(x); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function _revertOverflow() private pure { /// @solidity memory-safe-assembly assembly { // Store the function selector of `Overflow()`. mstore(0x00, 0x35278d12) // Revert with (offset, size). revert(0x1c, 0x04) } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /*////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////*/ /// Proof verification errors. error InvalidProofLeafIdxOutOfBounds(); error InvalidProofBadLeftRange(); error InvalidProofBadRightRange(); error InvalidProofUnrecognizedRoot(); /// Tree update errors. error InvalidUpdateOldRangeMismatchShouldBeEmpty(); error InvalidUpdateOldRangeMismatchWrongCurrentRoot(); error InvalidUpdateOldRangeMismatchWrongLength(); error InvalidUpdateTreeSizeMustGrow(); error InvalidUpdateNewRangeMismatchWrongLength(); /// @title Proof /// @notice A proof for a given leaf in a merkle mountain range. struct Proof { // The index of the leaf to be verified in the tree. uint256 index; // The leaf to be verified. bytes32 leaf; // The left range of the proof. bytes32[] leftRange; // The right range of the proof. bytes32[] rightRange; // The root of the tree the proof is being verified against. bytes32 targetRoot; } /// @title RootInfo /// @notice A packed 32 byte value containing info for any given root. struct RootInfo { // Max value = 2**176 - 1 = ~9.5e52 uint176 treeSize; // Max value = 2**40 - 1 = ~1.1e12 = 1099511627775 seconds = tens-of-thousands of years into the future uint40 timestamp; // Max value = 2**40 - 1 = ~1.1e12 = 1099511627775 = thousands of years' worth of sub-second blocks into the future uint40 height; } /// @title IWitness /// @author sina.eth /// @custom:coauthor runtheblocks.eth /// @notice Interface for the core Witness smart contract. /// @dev Base interface for the Witness contract. interface IWitness { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /// @notice Emitted when the root is updated. /// @param newRoot The newly accepted tree root hash. /// @param newSize The newly accepted tree size. event RootUpdated(bytes32 indexed newRoot, uint256 indexed newSize); /*////////////////////////////////////////////////////////////////////////// PUBLIC STORAGE //////////////////////////////////////////////////////////////////////////*/ /// @notice The current root hash. /// @dev This is the root hash of the most recently accepted update. function currentRoot() external view returns (bytes32); /// @notice A Mapping of checkpointed root hashes to their corresponding tree data. /// @param root The root hash for the checkpoint. /// @return info The `RootInfo` struct containing info about the root hash checkpoint. function rootInfo(bytes32 root) external view returns (RootInfo memory); /// @notice A mapping of checkpointed root hashes to their corresponding tree sizes. /// @dev This mapping is used to keep track of the tree size corresponding to when /// the contract accepted a given root hash. /// @dev Returns 0 if the root hash is not in the mapping. /// @param root The root hash for the checkpoint. /// @return treeSize The tree size corresponding to the root. function rootCache(bytes32 root) external view returns (uint256); /*////////////////////////////////////////////////////////////// READ METHODS //////////////////////////////////////////////////////////////*/ /// @notice Helper util to get the current tree state. /// /// @return currentRoot The current root of the tree. /// @return treeSize The current size of the tree. function getCurrentTreeState() external view returns (bytes32, uint256); /// @notice Helper util to get the last `block.timestamp` the tree was updated. /// /// @return timestamp The `block.timestamp` the update was made. function getLastUpdateTime() external view returns (uint256); /// @notice Helper util to get the last `block.number` the tree was updated. /// /// @return block The `block.timestamp` the update was made. function getLastUpdateBlock() external view returns (uint256); /// @notice Verifies a proof for a given leaf. Throws an error if the proof is invalid. /// /// @dev Notes: /// - For invalid proofs, this method will throw with an error indicating why the proof failed to validate. /// - The proof must validate against a checkpoint the contract has previously accepted. /// /// @param proof The proof to be verified. function verifyProof(Proof calldata proof) external view; /// @notice Verifies a proof for a given leaf, returning a boolean instead of throwing for invalid proofs. /// /// @dev This method is a wrapper around `verifyProof` that catches any errors and returns false instead. /// The params and logic are otherwise the same as `verifyProof`. /// /// @param proof The proof to be verified. function safeVerifyProof(Proof calldata proof) external view returns (bool isValid); /*////////////////////////////////////////////////////////////// WRITE METHODS //////////////////////////////////////////////////////////////*/ /// @notice Updates the tree root to a larger tree. /// /// @dev Emits a {RootUpdated} event. /// /// Notes: /// - A range proof is verified to ensure the new root is consistent with the previous root. /// - Roots are stored in storage for easier retrieval in the future, along with the treeSize /// they correspond to. /// /// Requirements: /// - `msg.sender` must be the contract owner. /// - `newSize` must be greater than the current tree size. /// - `oldRange` must correspond to the current tree root and size. /// - size check must pass on `newRange`. /// /// After these checks are verified, the new root is calculated based on `oldRange` and `newRange`. /// /// @param newSize The size of the updated tree. /// @param oldRange A compact range representing the current root. /// @param newRange A compact range representing the diff between oldRange and the new root's coverage. function updateTreeRoot(uint256 newSize, bytes32[] calldata oldRange, bytes32[] calldata newRange) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import { LibBit } from "solady/utils/LibBit.sol"; import { Proof } from "./interfaces/IWitness.sol"; enum ProofError { NONE, InvalidProofLeafIdxOutOfBounds, InvalidProofBadLeftRange, InvalidProofBadRightRange, InvalidProofUnrecognizedRoot } function validateProof(Proof calldata proof, uint256 targetTreeSize) pure returns (ProofError) { if (proof.index >= targetTreeSize) { // Provided index is out of bounds. return ProofError.InvalidProofLeafIdxOutOfBounds; } // leftRange covers the interval [0, index); // rightRange covers the interval [index + 1, targetTreeSize). // Verify the size of the ranges correspond to the right intervals. if (LibBit.popCount(proof.index) != proof.leftRange.length) { // Provided left range does not match expected size. return ProofError.InvalidProofBadLeftRange; } if (getRangeSizeForNonZeroBeginningInterval(proof.index + 1, targetTreeSize) != proof.rightRange.length) { // Provided right range does not match expected size. return ProofError.InvalidProofBadRightRange; } // First merge the leaf into the left and right ranges. (bytes32[] calldata mergedLeft, bytes32 seed, bytes32[] calldata mergedRight) = merge( proof.leftRange, proof.leaf, /** * seedHeight= */ 0, proof.index, proof.rightRange, targetTreeSize ); if (getRootForMergedRange(mergedLeft, seed, mergedRight) != proof.targetRoot) { // Root mismatch. return ProofError.InvalidProofUnrecognizedRoot; } return ProofError.NONE; } /// @notice Helper for calculating range size for a non-zero-starting interval. /// @dev The bitmath here decomposes the interval into two parts that in /// combination represent the compact range needed to express the interval. /// @param begin The start of the interval of the range's coverage (inclusive). /// @param end The end of the interval of the range's coverage (exclusive). /// @return left Bitmap representing the left part of the interval. /// @return right Bitmap representing the right part of the interval. function decomposeNonZeroInterval(uint256 begin, uint256 end) pure returns (uint256 left, uint256 right) { // Since `begin` represents the start of the interval, the index before that represents the // index of the last node included in the complimentary "zero-index-starting" interval. // Abbreviation of `complimentaryIntervalEndIdxInclusive`. uint256 complIntervalEndIdxInclusive = begin - 1; // End represents the index of the first node that's not included in the interval. // Recall that the bit representations of node indices represent their merge path. // The differences in merge path between the complimentary interval and the beginning // of the next interval is used to determine the max height of the left or right // components of the desired interval via its highest-significance set interval. uint256 divergeHeight = LibBit.fls(complIntervalEndIdxInclusive ^ end); // heightMask consists of `diverge` 1s, used to cap the heights of the left and right // components of the desired interval. // For example, if `diverge=3`, then `heightMask=0b111`. uint256 heightMask = (1 << divergeHeight) - 1; // The left portion of the interval consists of all nodes that will be merged into the // complementary interval, capped by `heightMask`. ~complIntervalEndIdxInclusive lets us select // the right-merges of the merge path. left = (~complIntervalEndIdxInclusive) & heightMask; // The right portion of the interval can be represented by all right-merges of `end`, capped // by `heightMask`. Recall that `end` represents the first node that's not included in the interval, // so its right merges correspond to nodes in the interval. right = end & heightMask; } /// @notice Returns the expected size of a compact range needed to express a non-zero-starting interval. /// @param start The start of the interval of the range's coverage (inclusive). /// @param end The end of the interval of the range's coverage (exclusive). /// @return size The size of the compact range needed to express the interval [start, end). function getRangeSizeForNonZeroBeginningInterval(uint256 start, uint256 end) pure returns (uint256) { if (start == end) { return 0; } (uint256 left, uint256 right) = decomposeNonZeroInterval(start, end); return LibBit.popCount(left) + LibBit.popCount(right); } /// @notice Returns the root for a given compact range. /// @dev This method "bags the peaks" of the compact range, folding in from R2L. /// @param hashes The hashes of the compact range to calculate the root for. /// @return root The root of the compact range. function getRoot(bytes32[] calldata hashes) pure returns (bytes32 root) { uint256 i = hashes.length; // i is never 0, so don't need the following condition. // if (i == 0) return keccak256(""); root = hashes[--i]; while (i > 0) { root = hashToParent(hashes[--i], root); } } /// @notice Utility for calculating the root of a compact range provided in a gas-convenient representation. /// @param leftRange The left portion of the compact range to merge. /// @param seed The middle portion of the compact range to merge. /// @param rightRange The right portion of the compact range to merge. /// @return root The calculated root of the compact range. function getRootForMergedRange( bytes32[] calldata leftRange, bytes32 seed, bytes32[] calldata rightRange ) pure returns (bytes32 root) { // Total merged range is comprised of the following arrays concattenated: // - leftRange + seed + rightRange // Merklizing a compact range involves "rolling it up" from R2L. if (rightRange.length == 0) { root = seed; } else { root = rightRange[rightRange.length - 1]; for (uint256 i = rightRange.length - 1; i > 0; --i) { root = hashToParent(rightRange[i - 1], root); } root = hashToParent(seed, root); } for (uint256 i = leftRange.length; i > 0; --i) { root = hashToParent(leftRange[i - 1], root); } } /// @notice Hashes two bytes32s together as into a merkle parent. /// @param left The left child to hash. /// @param right The right child to hash. /// @return parent The parent hash. function hashToParent(bytes32 left, bytes32 right) pure returns (bytes32 parent) { parent = keccak256(abi.encodePacked(left, right)); } /// @notice Merges two compact ranges along a given seed node. /// /// @dev Merge folds hashes in from leftRange and rightRange into /// seed in order to create a combined compact range. /// /// The merged range is left + seed + right. /// /// leftRange is assumed to start its coverage at index 0. /// /// @param leftRange The left compact range to merge. /// @param seed The seed node to merge along. /// @param seedHeight The height of the seed node. /// @param seedIndex The index of the seed node. /// @param rightRange The right compact range to merge. /// @param rightRangeEnd The end of the right range's coverage. /// @return left The left portion of the merged compact range. /// @return newSeed The new seed node of the merged range. /// @return right The right portion of the merged compact range. function merge( bytes32[] calldata leftRange, bytes32 seed, uint256 seedHeight, uint256 seedIndex, bytes32[] calldata rightRange, uint256 rightRangeEnd ) pure returns (bytes32[] calldata left, bytes32 newSeed, bytes32[] calldata right) { uint256 leftCursor = leftRange.length; uint256 rightCursor = 0; uint256 seedRangeStart = seedIndex * (1 << seedHeight); for (; seedHeight < 255; ++seedHeight) { uint256 layerCoverage = 1 << seedHeight; if (seedIndex & 1 == 0) { // Right merge, or break if not possible. uint256 mergedRangeEnd = seedRangeStart + (2 * layerCoverage); if (mergedRangeEnd > rightRangeEnd) { break; } seed = hashToParent(seed, rightRange[rightCursor++]); } else { // Left merge, or break if not possible. if (layerCoverage > seedRangeStart) { break; } seedRangeStart -= layerCoverage; seed = hashToParent(leftRange[--leftCursor], seed); } seedIndex >>= 1; } newSeed = seed; left = leftRange[:leftCursor]; right = rightRange[rightCursor:]; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
{ "remappings": [ "solady/=node_modules/solady/src/", "@prb/test/=node_modules/@prb/test/", "forge-std/=node_modules/forge-std/" ], "optimizer": { "enabled": true, "runs": 10000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InvalidProofBadLeftRange","type":"error"},{"inputs":[],"name":"InvalidProofBadRightRange","type":"error"},{"inputs":[],"name":"InvalidProofLeafIdxOutOfBounds","type":"error"},{"inputs":[],"name":"InvalidProofUnrecognizedRoot","type":"error"},{"inputs":[],"name":"InvalidUpdateNewRangeMismatchWrongLength","type":"error"},{"inputs":[],"name":"InvalidUpdateOldRangeMismatchShouldBeEmpty","type":"error"},{"inputs":[],"name":"InvalidUpdateOldRangeMismatchWrongCurrentRoot","type":"error"},{"inputs":[],"name":"InvalidUpdateOldRangeMismatchWrongLength","type":"error"},{"inputs":[],"name":"InvalidUpdateTreeSizeMustGrow","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"newRoot","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"newSize","type":"uint256"}],"name":"RootUpdated","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"UPDATER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"currentRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentTreeState","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastUpdateBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"rootCache","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"rootInfo","outputs":[{"components":[{"internalType":"uint176","name":"treeSize","type":"uint176"},{"internalType":"uint40","name":"timestamp","type":"uint40"},{"internalType":"uint40","name":"height","type":"uint40"}],"internalType":"struct RootInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bytes32","name":"leaf","type":"bytes32"},{"internalType":"bytes32[]","name":"leftRange","type":"bytes32[]"},{"internalType":"bytes32[]","name":"rightRange","type":"bytes32[]"},{"internalType":"bytes32","name":"targetRoot","type":"bytes32"}],"internalType":"struct Proof","name":"proof","type":"tuple"}],"name":"safeVerifyProof","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newSize","type":"uint256"},{"internalType":"bytes32[]","name":"oldRange","type":"bytes32[]"},{"internalType":"bytes32[]","name":"newRange","type":"bytes32[]"}],"name":"updateTreeRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bytes32","name":"leaf","type":"bytes32"},{"internalType":"bytes32[]","name":"leftRange","type":"bytes32[]"},{"internalType":"bytes32[]","name":"rightRange","type":"bytes32[]"},{"internalType":"bytes32","name":"targetRoot","type":"bytes32"}],"internalType":"struct Proof","name":"proof","type":"tuple"}],"name":"verifyProof","outputs":[],"stateMutability":"view","type":"function"}]
Contract Creation Code
6080346100d257601f61198338819003918201601f19168301916001600160401b038311848410176100d7578084926020946040528339810103126100d257516001600160a01b038116908181036100d25781638b78c6d81955600091827f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3638b78c6d8600c5281526020600c209060018254178092557f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600c5160601c9180a360405161189590816100ee8239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe6080604052600436101561001a575b34156110ac575b600080fd5b60003560e01c8063062eed451461018a57806307e2ee0f146101855780630a805d5c14610180578063183a4f6e1461017b5780631c10893f146101765780631cd64df414610171578063256929621461016c5780632de94807146101675780632fac691a1461016257806347e633801461015d5780634a4ee7b114610158578063514e62fc1461015357806354d1f13d1461014e578063715018a61461014957806374715f4814610144578063764e7d241461013f5780638da5cb5b1461013a578063b7f8832014610135578063e5b046f214610130578063f04e283e1461012b578063f2fde38b14610126578063fdab463d146101215763fee81cf40361000e5761082e565b610810565b6107d4565b610784565b610746565b610713565b6106c0565b6106aa565b610663565b610601565b6105ba565b610579565b610551565b610535565b6104b4565b610449565b6103fd565b6103bb565b610359565b61031c565b610288565b610247565b6101c1565b60031990602082820112610015576004359167ffffffffffffffff8311610015578260a0920301126100155760040190565b34610015576102036101d23661018f565b6080810135600052600160205275ffffffffffffffffffffffffffffffffffffffffffff60406000205416906111c6565b60058110156102185760209060405190158152f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b34610015576000806003193601126102735760408160209254815260018352205460d81c604051908152f35b80fd5b60031960209101126100155760043590565b3461001557606061029836610276565b60409060008280516102a981610934565b828152826020820152015260005260016020528060002090808051926102ce84610934565b5475ffffffffffffffffffffffffffffffffffffffffffff8116938481526020810164ffffffffff938492838560b01c168352019260d81c8352845195865251166020850152511690820152f35b602060031936011261001557610334600435336108ed565b005b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361001557565b60406003193601126100155761036d610336565b6103756108c3565b638b78c6d8600c526000526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3005b346100155760406003193601126100155760206103f36103d9610336565b602435918291638b78c6d8600c526000526020600c205490565b1614604051908152f35b6000806003193601126102735763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b3461001557602060031936011261001557602061047b610467610336565b638b78c6d8600c526000526020600c205490565b604051908152f35b9181601f840112156100155782359167ffffffffffffffff8311610015576020808501948460051b01011161001557565b346100155760606003193601126100155767ffffffffffffffff602435818111610015576104e6903690600401610483565b909160443590811161001557610500903690600401610483565b91638b78c6d8600c523360005260016020600c205416156105275761033493600435610baf565b6382b429006000526004601cfd5b3461001557600060031936011261001557602060405160018152f35b604060031936011261001557610334610568610336565b6105706108c3565b602435906108ed565b34610015576040600319360112610015576020610594610336565b6105af60243591638b78c6d8600c526000526020600c205490565b161515604051908152f35b6000806003193601126102735763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b600080600319360112610273576106166108c3565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b3461001557600080600319360112610273578075ffffffffffffffffffffffffffffffffffffffffffff604080935492838152600160205220541682519182526020820152f35b34610015576103346106bb3661018f565b610998565b346100155760006003193601126100155760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b34610015576000806003193601126102735764ffffffffff60408260209354815260018452205460b01c16604051908152f35b346100155761075436610276565b6000526001602052602075ffffffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b602060031936011261001557610798610336565b6107a06108c3565b63389a75e1600c52806000526020600c2090815442116107c65760006103349255610861565b636f5e88186000526004601cfd5b6020600319360112610015576107e8610336565b6107f06108c3565b8060601b156108025761033490610861565b637448fbae6000526004601cfd5b34610015576000600319360112610015576020600054604051908152f35b3461001557602060031936011261001557610847610336565b63389a75e1600c52600052602080600c2054604051908152f35b73ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754330361052757565b638b78c6d8600c526000526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3565b6060810190811067ffffffffffffffff82111761095057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519061098c82610934565b565b6005111561021857565b6109f7906109f16109d66109ba60808401356000526001602052604060002090565b5475ffffffffffffffffffffffffffffffffffffffffffff1690565b75ffffffffffffffffffffffffffffffffffffffffffff1690565b906111c6565b610a008161098e565b8015610af457610a0f8161098e565b60018114610aca57610a208161098e565b60028114610aa057610a318161098e565b60038114610a765780610a4560049261098e565b14610a4c57565b60046040517fa2dbd269000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe5f5ab4d000000000000000000000000000000000000000000000000000000008152fd5b60046040517f616e11bd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f74842dbb000000000000000000000000000000000000000000000000000000008152fd5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b906000198201918211610b3557565b610af7565b91908203918211610b3557565b9190811015610b575760051b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b909291928311610015579190565b90939293848311610015578411610015578160051b01920390565b9392919260009384548015610f3a57610bc8828561154a565b8103610f11576109d66109ba610be8926000526001602052604060002090565b9181610c98846000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b03610ee75782871115610ebd5780610cb0888561131c565b03610e93577ff9443a8c8ce8cb7bee33999ea495dd8a7d58561562af63f686750774a190af1694610d9194610d889484610d82610ced8c97610b26565b610cf8818487610b47565b3592610d7a610d74867e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405601f6001831901831692836fffffffffffffffffffffffffffffffff1060071b901560081b1783811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1792831c63d76453e004161a1790565b95610b26565b851c95610b86565b906117d1565b93929092611596565b91828155610e8f610da185611072565b610dff610dad4261104c565b610df1610db94361104c565b91610de3610dc561097f565b75ffffffffffffffffffffffffffffffffffffffffffff9096168652565b64ffffffffff166020850152565b64ffffffffff166040830152565b610e13856000526001602052604060002090565b8151602083015160409093015160b09390931b7affffffffff000000000000000000000000000000000000000000001675ffffffffffffffffffffffffffffffffffffffffffff919091161760d89290921b7fffffffffff00000000000000000000000000000000000000000000000000000016919091179055565b80a3565b60046040517fc1e5467e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fdc9e24a3000000000000000000000000000000000000000000000000000000008152fd5b60046040517fcb05a28e000000000000000000000000000000000000000000000000000000008152fd5b60046040517e687252000000000000000000000000000000000000000000000000000000008152fd5b50909291506110225781610ff2856000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b03610e93577ff9443a8c8ce8cb7bee33999ea495dd8a7d58561562af63f686750774a190af1691610d919161154a565b60046040517f07701351000000000000000000000000000000000000000000000000000000008152fd5b650100000000008110156110645764ffffffffff1690565b6335278d126000526004601cfd5b7601000000000000000000000000000000000000000000008110156110645775ffffffffffffffffffffffffffffffffffffffffffff1690565b3615611153576000805b80913682101561113657813560031983011860001a60018093019381156110e257508153015b906110b6565b9360029150357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd85011860001a9301926000198252607f908181111561112b575b1601016110dc565b838101388439611123565b600090389082305af43d6000803e1561114e573d6000f35b3d6000fd5b3636f35b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610015570180359067ffffffffffffffff821161001557602001918160051b3603831361001557565b9060018201809211610b3557565b91908201809211610b3557565b908135818110156113145761127f816000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b90604084019161128f8386611157565b9190500361130b576112a9836112a4836111ab565b61131c565b9260608501936112b98587611157565b91905003611301576080936112e1610d88936112d86112ef9689611157565b92909389611157565b93909260208a0135916116b4565b910135036112fc57600090565b600490565b5050505050600390565b50505050600290565b505050600190565b90808214611536576000198201918211610b355761152d826114816113d360018561153397187f07060605060205040602030205040301060502050303040105050304000000006f8421084210842108cc6318c6db6d54be826fffffffffffffffffffffffffffffffff1060071b89881460081b1783811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1783811c61ffff1060041b1783811c60ff1060031b1792831c1c601f161a171b610b26565b809219166000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b92166000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b906111b9565b90565b5050600090565b8015610b35576000190190565b916115548261153d565b928261156285809584610b47565b35935b611570575050909150565b61157c6115909561153d565b94859461158a868486610b47565b3561163e565b93611565565b949390929190806115df5750905092905b8091825b6115b457505050565b9091936115d16115d79161158a6115ca88610b26565b8686610b47565b9461153d565b9190826115ab565b6000198101818111610b35576115f9908285949394610b47565b359161160481610b26565b93845b61161e575050611617925061163e565b92906115a7565b9091926115d16116349161158a6115ca88610b26565b9392919084611607565b90604051906020820192835260408201526040815261165c81610934565b51902090565b908160011b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811603610b3557565b81810292918115918404141715610b3557565b6000198114610b355760010190565b949693959291600082938195600190828004821483151715610b35578b969795949383928c94925b60ff8310611707575b505050505050936116fa916117039597610b86565b97909796610b94565b9091565b929591949998818699929598991b8d868a1615600014611785575061173561172f8692611662565b896111b9565b116117765791611756826117679461175061175d95926116a5565b9d610b47565b359061163e565b955b831c936116a5565b8b93928d9899979695926116dc565b989994819897508296506116e5565b939b50919996908183116117c257509961158a611767936117b46117ae6117bc958d9e9f610b3a565b9961153d565b9b8c91610b47565b9561175f565b999897508d95509995996116e5565b95979496939187899493839660009560016117ee81831b85611692565b925b60ff831061180d57505050505050936116fa916117039597610b86565b929591949998818699929598991b8d868a161560001461185f575061183561172f8692611662565b116117765791611756826118509461175061175d95926116a5565b8b93928d9899979695926117f0565b939b50919996908183116117c257509961158a611850936117b46117ae6117bc958d9e9f610b3a56fea164736f6c6343000812000a00000000000000000000000010e859116a6388a7d0540a1bc1247ae599d24f16
Deployed Bytecode
0x6080604052600436101561001a575b34156110ac575b600080fd5b60003560e01c8063062eed451461018a57806307e2ee0f146101855780630a805d5c14610180578063183a4f6e1461017b5780631c10893f146101765780631cd64df414610171578063256929621461016c5780632de94807146101675780632fac691a1461016257806347e633801461015d5780634a4ee7b114610158578063514e62fc1461015357806354d1f13d1461014e578063715018a61461014957806374715f4814610144578063764e7d241461013f5780638da5cb5b1461013a578063b7f8832014610135578063e5b046f214610130578063f04e283e1461012b578063f2fde38b14610126578063fdab463d146101215763fee81cf40361000e5761082e565b610810565b6107d4565b610784565b610746565b610713565b6106c0565b6106aa565b610663565b610601565b6105ba565b610579565b610551565b610535565b6104b4565b610449565b6103fd565b6103bb565b610359565b61031c565b610288565b610247565b6101c1565b60031990602082820112610015576004359167ffffffffffffffff8311610015578260a0920301126100155760040190565b34610015576102036101d23661018f565b6080810135600052600160205275ffffffffffffffffffffffffffffffffffffffffffff60406000205416906111c6565b60058110156102185760209060405190158152f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b34610015576000806003193601126102735760408160209254815260018352205460d81c604051908152f35b80fd5b60031960209101126100155760043590565b3461001557606061029836610276565b60409060008280516102a981610934565b828152826020820152015260005260016020528060002090808051926102ce84610934565b5475ffffffffffffffffffffffffffffffffffffffffffff8116938481526020810164ffffffffff938492838560b01c168352019260d81c8352845195865251166020850152511690820152f35b602060031936011261001557610334600435336108ed565b005b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361001557565b60406003193601126100155761036d610336565b6103756108c3565b638b78c6d8600c526000526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3005b346100155760406003193601126100155760206103f36103d9610336565b602435918291638b78c6d8600c526000526020600c205490565b1614604051908152f35b6000806003193601126102735763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b3461001557602060031936011261001557602061047b610467610336565b638b78c6d8600c526000526020600c205490565b604051908152f35b9181601f840112156100155782359167ffffffffffffffff8311610015576020808501948460051b01011161001557565b346100155760606003193601126100155767ffffffffffffffff602435818111610015576104e6903690600401610483565b909160443590811161001557610500903690600401610483565b91638b78c6d8600c523360005260016020600c205416156105275761033493600435610baf565b6382b429006000526004601cfd5b3461001557600060031936011261001557602060405160018152f35b604060031936011261001557610334610568610336565b6105706108c3565b602435906108ed565b34610015576040600319360112610015576020610594610336565b6105af60243591638b78c6d8600c526000526020600c205490565b161515604051908152f35b6000806003193601126102735763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b600080600319360112610273576106166108c3565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b3461001557600080600319360112610273578075ffffffffffffffffffffffffffffffffffffffffffff604080935492838152600160205220541682519182526020820152f35b34610015576103346106bb3661018f565b610998565b346100155760006003193601126100155760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b34610015576000806003193601126102735764ffffffffff60408260209354815260018452205460b01c16604051908152f35b346100155761075436610276565b6000526001602052602075ffffffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b602060031936011261001557610798610336565b6107a06108c3565b63389a75e1600c52806000526020600c2090815442116107c65760006103349255610861565b636f5e88186000526004601cfd5b6020600319360112610015576107e8610336565b6107f06108c3565b8060601b156108025761033490610861565b637448fbae6000526004601cfd5b34610015576000600319360112610015576020600054604051908152f35b3461001557602060031936011261001557610847610336565b63389a75e1600c52600052602080600c2054604051908152f35b73ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754330361052757565b638b78c6d8600c526000526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3565b6060810190811067ffffffffffffffff82111761095057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519061098c82610934565b565b6005111561021857565b6109f7906109f16109d66109ba60808401356000526001602052604060002090565b5475ffffffffffffffffffffffffffffffffffffffffffff1690565b75ffffffffffffffffffffffffffffffffffffffffffff1690565b906111c6565b610a008161098e565b8015610af457610a0f8161098e565b60018114610aca57610a208161098e565b60028114610aa057610a318161098e565b60038114610a765780610a4560049261098e565b14610a4c57565b60046040517fa2dbd269000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe5f5ab4d000000000000000000000000000000000000000000000000000000008152fd5b60046040517f616e11bd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f74842dbb000000000000000000000000000000000000000000000000000000008152fd5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b906000198201918211610b3557565b610af7565b91908203918211610b3557565b9190811015610b575760051b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b909291928311610015579190565b90939293848311610015578411610015578160051b01920390565b9392919260009384548015610f3a57610bc8828561154a565b8103610f11576109d66109ba610be8926000526001602052604060002090565b9181610c98846000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b03610ee75782871115610ebd5780610cb0888561131c565b03610e93577ff9443a8c8ce8cb7bee33999ea495dd8a7d58561562af63f686750774a190af1694610d9194610d889484610d82610ced8c97610b26565b610cf8818487610b47565b3592610d7a610d74867e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405601f6001831901831692836fffffffffffffffffffffffffffffffff1060071b901560081b1783811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1792831c63d76453e004161a1790565b95610b26565b851c95610b86565b906117d1565b93929092611596565b91828155610e8f610da185611072565b610dff610dad4261104c565b610df1610db94361104c565b91610de3610dc561097f565b75ffffffffffffffffffffffffffffffffffffffffffff9096168652565b64ffffffffff166020850152565b64ffffffffff166040830152565b610e13856000526001602052604060002090565b8151602083015160409093015160b09390931b7affffffffff000000000000000000000000000000000000000000001675ffffffffffffffffffffffffffffffffffffffffffff919091161760d89290921b7fffffffffff00000000000000000000000000000000000000000000000000000016919091179055565b80a3565b60046040517fc1e5467e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fdc9e24a3000000000000000000000000000000000000000000000000000000008152fd5b60046040517fcb05a28e000000000000000000000000000000000000000000000000000000008152fd5b60046040517e687252000000000000000000000000000000000000000000000000000000008152fd5b50909291506110225781610ff2856000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b03610e93577ff9443a8c8ce8cb7bee33999ea495dd8a7d58561562af63f686750774a190af1691610d919161154a565b60046040517f07701351000000000000000000000000000000000000000000000000000000008152fd5b650100000000008110156110645764ffffffffff1690565b6335278d126000526004601cfd5b7601000000000000000000000000000000000000000000008110156110645775ffffffffffffffffffffffffffffffffffffffffffff1690565b3615611153576000805b80913682101561113657813560031983011860001a60018093019381156110e257508153015b906110b6565b9360029150357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd85011860001a9301926000198252607f908181111561112b575b1601016110dc565b838101388439611123565b600090389082305af43d6000803e1561114e573d6000f35b3d6000fd5b3636f35b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610015570180359067ffffffffffffffff821161001557602001918160051b3603831361001557565b9060018201809211610b3557565b91908201809211610b3557565b908135818110156113145761127f816000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b90604084019161128f8386611157565b9190500361130b576112a9836112a4836111ab565b61131c565b9260608501936112b98587611157565b91905003611301576080936112e1610d88936112d86112ef9689611157565b92909389611157565b93909260208a0135916116b4565b910135036112fc57600090565b600490565b5050505050600390565b50505050600290565b505050600190565b90808214611536576000198201918211610b355761152d826114816113d360018561153397187f07060605060205040602030205040301060502050303040105050304000000006f8421084210842108cc6318c6db6d54be826fffffffffffffffffffffffffffffffff1060071b89881460081b1783811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1783811c61ffff1060041b1783811c60ff1060031b1792831c1c601f161a171b610b26565b809219166000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b92166000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b906111b9565b90565b5050600090565b8015610b35576000190190565b916115548261153d565b928261156285809584610b47565b35935b611570575050909150565b61157c6115909561153d565b94859461158a868486610b47565b3561163e565b93611565565b949390929190806115df5750905092905b8091825b6115b457505050565b9091936115d16115d79161158a6115ca88610b26565b8686610b47565b9461153d565b9190826115ab565b6000198101818111610b35576115f9908285949394610b47565b359161160481610b26565b93845b61161e575050611617925061163e565b92906115a7565b9091926115d16116349161158a6115ca88610b26565b9392919084611607565b90604051906020820192835260408201526040815261165c81610934565b51902090565b908160011b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811603610b3557565b81810292918115918404141715610b3557565b6000198114610b355760010190565b949693959291600082938195600190828004821483151715610b35578b969795949383928c94925b60ff8310611707575b505050505050936116fa916117039597610b86565b97909796610b94565b9091565b929591949998818699929598991b8d868a1615600014611785575061173561172f8692611662565b896111b9565b116117765791611756826117679461175061175d95926116a5565b9d610b47565b359061163e565b955b831c936116a5565b8b93928d9899979695926116dc565b989994819897508296506116e5565b939b50919996908183116117c257509961158a611767936117b46117ae6117bc958d9e9f610b3a565b9961153d565b9b8c91610b47565b9561175f565b999897508d95509995996116e5565b95979496939187899493839660009560016117ee81831b85611692565b925b60ff831061180d57505050505050936116fa916117039597610b86565b929591949998818699929598991b8d868a161560001461185f575061183561172f8692611662565b116117765791611756826118509461175061175d95926116a5565b8b93928d9899979695926117f0565b939b50919996908183116117c257509961158a611850936117b46117ae6117bc958d9e9f610b3a56fea164736f6c6343000812000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000010e859116a6388a7d0540a1bc1247ae599d24f16
-----Decoded View---------------
Arg [0] : owner (address): 0x10e859116a6388A7D0540a1bc1247Ae599d24F16
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000010e859116a6388a7d0540a1bc1247ae599d24f16
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
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.