Overview
ETH Balance
More Info
ContractCreator
Multichain Info
Latest 25 from a total of 184,552 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Update Tree Root | 222413204 | 2 mins ago | IN | 0 ETH | 0.00000175 | ||||
| Update Tree Root | 222412161 | 7 mins ago | IN | 0 ETH | 0.00000168 | ||||
| Update Tree Root | 222411199 | 12 mins ago | IN | 0 ETH | 0.0000017 | ||||
| Update Tree Root | 222410188 | 17 mins ago | IN | 0 ETH | 0.00000168 | ||||
| Update Tree Root | 222409200 | 23 mins ago | IN | 0 ETH | 0.00000173 | ||||
| Update Tree Root | 222408142 | 28 mins ago | IN | 0 ETH | 0.00000168 | ||||
| Update Tree Root | 222407164 | 33 mins ago | IN | 0 ETH | 0.00000175 | ||||
| Update Tree Root | 222406245 | 38 mins ago | IN | 0 ETH | 0.00000169 | ||||
| Update Tree Root | 222405355 | 43 mins ago | IN | 0 ETH | 0.00000173 | ||||
| Update Tree Root | 222404339 | 48 mins ago | IN | 0 ETH | 0.00000169 | ||||
| Update Tree Root | 222403351 | 54 mins ago | IN | 0 ETH | 0.00000169 | ||||
| Update Tree Root | 222402461 | 1 hr ago | IN | 0 ETH | 0.00000161 | ||||
| Update Tree Root | 222401481 | 1 hr ago | IN | 0 ETH | 0.00000175 | ||||
| Update Tree Root | 222400493 | 1 hr ago | IN | 0 ETH | 0.00000175 | ||||
| Update Tree Root | 222399452 | 1 hr ago | IN | 0 ETH | 0.00000175 | ||||
| Update Tree Root | 222398374 | 1 hr ago | IN | 0 ETH | 0.00000171 | ||||
| Update Tree Root | 222397346 | 1 hr ago | IN | 0 ETH | 0.0000017 | ||||
| Update Tree Root | 222396288 | 1 hr ago | IN | 0 ETH | 0.0000017 | ||||
| Update Tree Root | 222395284 | 1 hr ago | IN | 0 ETH | 0.00000172 | ||||
| Update Tree Root | 222394310 | 1 hr ago | IN | 0 ETH | 0.00000169 | ||||
| Update Tree Root | 222393296 | 1 hr ago | IN | 0 ETH | 0.00000173 | ||||
| Update Tree Root | 222392285 | 1 hr ago | IN | 0 ETH | 0.00000169 | ||||
| Update Tree Root | 222391250 | 1 hr ago | IN | 0 ETH | 0.00000169 | ||||
| Update Tree Root | 222390239 | 2 hrs ago | IN | 0 ETH | 0.00000173 | ||||
| Update Tree Root | 222389177 | 2 hrs ago | IN | 0 ETH | 0.00000159 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | Amount | ||
|---|---|---|---|---|---|---|
| 31706016 | 607 days ago | Contract Creation | 0 ETH |
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import { OwnableRoles } from "solady/src/auth/OwnableRoles.sol";
import { LibBit } from "solady/src/utils/LibBit.sol";
import { LibZip } from "solady/src/utils/LibZip.sol";
import { SafeCastLib } from "solady/src/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/src/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/src/=node_modules/solady/src/",
"@prb/test/=node_modules/@prb/test/",
"forge-std/=node_modules/forge-std/",
"@witnessco/=node_modules/@witnessco/"
],
"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 ABI
API[{"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
6080346100d257601f61198338819003918201601f19168301916001600160401b038311848410176100d7578084926020946040528339810103126100d257516001600160a01b038116908181036100d25781638b78c6d81955600091827f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3638b78c6d8600c5281526020600c209060018254178092557f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600c5160601c9180a360405161189590816100ee8239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe6080604052600436101561001a575b34156110ac575b600080fd5b60003560e01c8063062eed451461018a57806307e2ee0f146101855780630a805d5c14610180578063183a4f6e1461017b5780631c10893f146101765780631cd64df414610171578063256929621461016c5780632de94807146101675780632fac691a1461016257806347e633801461015d5780634a4ee7b114610158578063514e62fc1461015357806354d1f13d1461014e578063715018a61461014957806374715f4814610144578063764e7d241461013f5780638da5cb5b1461013a578063b7f8832014610135578063e5b046f214610130578063f04e283e1461012b578063f2fde38b14610126578063fdab463d146101215763fee81cf40361000e5761082e565b610810565b6107d4565b610784565b610746565b610713565b6106c0565b6106aa565b610663565b610601565b6105ba565b610579565b610551565b610535565b6104b4565b610449565b6103fd565b6103bb565b610359565b61031c565b610288565b610247565b6101c1565b60031990602082820112610015576004359167ffffffffffffffff8311610015578260a0920301126100155760040190565b34610015576102036101d23661018f565b6080810135600052600160205275ffffffffffffffffffffffffffffffffffffffffffff60406000205416906111c6565b60058110156102185760209060405190158152f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b34610015576000806003193601126102735760408160209254815260018352205460d81c604051908152f35b80fd5b60031960209101126100155760043590565b3461001557606061029836610276565b60409060008280516102a981610934565b828152826020820152015260005260016020528060002090808051926102ce84610934565b5475ffffffffffffffffffffffffffffffffffffffffffff8116938481526020810164ffffffffff938492838560b01c168352019260d81c8352845195865251166020850152511690820152f35b602060031936011261001557610334600435336108ed565b005b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361001557565b60406003193601126100155761036d610336565b6103756108c3565b638b78c6d8600c526000526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3005b346100155760406003193601126100155760206103f36103d9610336565b602435918291638b78c6d8600c526000526020600c205490565b1614604051908152f35b6000806003193601126102735763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b3461001557602060031936011261001557602061047b610467610336565b638b78c6d8600c526000526020600c205490565b604051908152f35b9181601f840112156100155782359167ffffffffffffffff8311610015576020808501948460051b01011161001557565b346100155760606003193601126100155767ffffffffffffffff602435818111610015576104e6903690600401610483565b909160443590811161001557610500903690600401610483565b91638b78c6d8600c523360005260016020600c205416156105275761033493600435610baf565b6382b429006000526004601cfd5b3461001557600060031936011261001557602060405160018152f35b604060031936011261001557610334610568610336565b6105706108c3565b602435906108ed565b34610015576040600319360112610015576020610594610336565b6105af60243591638b78c6d8600c526000526020600c205490565b161515604051908152f35b6000806003193601126102735763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b600080600319360112610273576106166108c3565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b3461001557600080600319360112610273578075ffffffffffffffffffffffffffffffffffffffffffff604080935492838152600160205220541682519182526020820152f35b34610015576103346106bb3661018f565b610998565b346100155760006003193601126100155760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b34610015576000806003193601126102735764ffffffffff60408260209354815260018452205460b01c16604051908152f35b346100155761075436610276565b6000526001602052602075ffffffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b602060031936011261001557610798610336565b6107a06108c3565b63389a75e1600c52806000526020600c2090815442116107c65760006103349255610861565b636f5e88186000526004601cfd5b6020600319360112610015576107e8610336565b6107f06108c3565b8060601b156108025761033490610861565b637448fbae6000526004601cfd5b34610015576000600319360112610015576020600054604051908152f35b3461001557602060031936011261001557610847610336565b63389a75e1600c52600052602080600c2054604051908152f35b73ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754330361052757565b638b78c6d8600c526000526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3565b6060810190811067ffffffffffffffff82111761095057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519061098c82610934565b565b6005111561021857565b6109f7906109f16109d66109ba60808401356000526001602052604060002090565b5475ffffffffffffffffffffffffffffffffffffffffffff1690565b75ffffffffffffffffffffffffffffffffffffffffffff1690565b906111c6565b610a008161098e565b8015610af457610a0f8161098e565b60018114610aca57610a208161098e565b60028114610aa057610a318161098e565b60038114610a765780610a4560049261098e565b14610a4c57565b60046040517fa2dbd269000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe5f5ab4d000000000000000000000000000000000000000000000000000000008152fd5b60046040517f616e11bd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f74842dbb000000000000000000000000000000000000000000000000000000008152fd5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b906000198201918211610b3557565b610af7565b91908203918211610b3557565b9190811015610b575760051b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b909291928311610015579190565b90939293848311610015578411610015578160051b01920390565b9392919260009384548015610f3a57610bc8828561154a565b8103610f11576109d66109ba610be8926000526001602052604060002090565b9181610c98846000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b03610ee75782871115610ebd5780610cb0888561131c565b03610e93577ff9443a8c8ce8cb7bee33999ea495dd8a7d58561562af63f686750774a190af1694610d9194610d889484610d82610ced8c97610b26565b610cf8818487610b47565b3592610d7a610d74867e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405601f6001831901831692836fffffffffffffffffffffffffffffffff1060071b901560081b1783811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1792831c63d76453e004161a1790565b95610b26565b851c95610b86565b906117d1565b93929092611596565b91828155610e8f610da185611072565b610dff610dad4261104c565b610df1610db94361104c565b91610de3610dc561097f565b75ffffffffffffffffffffffffffffffffffffffffffff9096168652565b64ffffffffff166020850152565b64ffffffffff166040830152565b610e13856000526001602052604060002090565b8151602083015160409093015160b09390931b7affffffffff000000000000000000000000000000000000000000001675ffffffffffffffffffffffffffffffffffffffffffff919091161760d89290921b7fffffffffff00000000000000000000000000000000000000000000000000000016919091179055565b80a3565b60046040517fc1e5467e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fdc9e24a3000000000000000000000000000000000000000000000000000000008152fd5b60046040517fcb05a28e000000000000000000000000000000000000000000000000000000008152fd5b60046040517e687252000000000000000000000000000000000000000000000000000000008152fd5b50909291506110225781610ff2856000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b03610e93577ff9443a8c8ce8cb7bee33999ea495dd8a7d58561562af63f686750774a190af1691610d919161154a565b60046040517f07701351000000000000000000000000000000000000000000000000000000008152fd5b650100000000008110156110645764ffffffffff1690565b6335278d126000526004601cfd5b7601000000000000000000000000000000000000000000008110156110645775ffffffffffffffffffffffffffffffffffffffffffff1690565b3615611153576000805b80913682101561113657813560031983011860001a60018093019381156110e257508153015b906110b6565b9360029150357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd85011860001a9301926000198252607f908181111561112b575b1601016110dc565b838101388439611123565b600090389082305af43d6000803e1561114e573d6000f35b3d6000fd5b3636f35b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610015570180359067ffffffffffffffff821161001557602001918160051b3603831361001557565b9060018201809211610b3557565b91908201809211610b3557565b908135818110156113145761127f816000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b90604084019161128f8386611157565b9190500361130b576112a9836112a4836111ab565b61131c565b9260608501936112b98587611157565b91905003611301576080936112e1610d88936112d86112ef9689611157565b92909389611157565b93909260208a0135916116b4565b910135036112fc57600090565b600490565b5050505050600390565b50505050600290565b505050600190565b90808214611536576000198201918211610b355761152d826114816113d360018561153397187f07060605060205040602030205040301060502050303040105050304000000006f8421084210842108cc6318c6db6d54be826fffffffffffffffffffffffffffffffff1060071b89881460081b1783811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1783811c61ffff1060041b1783811c60ff1060031b1792831c1c601f161a171b610b26565b809219166000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b92166000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b906111b9565b90565b5050600090565b8015610b35576000190190565b916115548261153d565b928261156285809584610b47565b35935b611570575050909150565b61157c6115909561153d565b94859461158a868486610b47565b3561163e565b93611565565b949390929190806115df5750905092905b8091825b6115b457505050565b9091936115d16115d79161158a6115ca88610b26565b8686610b47565b9461153d565b9190826115ab565b6000198101818111610b35576115f9908285949394610b47565b359161160481610b26565b93845b61161e575050611617925061163e565b92906115a7565b9091926115d16116349161158a6115ca88610b26565b9392919084611607565b90604051906020820192835260408201526040815261165c81610934565b51902090565b908160011b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811603610b3557565b81810292918115918404141715610b3557565b6000198114610b355760010190565b949693959291600082938195600190828004821483151715610b35578b969795949383928c94925b60ff8310611707575b505050505050936116fa916117039597610b86565b97909796610b94565b9091565b929591949998818699929598991b8d868a1615600014611785575061173561172f8692611662565b896111b9565b116117765791611756826117679461175061175d95926116a5565b9d610b47565b359061163e565b955b831c936116a5565b8b93928d9899979695926116dc565b989994819897508296506116e5565b939b50919996908183116117c257509961158a611767936117b46117ae6117bc958d9e9f610b3a565b9961153d565b9b8c91610b47565b9561175f565b999897508d95509995996116e5565b95979496939187899493839660009560016117ee81831b85611692565b925b60ff831061180d57505050505050936116fa916117039597610b86565b929591949998818699929598991b8d868a161560001461185f575061183561172f8692611662565b116117765791611756826118509461175061175d95926116a5565b8b93928d9899979695926117f0565b939b50919996908183116117c257509961158a611850936117b46117ae6117bc958d9e9f610b3a56fea164736f6c6343000812000a000000000000000000000000d7db685f44ccde17c966a16528d94942b497ebfe
Deployed Bytecode
0x6080604052600436101561001a575b34156110ac575b600080fd5b60003560e01c8063062eed451461018a57806307e2ee0f146101855780630a805d5c14610180578063183a4f6e1461017b5780631c10893f146101765780631cd64df414610171578063256929621461016c5780632de94807146101675780632fac691a1461016257806347e633801461015d5780634a4ee7b114610158578063514e62fc1461015357806354d1f13d1461014e578063715018a61461014957806374715f4814610144578063764e7d241461013f5780638da5cb5b1461013a578063b7f8832014610135578063e5b046f214610130578063f04e283e1461012b578063f2fde38b14610126578063fdab463d146101215763fee81cf40361000e5761082e565b610810565b6107d4565b610784565b610746565b610713565b6106c0565b6106aa565b610663565b610601565b6105ba565b610579565b610551565b610535565b6104b4565b610449565b6103fd565b6103bb565b610359565b61031c565b610288565b610247565b6101c1565b60031990602082820112610015576004359167ffffffffffffffff8311610015578260a0920301126100155760040190565b34610015576102036101d23661018f565b6080810135600052600160205275ffffffffffffffffffffffffffffffffffffffffffff60406000205416906111c6565b60058110156102185760209060405190158152f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b34610015576000806003193601126102735760408160209254815260018352205460d81c604051908152f35b80fd5b60031960209101126100155760043590565b3461001557606061029836610276565b60409060008280516102a981610934565b828152826020820152015260005260016020528060002090808051926102ce84610934565b5475ffffffffffffffffffffffffffffffffffffffffffff8116938481526020810164ffffffffff938492838560b01c168352019260d81c8352845195865251166020850152511690820152f35b602060031936011261001557610334600435336108ed565b005b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361001557565b60406003193601126100155761036d610336565b6103756108c3565b638b78c6d8600c526000526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3005b346100155760406003193601126100155760206103f36103d9610336565b602435918291638b78c6d8600c526000526020600c205490565b1614604051908152f35b6000806003193601126102735763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b3461001557602060031936011261001557602061047b610467610336565b638b78c6d8600c526000526020600c205490565b604051908152f35b9181601f840112156100155782359167ffffffffffffffff8311610015576020808501948460051b01011161001557565b346100155760606003193601126100155767ffffffffffffffff602435818111610015576104e6903690600401610483565b909160443590811161001557610500903690600401610483565b91638b78c6d8600c523360005260016020600c205416156105275761033493600435610baf565b6382b429006000526004601cfd5b3461001557600060031936011261001557602060405160018152f35b604060031936011261001557610334610568610336565b6105706108c3565b602435906108ed565b34610015576040600319360112610015576020610594610336565b6105af60243591638b78c6d8600c526000526020600c205490565b161515604051908152f35b6000806003193601126102735763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b600080600319360112610273576106166108c3565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b3461001557600080600319360112610273578075ffffffffffffffffffffffffffffffffffffffffffff604080935492838152600160205220541682519182526020820152f35b34610015576103346106bb3661018f565b610998565b346100155760006003193601126100155760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b34610015576000806003193601126102735764ffffffffff60408260209354815260018452205460b01c16604051908152f35b346100155761075436610276565b6000526001602052602075ffffffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b602060031936011261001557610798610336565b6107a06108c3565b63389a75e1600c52806000526020600c2090815442116107c65760006103349255610861565b636f5e88186000526004601cfd5b6020600319360112610015576107e8610336565b6107f06108c3565b8060601b156108025761033490610861565b637448fbae6000526004601cfd5b34610015576000600319360112610015576020600054604051908152f35b3461001557602060031936011261001557610847610336565b63389a75e1600c52600052602080600c2054604051908152f35b73ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754330361052757565b638b78c6d8600c526000526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3565b6060810190811067ffffffffffffffff82111761095057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519061098c82610934565b565b6005111561021857565b6109f7906109f16109d66109ba60808401356000526001602052604060002090565b5475ffffffffffffffffffffffffffffffffffffffffffff1690565b75ffffffffffffffffffffffffffffffffffffffffffff1690565b906111c6565b610a008161098e565b8015610af457610a0f8161098e565b60018114610aca57610a208161098e565b60028114610aa057610a318161098e565b60038114610a765780610a4560049261098e565b14610a4c57565b60046040517fa2dbd269000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe5f5ab4d000000000000000000000000000000000000000000000000000000008152fd5b60046040517f616e11bd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f74842dbb000000000000000000000000000000000000000000000000000000008152fd5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b906000198201918211610b3557565b610af7565b91908203918211610b3557565b9190811015610b575760051b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b909291928311610015579190565b90939293848311610015578411610015578160051b01920390565b9392919260009384548015610f3a57610bc8828561154a565b8103610f11576109d66109ba610be8926000526001602052604060002090565b9181610c98846000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b03610ee75782871115610ebd5780610cb0888561131c565b03610e93577ff9443a8c8ce8cb7bee33999ea495dd8a7d58561562af63f686750774a190af1694610d9194610d889484610d82610ced8c97610b26565b610cf8818487610b47565b3592610d7a610d74867e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405601f6001831901831692836fffffffffffffffffffffffffffffffff1060071b901560081b1783811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1792831c63d76453e004161a1790565b95610b26565b851c95610b86565b906117d1565b93929092611596565b91828155610e8f610da185611072565b610dff610dad4261104c565b610df1610db94361104c565b91610de3610dc561097f565b75ffffffffffffffffffffffffffffffffffffffffffff9096168652565b64ffffffffff166020850152565b64ffffffffff166040830152565b610e13856000526001602052604060002090565b8151602083015160409093015160b09390931b7affffffffff000000000000000000000000000000000000000000001675ffffffffffffffffffffffffffffffffffffffffffff919091161760d89290921b7fffffffffff00000000000000000000000000000000000000000000000000000016919091179055565b80a3565b60046040517fc1e5467e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fdc9e24a3000000000000000000000000000000000000000000000000000000008152fd5b60046040517fcb05a28e000000000000000000000000000000000000000000000000000000008152fd5b60046040517e687252000000000000000000000000000000000000000000000000000000008152fd5b50909291506110225781610ff2856000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b03610e93577ff9443a8c8ce8cb7bee33999ea495dd8a7d58561562af63f686750774a190af1691610d919161154a565b60046040517f07701351000000000000000000000000000000000000000000000000000000008152fd5b650100000000008110156110645764ffffffffff1690565b6335278d126000526004601cfd5b7601000000000000000000000000000000000000000000008110156110645775ffffffffffffffffffffffffffffffffffffffffffff1690565b3615611153576000805b80913682101561113657813560031983011860001a60018093019381156110e257508153015b906110b6565b9360029150357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd85011860001a9301926000198252607f908181111561112b575b1601016110dc565b838101388439611123565b600090389082305af43d6000803e1561114e573d6000f35b3d6000fd5b3636f35b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610015570180359067ffffffffffffffff821161001557602001918160051b3603831361001557565b9060018201809211610b3557565b91908201809211610b3557565b908135818110156113145761127f816000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b90604084019161128f8386611157565b9190500361130b576112a9836112a4836111ab565b61131c565b9260608501936112b98587611157565b91905003611301576080936112e1610d88936112d86112ef9689611157565b92909389611157565b93909260208a0135916116b4565b910135036112fc57600090565b600490565b5050505050600390565b50505050600290565b505050600190565b90808214611536576000198201918211610b355761152d826114816113d360018561153397187f07060605060205040602030205040301060502050303040105050304000000006f8421084210842108cc6318c6db6d54be826fffffffffffffffffffffffffffffffff1060071b89881460081b1783811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1783811c61ffff1060041b1783811c60ff1060031b1792831c1c601f161a171b610b26565b809219166000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b92166000197f01010101010101010101010101010101010101010101010101010101010101017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f55555555555555555555555555555555555555555555555555555555555555558460011c1684037f3333333333333333333333333333333333333333333333333333333333333333808260021c169116018060041c01160260f81c911460081b1790565b906111b9565b90565b5050600090565b8015610b35576000190190565b916115548261153d565b928261156285809584610b47565b35935b611570575050909150565b61157c6115909561153d565b94859461158a868486610b47565b3561163e565b93611565565b949390929190806115df5750905092905b8091825b6115b457505050565b9091936115d16115d79161158a6115ca88610b26565b8686610b47565b9461153d565b9190826115ab565b6000198101818111610b35576115f9908285949394610b47565b359161160481610b26565b93845b61161e575050611617925061163e565b92906115a7565b9091926115d16116349161158a6115ca88610b26565b9392919084611607565b90604051906020820192835260408201526040815261165c81610934565b51902090565b908160011b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811603610b3557565b81810292918115918404141715610b3557565b6000198114610b355760010190565b949693959291600082938195600190828004821483151715610b35578b969795949383928c94925b60ff8310611707575b505050505050936116fa916117039597610b86565b97909796610b94565b9091565b929591949998818699929598991b8d868a1615600014611785575061173561172f8692611662565b896111b9565b116117765791611756826117679461175061175d95926116a5565b9d610b47565b359061163e565b955b831c936116a5565b8b93928d9899979695926116dc565b989994819897508296506116e5565b939b50919996908183116117c257509961158a611767936117b46117ae6117bc958d9e9f610b3a565b9961153d565b9b8c91610b47565b9561175f565b999897508d95509995996116e5565b95979496939187899493839660009560016117ee81831b85611692565b925b60ff831061180d57505050505050936116fa916117039597610b86565b929591949998818699929598991b8d868a161560001461185f575061183561172f8692611662565b116117765791611756826118509461175061175d95926116a5565b8b93928d9899979695926117f0565b939b50919996908183116117c257509961158a611850936117b46117ae6117bc958d9e9f610b3a56fea164736f6c6343000812000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d7db685f44ccde17c966a16528d94942b497ebfe
-----Decoded View---------------
Arg [0] : owner (address): 0xd7db685f44CCDe17C966A16528d94942b497EBfE
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d7db685f44ccde17c966a16528d94942b497ebfe
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.