// SPDX-License-Identifier: BUSL-1.1pragmasolidity ^0.8.0;/*//////////////////////////////////////////////////////////////
CUSTOM ERRORS
//////////////////////////////////////////////////////////////*//// Proof verification errors.errorInvalidProofLeafIdxOutOfBounds();
errorInvalidProofBadLeftRange();
errorInvalidProofBadRightRange();
errorInvalidProofUnrecognizedRoot();
/// Tree update errors.errorInvalidUpdateOldRangeMismatchShouldBeEmpty();
errorInvalidUpdateOldRangeMismatchWrongCurrentRoot();
errorInvalidUpdateOldRangeMismatchWrongLength();
errorInvalidUpdateTreeSizeMustGrow();
errorInvalidUpdateNewRangeMismatchWrongLength();
/// @title Proof/// @notice A proof for a given leaf in a merkle mountain range.structProof {
// 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.structRootInfo {
// Max value = 2**176 - 1 = ~9.5e52uint176 treeSize;
// Max value = 2**40 - 1 = ~1.1e12 = 1099511627775 seconds = tens-of-thousands of years into the futureuint40 timestamp;
// Max value = 2**40 - 1 = ~1.1e12 = 1099511627775 = thousands of years' worth of sub-second blocks into the futureuint40 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.interfaceIWitness{
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*//// @notice Emitted when the root is updated./// @param newRoot The newly accepted tree root hash./// @param newSize The newly accepted tree size.eventRootUpdated(bytes32indexed newRoot, uint256indexed newSize);
/*//////////////////////////////////////////////////////////////////////////
PUBLIC STORAGE
//////////////////////////////////////////////////////////////////////////*//// @notice The current root hash./// @dev This is the root hash of the most recently accepted update.functioncurrentRoot() externalviewreturns (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.functionrootInfo(bytes32 root) externalviewreturns (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.functionrootCache(bytes32 root) externalviewreturns (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.functiongetCurrentTreeState() externalviewreturns (bytes32, uint256);
/// @notice Helper util to get the last `block.timestamp` the tree was updated.////// @return timestamp The `block.timestamp` the update was made.functiongetLastUpdateTime() externalviewreturns (uint256);
/// @notice Helper util to get the last `block.number` the tree was updated.////// @return block The `block.timestamp` the update was made.functiongetLastUpdateBlock() externalviewreturns (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.functionverifyProof(Proof calldata proof) externalview;
/// @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.functionsafeVerifyProof(Proof calldata proof) externalviewreturns (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.functionupdateTreeRoot(uint256 newSize, bytes32[] calldata oldRange, bytes32[] calldata newRange) external;
}
Contract Source Code
File 2 of 8: LibBit.sol
// SPDX-License-Identifier: MITpragmasolidity ^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)libraryLibBit{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* 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.functionfls(uint256 x) internalpurereturns (uint256 r) {
/// @solidity memory-safe-assemblyassembly {
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.functionclz(uint256 x) internalpurereturns (uint256 r) {
/// @solidity memory-safe-assemblyassembly {
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.functionffs(uint256 x) internalpurereturns (uint256 r) {
/// @solidity memory-safe-assemblyassembly {
// 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`.functionpopCount(uint256 x) internalpurereturns (uint256 c) {
/// @solidity memory-safe-assemblyassembly {
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.functionisPo2(uint256 x) internalpurereturns (bool result) {
/// @solidity memory-safe-assemblyassembly {
// Equivalent to `x && !(x & (x - 1))`.
result :=iszero(add(and(x, sub(x, 1)), iszero(x)))
}
}
/// @dev Returns `x` reversed at the bit level.functionreverseBits(uint256 x) internalpurereturns (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.functionreverseBytes(uint256 x) internalpurereturns (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.functionrawAnd(bool x, bool y) internalpurereturns (bool z) {
/// @solidity memory-safe-assemblyassembly {
z :=and(x, y)
}
}
/// @dev Returns `x & y`.functionand(bool x, bool y) internalpurereturns (bool z) {
/// @solidity memory-safe-assemblyassembly {
z :=and(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns `x | y`. Inputs must be clean.functionrawOr(bool x, bool y) internalpurereturns (bool z) {
/// @solidity memory-safe-assemblyassembly {
z :=or(x, y)
}
}
/// @dev Returns `x | y`.functionor(bool x, bool y) internalpurereturns (bool z) {
/// @solidity memory-safe-assemblyassembly {
z :=or(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns 1 if `b` is true, else 0. Input must be clean.functionrawToUint(bool b) internalpurereturns (uint256 z) {
/// @solidity memory-safe-assemblyassembly {
z := b
}
}
/// @dev Returns 1 if `b` is true, else 0.functiontoUint(bool b) internalpurereturns (uint256 z) {
/// @solidity memory-safe-assemblyassembly {
z :=iszero(iszero(b))
}
}
}
Contract Source Code
File 3 of 8: LibZip.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.libraryLibZip{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* 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`.functionflzCompress(bytesmemory data) internalpurereturns (bytesmemory result) {
/// @solidity memory-safe-assemblyassembly {
functionms8(d_, v_) ->_d{
mstore8(d_, v_)
_d :=add(d_, 1)
}
functionu24(p_) -> _u{
_u := mload(p_)
_u := or(shl(16, byte(2, _u)), or(shl(8, byte(1, _u)), byte(0, _u)))
}
functioncmp(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_)
}
}
functionliterals(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_))
}
functionmt(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_))
}
functionsetHash(i_, v_) {
let p_ := add(mload(0x40), shl(2, i_))
mstore(p_, xor(mload(p_), shl(224, xor(shr(224, mload(p_)), v_))))
}
functiongetHash(i_) -> _h{
_h := shr(224, mload(add(mload(0x40), shl(2, i_))))
}
functionhash(v_) -> _r{
_r := and(shr(19, mul(2654435769, v_)), 0x1fff)
}
functionsetNextHash(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 :=0for {} 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`.functionflzDecompress(bytesmemory data) internalpurereturns (bytesmemory result) {
/// @solidity memory-safe-assemblyassembly {
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)
ifiszero(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)))))) // Mlet s :=add(add(shl(8, and(0x1f, c)), byte(add(1, g), w)), 1) // Rlet 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)
iflt(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`.functioncdCompress(bytesmemory data) internalpurereturns (bytesmemory result) {
/// @solidity memory-safe-assemblyassembly {
functionrle(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`.functioncdDecompress(bytesmemory data) internalpurereturns (bytesmemory result) {
/// @solidity memory-safe-assemblyassembly {
ifmload(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))
ifiszero(c) {
data :=add(data, 1)
let d :=byte(31, mload(data))
// Fill with either 0xff or 0x00.mstore(o, not(0))
ifiszero(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.functioncdFallback() internal{
assembly {
ifiszero(calldatasize()) { return(calldatasize(), calldatasize()) }
let o :=0let 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)
ifiszero(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))
ifiszero(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())
ifiszero(success) { revert(0x00, returndatasize()) }
return(0x00, returndatasize())
}
}
}
Contract Source Code
File 4 of 8: Ownable.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.abstractcontractOwnable{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* CUSTOM ERRORS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev The caller is not authorized to call the function.errorUnauthorized();
/// @dev The `newOwner` cannot be the zero address.errorNewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.errorNoHandoverRequest();
/// @dev Cannot double-initialize.errorAlreadyInitialized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* 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.eventOwnershipTransferred(addressindexed oldOwner, addressindexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.eventOwnershipHandoverRequested(addressindexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.eventOwnershipHandoverCanceled(addressindexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.uint256privateconstant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.uint256privateconstant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.uint256privateconstant _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.bytes32internalconstant _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.uint256privateconstant _HANDOVER_SLOT_SEED =0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* INTERNAL FUNCTIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Override to return true to make `_initializeOwner` prevent double-initialization.function_guardInitializeOwner() internalpurevirtualreturns (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) internalvirtual{
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assemblyassembly {
let ownerSlot := _OWNER_SLOT
ifsload(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-assemblyassembly {
// 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) internalvirtual{
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assemblyassembly {
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-assemblyassembly {
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() internalviewvirtual{
/// @solidity memory-safe-assemblyassembly {
// If the caller is not the stored owner, revert.ifiszero(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() internalviewvirtualreturns (uint64) {
return48*3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* PUBLIC UPDATE FUNCTIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Allows the owner to transfer the ownership to `newOwner`.functiontransferOwnership(address newOwner) publicpayablevirtualonlyOwner{
/// @solidity memory-safe-assemblyassembly {
ifiszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.functionrenounceOwnership() publicpayablevirtualonlyOwner{
_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.functionrequestOwnershipHandover() publicpayablevirtual{
unchecked {
uint256 expires =block.timestamp+ _ownershipHandoverValidFor();
/// @solidity memory-safe-assemblyassembly {
// 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.functioncancelOwnershipHandover() publicpayablevirtual{
/// @solidity memory-safe-assemblyassembly {
// 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`.functioncompleteOwnershipHandover(address pendingOwner) publicpayablevirtualonlyOwner{
/// @solidity memory-safe-assemblyassembly {
// 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.ifgt(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.functionowner() publicviewvirtualreturns (address result) {
/// @solidity memory-safe-assemblyassembly {
result :=sload(_OWNER_SLOT)
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.functionownershipHandoverExpiresAt(address pendingOwner)
publicviewvirtualreturns (uint256 result)
{
/// @solidity memory-safe-assemblyassembly {
// 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.modifieronlyOwner() virtual{
_checkOwner();
_;
}
}
Contract Source Code
File 5 of 8: OwnableRoles.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.abstractcontractOwnableRolesisOwnable{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* EVENTS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev The `user`'s roles is updated to `roles`./// Each bit of `roles` represents whether the role is set.eventRolesUpdated(addressindexed user, uint256indexed roles);
/// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.uint256privateconstant _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")))`.uint256privateconstant _ROLE_SLOT_SEED =0x8b78c6d8;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* INTERNAL FUNCTIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Overwrite the roles directly without authorization guard.function_setRoles(address user, uint256 roles) internalvirtual{
/// @solidity memory-safe-assemblyassembly {
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) internalvirtual{
/// @solidity memory-safe-assemblyassembly {
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.ifiszero(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) internalvirtual{
_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) internalvirtual{
_updateRoles(user, roles, false);
}
/// @dev Throws if the sender does not have any of the `roles`.function_checkRoles(uint256 roles) internalviewvirtual{
/// @solidity memory-safe-assemblyassembly {
// 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.ifiszero(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) internalviewvirtual{
/// @solidity memory-safe-assemblyassembly {
// If the caller is not the stored owner.// Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.ifiszero(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.ifiszero(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) internalviewvirtual{
/// @solidity memory-safe-assemblyassembly {
// 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.ifiszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
// If the caller is not the stored owner.// Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.ifiszero(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) internalpurereturns (uint256 roles) {
/// @solidity memory-safe-assemblyassembly {
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) internalpurereturns (uint8[] memory ordinals) {
/// @solidity memory-safe-assemblyassembly {
// 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)
ifiszero(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.functiongrantRoles(address user, uint256 roles) publicpayablevirtualonlyOwner{
_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.functionrevokeRoles(address user, uint256 roles) publicpayablevirtualonlyOwner{
_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.functionrenounceRoles(uint256 roles) publicpayablevirtual{
_removeRoles(msg.sender, roles);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* PUBLIC READ FUNCTIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Returns the roles of `user`.functionrolesOf(address user) publicviewvirtualreturns (uint256 roles) {
/// @solidity memory-safe-assemblyassembly {
// 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`.functionhasAnyRole(address user, uint256 roles) publicviewvirtualreturns (bool) {
return rolesOf(user) & roles !=0;
}
/// @dev Returns whether `user` has all of `roles`.functionhasAllRoles(address user, uint256 roles) publicviewvirtualreturns (bool) {
return rolesOf(user) & roles == roles;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* MODIFIERS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Marks a function as only callable by an account with `roles`.modifieronlyRoles(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.modifieronlyOwnerOrRoles(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.modifieronlyRolesOrOwner(uint256 roles) virtual{
_checkRolesOrOwner(roles);
_;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* ROLE CONSTANTS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/// IYKYKuint256internalconstant _ROLE_0 =1<<0;
uint256internalconstant _ROLE_1 =1<<1;
uint256internalconstant _ROLE_2 =1<<2;
uint256internalconstant _ROLE_3 =1<<3;
uint256internalconstant _ROLE_4 =1<<4;
uint256internalconstant _ROLE_5 =1<<5;
uint256internalconstant _ROLE_6 =1<<6;
uint256internalconstant _ROLE_7 =1<<7;
uint256internalconstant _ROLE_8 =1<<8;
uint256internalconstant _ROLE_9 =1<<9;
uint256internalconstant _ROLE_10 =1<<10;
uint256internalconstant _ROLE_11 =1<<11;
uint256internalconstant _ROLE_12 =1<<12;
uint256internalconstant _ROLE_13 =1<<13;
uint256internalconstant _ROLE_14 =1<<14;
uint256internalconstant _ROLE_15 =1<<15;
uint256internalconstant _ROLE_16 =1<<16;
uint256internalconstant _ROLE_17 =1<<17;
uint256internalconstant _ROLE_18 =1<<18;
uint256internalconstant _ROLE_19 =1<<19;
uint256internalconstant _ROLE_20 =1<<20;
uint256internalconstant _ROLE_21 =1<<21;
uint256internalconstant _ROLE_22 =1<<22;
uint256internalconstant _ROLE_23 =1<<23;
uint256internalconstant _ROLE_24 =1<<24;
uint256internalconstant _ROLE_25 =1<<25;
uint256internalconstant _ROLE_26 =1<<26;
uint256internalconstant _ROLE_27 =1<<27;
uint256internalconstant _ROLE_28 =1<<28;
uint256internalconstant _ROLE_29 =1<<29;
uint256internalconstant _ROLE_30 =1<<30;
uint256internalconstant _ROLE_31 =1<<31;
uint256internalconstant _ROLE_32 =1<<32;
uint256internalconstant _ROLE_33 =1<<33;
uint256internalconstant _ROLE_34 =1<<34;
uint256internalconstant _ROLE_35 =1<<35;
uint256internalconstant _ROLE_36 =1<<36;
uint256internalconstant _ROLE_37 =1<<37;
uint256internalconstant _ROLE_38 =1<<38;
uint256internalconstant _ROLE_39 =1<<39;
uint256internalconstant _ROLE_40 =1<<40;
uint256internalconstant _ROLE_41 =1<<41;
uint256internalconstant _ROLE_42 =1<<42;
uint256internalconstant _ROLE_43 =1<<43;
uint256internalconstant _ROLE_44 =1<<44;
uint256internalconstant _ROLE_45 =1<<45;
uint256internalconstant _ROLE_46 =1<<46;
uint256internalconstant _ROLE_47 =1<<47;
uint256internalconstant _ROLE_48 =1<<48;
uint256internalconstant _ROLE_49 =1<<49;
uint256internalconstant _ROLE_50 =1<<50;
uint256internalconstant _ROLE_51 =1<<51;
uint256internalconstant _ROLE_52 =1<<52;
uint256internalconstant _ROLE_53 =1<<53;
uint256internalconstant _ROLE_54 =1<<54;
uint256internalconstant _ROLE_55 =1<<55;
uint256internalconstant _ROLE_56 =1<<56;
uint256internalconstant _ROLE_57 =1<<57;
uint256internalconstant _ROLE_58 =1<<58;
uint256internalconstant _ROLE_59 =1<<59;
uint256internalconstant _ROLE_60 =1<<60;
uint256internalconstant _ROLE_61 =1<<61;
uint256internalconstant _ROLE_62 =1<<62;
uint256internalconstant _ROLE_63 =1<<63;
uint256internalconstant _ROLE_64 =1<<64;
uint256internalconstant _ROLE_65 =1<<65;
uint256internalconstant _ROLE_66 =1<<66;
uint256internalconstant _ROLE_67 =1<<67;
uint256internalconstant _ROLE_68 =1<<68;
uint256internalconstant _ROLE_69 =1<<69;
uint256internalconstant _ROLE_70 =1<<70;
uint256internalconstant _ROLE_71 =1<<71;
uint256internalconstant _ROLE_72 =1<<72;
uint256internalconstant _ROLE_73 =1<<73;
uint256internalconstant _ROLE_74 =1<<74;
uint256internalconstant _ROLE_75 =1<<75;
uint256internalconstant _ROLE_76 =1<<76;
uint256internalconstant _ROLE_77 =1<<77;
uint256internalconstant _ROLE_78 =1<<78;
uint256internalconstant _ROLE_79 =1<<79;
uint256internalconstant _ROLE_80 =1<<80;
uint256internalconstant _ROLE_81 =1<<81;
uint256internalconstant _ROLE_82 =1<<82;
uint256internalconstant _ROLE_83 =1<<83;
uint256internalconstant _ROLE_84 =1<<84;
uint256internalconstant _ROLE_85 =1<<85;
uint256internalconstant _ROLE_86 =1<<86;
uint256internalconstant _ROLE_87 =1<<87;
uint256internalconstant _ROLE_88 =1<<88;
uint256internalconstant _ROLE_89 =1<<89;
uint256internalconstant _ROLE_90 =1<<90;
uint256internalconstant _ROLE_91 =1<<91;
uint256internalconstant _ROLE_92 =1<<92;
uint256internalconstant _ROLE_93 =1<<93;
uint256internalconstant _ROLE_94 =1<<94;
uint256internalconstant _ROLE_95 =1<<95;
uint256internalconstant _ROLE_96 =1<<96;
uint256internalconstant _ROLE_97 =1<<97;
uint256internalconstant _ROLE_98 =1<<98;
uint256internalconstant _ROLE_99 =1<<99;
uint256internalconstant _ROLE_100 =1<<100;
uint256internalconstant _ROLE_101 =1<<101;
uint256internalconstant _ROLE_102 =1<<102;
uint256internalconstant _ROLE_103 =1<<103;
uint256internalconstant _ROLE_104 =1<<104;
uint256internalconstant _ROLE_105 =1<<105;
uint256internalconstant _ROLE_106 =1<<106;
uint256internalconstant _ROLE_107 =1<<107;
uint256internalconstant _ROLE_108 =1<<108;
uint256internalconstant _ROLE_109 =1<<109;
uint256internalconstant _ROLE_110 =1<<110;
uint256internalconstant _ROLE_111 =1<<111;
uint256internalconstant _ROLE_112 =1<<112;
uint256internalconstant _ROLE_113 =1<<113;
uint256internalconstant _ROLE_114 =1<<114;
uint256internalconstant _ROLE_115 =1<<115;
uint256internalconstant _ROLE_116 =1<<116;
uint256internalconstant _ROLE_117 =1<<117;
uint256internalconstant _ROLE_118 =1<<118;
uint256internalconstant _ROLE_119 =1<<119;
uint256internalconstant _ROLE_120 =1<<120;
uint256internalconstant _ROLE_121 =1<<121;
uint256internalconstant _ROLE_122 =1<<122;
uint256internalconstant _ROLE_123 =1<<123;
uint256internalconstant _ROLE_124 =1<<124;
uint256internalconstant _ROLE_125 =1<<125;
uint256internalconstant _ROLE_126 =1<<126;
uint256internalconstant _ROLE_127 =1<<127;
uint256internalconstant _ROLE_128 =1<<128;
uint256internalconstant _ROLE_129 =1<<129;
uint256internalconstant _ROLE_130 =1<<130;
uint256internalconstant _ROLE_131 =1<<131;
uint256internalconstant _ROLE_132 =1<<132;
uint256internalconstant _ROLE_133 =1<<133;
uint256internalconstant _ROLE_134 =1<<134;
uint256internalconstant _ROLE_135 =1<<135;
uint256internalconstant _ROLE_136 =1<<136;
uint256internalconstant _ROLE_137 =1<<137;
uint256internalconstant _ROLE_138 =1<<138;
uint256internalconstant _ROLE_139 =1<<139;
uint256internalconstant _ROLE_140 =1<<140;
uint256internalconstant _ROLE_141 =1<<141;
uint256internalconstant _ROLE_142 =1<<142;
uint256internalconstant _ROLE_143 =1<<143;
uint256internalconstant _ROLE_144 =1<<144;
uint256internalconstant _ROLE_145 =1<<145;
uint256internalconstant _ROLE_146 =1<<146;
uint256internalconstant _ROLE_147 =1<<147;
uint256internalconstant _ROLE_148 =1<<148;
uint256internalconstant _ROLE_149 =1<<149;
uint256internalconstant _ROLE_150 =1<<150;
uint256internalconstant _ROLE_151 =1<<151;
uint256internalconstant _ROLE_152 =1<<152;
uint256internalconstant _ROLE_153 =1<<153;
uint256internalconstant _ROLE_154 =1<<154;
uint256internalconstant _ROLE_155 =1<<155;
uint256internalconstant _ROLE_156 =1<<156;
uint256internalconstant _ROLE_157 =1<<157;
uint256internalconstant _ROLE_158 =1<<158;
uint256internalconstant _ROLE_159 =1<<159;
uint256internalconstant _ROLE_160 =1<<160;
uint256internalconstant _ROLE_161 =1<<161;
uint256internalconstant _ROLE_162 =1<<162;
uint256internalconstant _ROLE_163 =1<<163;
uint256internalconstant _ROLE_164 =1<<164;
uint256internalconstant _ROLE_165 =1<<165;
uint256internalconstant _ROLE_166 =1<<166;
uint256internalconstant _ROLE_167 =1<<167;
uint256internalconstant _ROLE_168 =1<<168;
uint256internalconstant _ROLE_169 =1<<169;
uint256internalconstant _ROLE_170 =1<<170;
uint256internalconstant _ROLE_171 =1<<171;
uint256internalconstant _ROLE_172 =1<<172;
uint256internalconstant _ROLE_173 =1<<173;
uint256internalconstant _ROLE_174 =1<<174;
uint256internalconstant _ROLE_175 =1<<175;
uint256internalconstant _ROLE_176 =1<<176;
uint256internalconstant _ROLE_177 =1<<177;
uint256internalconstant _ROLE_178 =1<<178;
uint256internalconstant _ROLE_179 =1<<179;
uint256internalconstant _ROLE_180 =1<<180;
uint256internalconstant _ROLE_181 =1<<181;
uint256internalconstant _ROLE_182 =1<<182;
uint256internalconstant _ROLE_183 =1<<183;
uint256internalconstant _ROLE_184 =1<<184;
uint256internalconstant _ROLE_185 =1<<185;
uint256internalconstant _ROLE_186 =1<<186;
uint256internalconstant _ROLE_187 =1<<187;
uint256internalconstant _ROLE_188 =1<<188;
uint256internalconstant _ROLE_189 =1<<189;
uint256internalconstant _ROLE_190 =1<<190;
uint256internalconstant _ROLE_191 =1<<191;
uint256internalconstant _ROLE_192 =1<<192;
uint256internalconstant _ROLE_193 =1<<193;
uint256internalconstant _ROLE_194 =1<<194;
uint256internalconstant _ROLE_195 =1<<195;
uint256internalconstant _ROLE_196 =1<<196;
uint256internalconstant _ROLE_197 =1<<197;
uint256internalconstant _ROLE_198 =1<<198;
uint256internalconstant _ROLE_199 =1<<199;
uint256internalconstant _ROLE_200 =1<<200;
uint256internalconstant _ROLE_201 =1<<201;
uint256internalconstant _ROLE_202 =1<<202;
uint256internalconstant _ROLE_203 =1<<203;
uint256internalconstant _ROLE_204 =1<<204;
uint256internalconstant _ROLE_205 =1<<205;
uint256internalconstant _ROLE_206 =1<<206;
uint256internalconstant _ROLE_207 =1<<207;
uint256internalconstant _ROLE_208 =1<<208;
uint256internalconstant _ROLE_209 =1<<209;
uint256internalconstant _ROLE_210 =1<<210;
uint256internalconstant _ROLE_211 =1<<211;
uint256internalconstant _ROLE_212 =1<<212;
uint256internalconstant _ROLE_213 =1<<213;
uint256internalconstant _ROLE_214 =1<<214;
uint256internalconstant _ROLE_215 =1<<215;
uint256internalconstant _ROLE_216 =1<<216;
uint256internalconstant _ROLE_217 =1<<217;
uint256internalconstant _ROLE_218 =1<<218;
uint256internalconstant _ROLE_219 =1<<219;
uint256internalconstant _ROLE_220 =1<<220;
uint256internalconstant _ROLE_221 =1<<221;
uint256internalconstant _ROLE_222 =1<<222;
uint256internalconstant _ROLE_223 =1<<223;
uint256internalconstant _ROLE_224 =1<<224;
uint256internalconstant _ROLE_225 =1<<225;
uint256internalconstant _ROLE_226 =1<<226;
uint256internalconstant _ROLE_227 =1<<227;
uint256internalconstant _ROLE_228 =1<<228;
uint256internalconstant _ROLE_229 =1<<229;
uint256internalconstant _ROLE_230 =1<<230;
uint256internalconstant _ROLE_231 =1<<231;
uint256internalconstant _ROLE_232 =1<<232;
uint256internalconstant _ROLE_233 =1<<233;
uint256internalconstant _ROLE_234 =1<<234;
uint256internalconstant _ROLE_235 =1<<235;
uint256internalconstant _ROLE_236 =1<<236;
uint256internalconstant _ROLE_237 =1<<237;
uint256internalconstant _ROLE_238 =1<<238;
uint256internalconstant _ROLE_239 =1<<239;
uint256internalconstant _ROLE_240 =1<<240;
uint256internalconstant _ROLE_241 =1<<241;
uint256internalconstant _ROLE_242 =1<<242;
uint256internalconstant _ROLE_243 =1<<243;
uint256internalconstant _ROLE_244 =1<<244;
uint256internalconstant _ROLE_245 =1<<245;
uint256internalconstant _ROLE_246 =1<<246;
uint256internalconstant _ROLE_247 =1<<247;
uint256internalconstant _ROLE_248 =1<<248;
uint256internalconstant _ROLE_249 =1<<249;
uint256internalconstant _ROLE_250 =1<<250;
uint256internalconstant _ROLE_251 =1<<251;
uint256internalconstant _ROLE_252 =1<<252;
uint256internalconstant _ROLE_253 =1<<253;
uint256internalconstant _ROLE_254 =1<<254;
uint256internalconstant _ROLE_255 =1<<255;
}
Contract Source Code
File 6 of 8: SafeCastLib.sol
// SPDX-License-Identifier: MITpragmasolidity ^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)librarySafeCastLib{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* CUSTOM ERRORS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/errorOverflow();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* UNSIGNED INTEGER SAFE CASTING OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/functiontoUint8(uint256 x) internalpurereturns (uint8) {
if (x >=1<<8) _revertOverflow();
returnuint8(x);
}
functiontoUint16(uint256 x) internalpurereturns (uint16) {
if (x >=1<<16) _revertOverflow();
returnuint16(x);
}
functiontoUint24(uint256 x) internalpurereturns (uint24) {
if (x >=1<<24) _revertOverflow();
returnuint24(x);
}
functiontoUint32(uint256 x) internalpurereturns (uint32) {
if (x >=1<<32) _revertOverflow();
returnuint32(x);
}
functiontoUint40(uint256 x) internalpurereturns (uint40) {
if (x >=1<<40) _revertOverflow();
returnuint40(x);
}
functiontoUint48(uint256 x) internalpurereturns (uint48) {
if (x >=1<<48) _revertOverflow();
returnuint48(x);
}
functiontoUint56(uint256 x) internalpurereturns (uint56) {
if (x >=1<<56) _revertOverflow();
returnuint56(x);
}
functiontoUint64(uint256 x) internalpurereturns (uint64) {
if (x >=1<<64) _revertOverflow();
returnuint64(x);
}
functiontoUint72(uint256 x) internalpurereturns (uint72) {
if (x >=1<<72) _revertOverflow();
returnuint72(x);
}
functiontoUint80(uint256 x) internalpurereturns (uint80) {
if (x >=1<<80) _revertOverflow();
returnuint80(x);
}
functiontoUint88(uint256 x) internalpurereturns (uint88) {
if (x >=1<<88) _revertOverflow();
returnuint88(x);
}
functiontoUint96(uint256 x) internalpurereturns (uint96) {
if (x >=1<<96) _revertOverflow();
returnuint96(x);
}
functiontoUint104(uint256 x) internalpurereturns (uint104) {
if (x >=1<<104) _revertOverflow();
returnuint104(x);
}
functiontoUint112(uint256 x) internalpurereturns (uint112) {
if (x >=1<<112) _revertOverflow();
returnuint112(x);
}
functiontoUint120(uint256 x) internalpurereturns (uint120) {
if (x >=1<<120) _revertOverflow();
returnuint120(x);
}
functiontoUint128(uint256 x) internalpurereturns (uint128) {
if (x >=1<<128) _revertOverflow();
returnuint128(x);
}
functiontoUint136(uint256 x) internalpurereturns (uint136) {
if (x >=1<<136) _revertOverflow();
returnuint136(x);
}
functiontoUint144(uint256 x) internalpurereturns (uint144) {
if (x >=1<<144) _revertOverflow();
returnuint144(x);
}
functiontoUint152(uint256 x) internalpurereturns (uint152) {
if (x >=1<<152) _revertOverflow();
returnuint152(x);
}
functiontoUint160(uint256 x) internalpurereturns (uint160) {
if (x >=1<<160) _revertOverflow();
returnuint160(x);
}
functiontoUint168(uint256 x) internalpurereturns (uint168) {
if (x >=1<<168) _revertOverflow();
returnuint168(x);
}
functiontoUint176(uint256 x) internalpurereturns (uint176) {
if (x >=1<<176) _revertOverflow();
returnuint176(x);
}
functiontoUint184(uint256 x) internalpurereturns (uint184) {
if (x >=1<<184) _revertOverflow();
returnuint184(x);
}
functiontoUint192(uint256 x) internalpurereturns (uint192) {
if (x >=1<<192) _revertOverflow();
returnuint192(x);
}
functiontoUint200(uint256 x) internalpurereturns (uint200) {
if (x >=1<<200) _revertOverflow();
returnuint200(x);
}
functiontoUint208(uint256 x) internalpurereturns (uint208) {
if (x >=1<<208) _revertOverflow();
returnuint208(x);
}
functiontoUint216(uint256 x) internalpurereturns (uint216) {
if (x >=1<<216) _revertOverflow();
returnuint216(x);
}
functiontoUint224(uint256 x) internalpurereturns (uint224) {
if (x >=1<<224) _revertOverflow();
returnuint224(x);
}
functiontoUint232(uint256 x) internalpurereturns (uint232) {
if (x >=1<<232) _revertOverflow();
returnuint232(x);
}
functiontoUint240(uint256 x) internalpurereturns (uint240) {
if (x >=1<<240) _revertOverflow();
returnuint240(x);
}
functiontoUint248(uint256 x) internalpurereturns (uint248) {
if (x >=1<<248) _revertOverflow();
returnuint248(x);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* SIGNED INTEGER SAFE CASTING OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/functiontoInt8(int256 x) internalpurereturns (int8) {
int8 y =int8(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt16(int256 x) internalpurereturns (int16) {
int16 y =int16(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt24(int256 x) internalpurereturns (int24) {
int24 y =int24(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt32(int256 x) internalpurereturns (int32) {
int32 y =int32(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt40(int256 x) internalpurereturns (int40) {
int40 y =int40(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt48(int256 x) internalpurereturns (int48) {
int48 y =int48(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt56(int256 x) internalpurereturns (int56) {
int56 y =int56(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt64(int256 x) internalpurereturns (int64) {
int64 y =int64(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt72(int256 x) internalpurereturns (int72) {
int72 y =int72(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt80(int256 x) internalpurereturns (int80) {
int80 y =int80(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt88(int256 x) internalpurereturns (int88) {
int88 y =int88(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt96(int256 x) internalpurereturns (int96) {
int96 y =int96(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt104(int256 x) internalpurereturns (int104) {
int104 y =int104(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt112(int256 x) internalpurereturns (int112) {
int112 y =int112(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt120(int256 x) internalpurereturns (int120) {
int120 y =int120(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt128(int256 x) internalpurereturns (int128) {
int128 y =int128(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt136(int256 x) internalpurereturns (int136) {
int136 y =int136(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt144(int256 x) internalpurereturns (int144) {
int144 y =int144(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt152(int256 x) internalpurereturns (int152) {
int152 y =int152(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt160(int256 x) internalpurereturns (int160) {
int160 y =int160(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt168(int256 x) internalpurereturns (int168) {
int168 y =int168(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt176(int256 x) internalpurereturns (int176) {
int176 y =int176(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt184(int256 x) internalpurereturns (int184) {
int184 y =int184(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt192(int256 x) internalpurereturns (int192) {
int192 y =int192(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt200(int256 x) internalpurereturns (int200) {
int200 y =int200(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt208(int256 x) internalpurereturns (int208) {
int208 y =int208(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt216(int256 x) internalpurereturns (int216) {
int216 y =int216(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt224(int256 x) internalpurereturns (int224) {
int224 y =int224(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt232(int256 x) internalpurereturns (int232) {
int232 y =int232(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt240(int256 x) internalpurereturns (int240) {
int240 y =int240(x);
if (x != y) _revertOverflow();
return y;
}
functiontoInt248(int256 x) internalpurereturns (int248) {
int248 y =int248(x);
if (x != y) _revertOverflow();
return y;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* OTHER SAFE CASTING OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/functiontoInt256(uint256 x) internalpurereturns (int256) {
if (x >=1<<255) _revertOverflow();
returnint256(x);
}
functiontoUint256(int256 x) internalpurereturns (uint256) {
if (x <0) _revertOverflow();
returnuint256(x);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* PRIVATE HELPERS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/function_revertOverflow() privatepure{
/// @solidity memory-safe-assemblyassembly {
// Store the function selector of `Overflow()`.mstore(0x00, 0x35278d12)
// Revert with (offset, size).revert(0x1c, 0x04)
}
}
}
Contract Source Code
File 7 of 8: Witness.sol
// SPDX-License-Identifier: BUSL-1.1pragmasolidity ^0.8.0;import { OwnableRoles } from"solady/auth/OwnableRoles.sol";
import { LibBit } from"solady/utils/LibBit.sol";
import { LibZip } from"solady/utils/LibZip.sol";
import { SafeCastLib } from"solady/utils/SafeCastLib.sol";
import {
InvalidProofBadLeftRange,
InvalidProofBadRightRange,
InvalidProofLeafIdxOutOfBounds,
InvalidProofUnrecognizedRoot,
InvalidUpdateNewRangeMismatchWrongLength,
InvalidUpdateOldRangeMismatchShouldBeEmpty,
InvalidUpdateOldRangeMismatchWrongCurrentRoot,
InvalidUpdateOldRangeMismatchWrongLength,
InvalidUpdateTreeSizeMustGrow,
IWitness,
Proof,
RootInfo
} from"./interfaces/IWitness.sol";
import {
getRangeSizeForNonZeroBeginningInterval,
getRoot,
getRootForMergedRange,
merge,
ProofError,
validateProof
} from"./WitnessUtils.sol";
/// @title Witness/// @author sina.eth/// @custom:coauthor runtheblocks.eth/// @notice The core Witness smart contract./// @dev The Witness smart contract tracks a merkle mountain range and enforces/// that any newly posted merkle root is consistent with the previous root.contractWitnessisIWitness, OwnableRoles{
usingSafeCastLibforuint256;
usingLibBitforuint256;
/*//////////////////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////////////////*/uint256publicconstant UPDATER_ROLE = _ROLE_0;
/*//////////////////////////////////////////////////////////////////////////
MUTABLE STORAGE
//////////////////////////////////////////////////////////////////////////*//// @inheritdoc IWitnessbytes32public currentRoot;
mapping(bytes32 root => RootInfo cache) internal _rootInfo;
/// @inheritdoc IWitnessfunctionrootInfo(bytes32 root) publicviewvirtualreturns (RootInfo memory) {
return _rootInfo[root];
}
/// @inheritdoc IWitnessfunctionrootCache(bytes32 root) publicviewvirtualreturns (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 IWitnessfunctiongetCurrentTreeState() externalviewvirtualreturns (bytes32, uint256) {
bytes32 _currentRoot = currentRoot;
return (_currentRoot, _rootInfo[_currentRoot].treeSize);
}
/// @inheritdoc IWitnessfunctiongetLastUpdateTime() externalviewvirtualreturns (uint256) {
return _rootInfo[currentRoot].timestamp;
}
/// @inheritdoc IWitnessfunctiongetLastUpdateBlock() externalviewvirtualreturns (uint256) {
return _rootInfo[currentRoot].height;
}
/// @inheritdoc IWitnessfunctionverifyProof(Proof calldata proof) externalviewvirtual{
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 IWitnessfunctionsafeVerifyProof(Proof calldata proof) externalviewreturns (bool isValid) {
return validateProof(proof, _rootInfo[proof.targetRoot].treeSize) == ProofError.NONE;
}
/*//////////////////////////////////////////////////////////////
WRITE METHODS
//////////////////////////////////////////////////////////////*//// @inheritdoc IWitnessfunctionupdateTreeRoot(uint256 newSize,
bytes32[] calldata oldRange,
bytes32[] calldata newRange
)
externalvirtualonlyRoles(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() externalvirtual{
LibZip.cdFallback();
}
}
Contract Source Code
File 8 of 8: WitnessUtils.sol
// SPDX-License-Identifier: BUSL-1.1pragmasolidity ^0.8.0;import { LibBit } from"solady/utils/LibBit.sol";
import { Proof } from"./interfaces/IWitness.sol";
enumProofError {
NONE,
InvalidProofLeafIdxOutOfBounds,
InvalidProofBadLeftRange,
InvalidProofBadRightRange,
InvalidProofUnrecognizedRoot
}
functionvalidateProof(Proof calldata proof, uint256 targetTreeSize) purereturns (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.functiondecomposeNonZeroInterval(uint256 begin, uint256 end) purereturns (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).functiongetRangeSizeForNonZeroBeginningInterval(uint256 start, uint256 end) purereturns (uint256) {
if (start == end) {
return0;
}
(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.functiongetRoot(bytes32[] calldata hashes) purereturns (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.functiongetRootForMergedRange(bytes32[] calldata leftRange,
bytes32 seed,
bytes32[] calldata rightRange
)
purereturns (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.functionhashToParent(bytes32 left, bytes32 right) purereturns (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.functionmerge(bytes32[] calldata leftRange,
bytes32 seed,
uint256 seedHeight,
uint256 seedIndex,
bytes32[] calldata rightRange,
uint256 rightRangeEnd
)
purereturns (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:];
}