Contract Overview
Balance:
0 MATIC
MATIC Value:
$0.00
My Name Tag:
Not Available, login to update
Txn Hash |
Method
|
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0xe1ab50e4bf44911c9cfa4340d60b0428b1936a5dc03f12ae38e9844d1adf569a | 0x60806040 | 40786818 | 64 days 8 hrs ago | 0xa25f22b0ab021a9ca1513c892e6faacc50e92907 | IN | Create: RainterpreterStore | 0 MATIC | 0.032686858 |
[ Download CSV Export ]
Contract Source Code Verified (Exact Match)
Contract Name:
RainterpreterStore
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../store/IInterpreterStoreV1.sol"; import "../run/LibInterpreterState.sol"; import {IERC165Upgradeable as IERC165} from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol"; /// @title RainterpreterStore /// @notice Simplest possible `IInterpreterStoreV1` that could work. /// Takes key/value pairings from the input array and stores each in an internal /// mapping. `StateNamespace` is fully qualified only by `msg.sender` on set and /// doesn't attempt to do any deduping etc. if the same key appears twice it will /// be set twice. contract RainterpreterStore is IInterpreterStoreV1, IERC165 { using LibInterpreterState for StateNamespace; /// Store is several tiers of sandbox. /// /// 0. Address hashed into `FullyQualifiedNamespace` is `msg.sender` so that /// callers cannot attack each other /// 1. StateNamespace is caller-provided namespace so that expressions cannot /// attack each other /// 2. `uint256` is expression-provided key /// 3. `uint256` is expression-provided value /// /// tiers 0 and 1 are both embodied in the `FullyQualifiedNamespace`. mapping(FullyQualifiedNamespace => mapping(uint256 => uint256)) internal store; // @inheritdoc IERC165 function supportsInterface( bytes4 interfaceId_ ) public view virtual override returns (bool) { return interfaceId_ == type(IInterpreterStoreV1).interfaceId || interfaceId_ == type(IERC165).interfaceId; } /// @inheritdoc IInterpreterStoreV1 function set(StateNamespace namespace_, uint256[] calldata kvs_) external { unchecked { FullyQualifiedNamespace fullyQualifiedNamespace_ = namespace_ .qualifyNamespace(); for (uint256 i_ = 0; i_ < kvs_.length; i_ += 2) { store[fullyQualifiedNamespace_][kvs_[i_]] = kvs_[i_ + 1]; } } } /// @inheritdoc IInterpreterStoreV1 function get( FullyQualifiedNamespace namespace_, uint256 key_ ) external view returns (uint256) { return store[namespace_][key_]; } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; import "../run/IInterpreterV1.sol"; /// A fully qualified namespace includes the interpreter's own namespacing logic /// IN ADDITION to the calling contract's requested `StateNamespace`. Typically /// this involves hashing the `msg.sender` into the `StateNamespace` so that each /// caller operates within its own disjoint state universe. Intepreters MUST NOT /// allow either the caller nor any expression/word to modify this directly on /// pain of potential key collisions on writes to the interpreter's own storage. type FullyQualifiedNamespace is uint256; IInterpreterStoreV1 constant NO_STORE = IInterpreterStoreV1(address(0)); /// @title IInterpreterStoreV1 /// @notice Tracks state changes on behalf of an interpreter. A single store can /// handle state changes for many calling contracts, many interpreters and many /// expressions. The store is responsible for ensuring that applying these state /// changes is safe from key collisions with calls to `set` from different /// `msg.sender` callers. I.e. it MUST NOT be possible for a caller to modify the /// state changes associated with some other caller. /// /// The store defines the shape of its own state changes, which is opaque to the /// calling contract. For example, some store may treat the list of state changes /// as a pairwise key/value set, and some other store may treat it as a literal /// list to be stored as-is. /// /// Each interpreter decides for itself which store to use based on the /// compatibility of its own opcodes. /// /// The store MUST assume the state changes have been corrupted by the calling /// contract due to bugs or malicious intent, and enforce state isolation between /// callers despite arbitrarily invalid state changes. The store MUST revert if /// it can detect invalid state changes, such as a key/value list having an odd /// number of items, but this MAY NOT be possible if the corruption is /// undetectable. interface IInterpreterStoreV1 { /// Mutates the interpreter store in bulk. The bulk values are provided in /// the form of a `uint256[]` which can be treated e.g. as pairwise keys and /// values to be stored in a Solidity mapping. The `IInterpreterStoreV1` /// defines the meaning of the `uint256[]` for its own storage logic. /// /// @param namespace The unqualified namespace for the set that MUST be /// fully qualified by the `IInterpreterStoreV1` to prevent key collisions /// between callers. The fully qualified namespace forms a compound key with /// the keys for each value to set. /// @param kvs The list of changes to apply to the store's internal state. function set(StateNamespace namespace, uint256[] calldata kvs) external; /// Given a fully qualified namespace and key, return the associated value. /// Ostensibly the interpreter can use this to implement opcodes that read /// previously set values. The interpreter MUST apply the same qualification /// logic as the store that it uses to guarantee consistent round tripping of /// data and prevent malicious behaviours. Technically also allows onchain /// reads of any set value from any contract, not just interpreters, but in /// this case readers MUST be aware and handle inconsistencies between get /// and set while the state changes are still in memory in the calling /// context and haven't yet been persisted to the store. /// /// `IInterpreterStoreV1` uses the same fallback behaviour for unset keys as /// Solidity. Specifically, any UNSET VALUES SILENTLY FALLBACK TO `0`. /// @param namespace The fully qualified namespace to get a single value for. /// @param key The key to get the value for within the namespace. /// @return The value OR ZERO IF NOT SET. function get( FullyQualifiedNamespace namespace, uint256 key ) external view returns (uint256); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; import "../store/IInterpreterStoreV1.sol"; /// @dev The index of a source within a deployed expression that can be evaluated /// by an `IInterpreterV1`. MAY be an entrypoint or the index of a source called /// internally such as by the `call` opcode. type SourceIndex is uint256; /// @dev Encoded information about a specific evaluation including the expression /// address onchain, entrypoint and expected return values. type EncodedDispatch is uint256; /// @dev The namespace for state changes as requested by the calling contract. /// The interpreter MUST apply this namespace IN ADDITION to namespacing by /// caller etc. type StateNamespace is uint256; /// @dev Additional bytes that can be used to configure a single opcode dispatch. /// Commonly used to specify the number of inputs to a variadic function such /// as addition or multiplication. type Operand is uint256; /// @dev The default state namespace MUST be used when a calling contract has no /// particular opinion on or need for dynamic namespaces. StateNamespace constant DEFAULT_STATE_NAMESPACE = StateNamespace.wrap(0); /// @title IInterpreterV1 /// Interface into a standard interpreter that supports: /// /// - evaluating `view` logic deployed onchain by an `IExpressionDeployerV1` /// - receiving arbitrary `uint256[][]` supporting context to be made available /// to the evaluated logic /// - handling subsequent state changes in bulk in response to evaluated logic /// - namespacing state changes according to the caller's preferences to avoid /// unwanted key collisions /// - exposing its internal function pointers to support external precompilation /// of logic for more gas efficient runtime evaluation by the interpreter /// /// The interface is designed to be stable across many versions and /// implementations of an interpreter, balancing minimalism with features /// required for a general purpose onchain interpreted compute environment. /// /// The security model of an interpreter is that it MUST be resilient to /// malicious expressions even if they dispatch arbitrary internal function /// pointers during an eval. The interpreter MAY return garbage or exhibit /// undefined behaviour or error during an eval, _provided that no state changes /// are persisted_ e.g. in storage, such that only the caller that specifies the /// malicious expression can be negatively impacted by the result. In turn, the /// caller must guard itself against arbitrarily corrupt/malicious reverts and /// return values from any interpreter that it requests an expression from. And /// so on and so forth up to the externally owned account (EOA) who signs the /// transaction and agrees to a specific combination of contracts, expressions /// and interpreters, who can presumably make an informed decision about which /// ones to trust to get the job done. /// /// The state changes for an interpreter are expected to be produces by an `eval` /// and passed to the `IInterpreterStoreV1` returned by the eval, as-is by the /// caller, after the caller has had an opportunity to apply their own /// intermediate logic such as reentrancy defenses against malicious /// interpreters. The interpreter is free to structure the state changes however /// it wants but MUST guard against the calling contract corrupting the changes /// between `eval` and `set`. For example a store could sandbox storage writes /// per-caller so that a malicious caller can only damage their own state /// changes, while honest callers respect, benefit from and are protected by the /// interpreter store's state change handling. /// /// The two step eval-state model allows eval to be read-only which provides /// security guarantees for the caller such as no stateful reentrancy, either /// from the interpreter or some contract interface used by some word, while /// still allowing for storage writes. As the storage writes happen on the /// interpreter rather than the caller (c.f. delegate call) the caller DOES NOT /// need to trust the interpreter, which allows for permissionless selection of /// interpreters by end users. Delegate call always implies an admin key on the /// caller because the delegatee contract can write arbitrarily to the state of /// the delegator, which severely limits the generality of contract composition. interface IInterpreterV1 { /// Exposes the function pointers as `uint16` values packed into a single /// `bytes` in the same order as they would be indexed into by opcodes. For /// example, if opcode `2` should dispatch function at position `0x1234` then /// the start of the returned bytes would be `0xXXXXXXXX1234` where `X` is /// a placeholder for the function pointers of opcodes `0` and `1`. /// /// `IExpressionDeployerV1` contracts use these function pointers to /// "compile" the expression into something that an interpreter can dispatch /// directly without paying gas to lookup the same at runtime. As the /// validity of any integrity check and subsequent dispatch is highly /// sensitive to both the function pointers and overall bytecode of the /// interpreter, `IExpressionDeployerV1` contracts SHOULD implement guards /// against accidentally being deployed onchain paired against an unknown /// interpreter. It is very easy for an apparent compatible pairing to be /// subtly and critically incompatible due to addition/removal/reordering of /// opcodes and compiler optimisations on the interpreter bytecode. /// /// This MAY return different values during construction vs. all other times /// after the interpreter has been successfully deployed onchain. DO NOT rely /// on function pointers reported during contract construction. function functionPointers() external view returns (bytes memory); /// The raison d'etre for an interpreter. Given some expression and per-call /// additional contextual data, produce a stack of results and a set of state /// changes that the caller MAY OPTIONALLY pass back to be persisted by a /// call to `IInterpreterStoreV1.set`. /// @param store The storage contract that the returned key/value pairs /// MUST be passed to IF the calling contract is in a non-static calling /// context. Static calling contexts MUST pass `address(0)`. /// @param namespace The state namespace that will be fully qualified by the /// interpreter at runtime in order to perform gets on the underlying store. /// MUST be the same namespace passed to the store by the calling contract /// when sending the resulting key/value items to storage. /// @param dispatch All the information required for the interpreter to load /// an expression, select an entrypoint and return the values expected by the /// caller. The interpreter MAY encode dispatches differently to /// `LibEncodedDispatch` but this WILL negatively impact compatibility for /// calling contracts that hardcode the encoding logic. /// @param context A 2-dimensional array of data that can be indexed into at /// runtime by the interpreter. The calling contract is responsible for /// ensuring the authenticity and completeness of context data. The /// interpreter MUST revert at runtime if an expression attempts to index /// into some context value that is not provided by the caller. This implies /// that context reads cannot be checked for out of bounds reads at deploy /// time, as the runtime context MAY be provided in a different shape to what /// the expression is expecting. /// Same as `eval` but allowing the caller to specify a namespace under which /// the state changes will be applied. The interpeter MUST ensure that keys /// will never collide across namespaces, even if, for example: /// /// - The calling contract is malicious and attempts to craft a collision /// with state changes from another contract /// - The expression is malicious and attempts to craft a collision with /// other expressions evaluated by the same calling contract /// /// A malicious entity MAY have access to significant offchain resources to /// attempt to precompute key collisions through brute force. The collision /// resistance of namespaces should be comparable or equivalent to the /// collision resistance of the hashing algorithms employed by the blockchain /// itself, such as the design of `mapping` in Solidity that hashes each /// nested key to produce a collision resistant compound key. /// @return stack The list of values produced by evaluating the expression. /// MUST NOT be longer than the maximum length specified by `dispatch`, if /// applicable. /// @return kvs A list of pairwise key/value items to be saved in the store. function eval( IInterpreterStoreV1 store, StateNamespace namespace, EncodedDispatch dispatch, uint256[][] calldata context ) external view returns (uint256[] memory stack, uint256[] memory kvs); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../run/IInterpreterV1.sol"; import "../deploy/IExpressionDeployerV1.sol"; import "./LibStackPointer.sol"; import "../../type/LibCast.sol"; import "../../type/LibConvert.sol"; import "../../array/LibUint256Array.sol"; import "../../memory/LibMemorySize.sol"; import {SafeCastUpgradeable as SafeCast} from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; import "../../kv/LibMemoryKV.sol"; import "hardhat/console.sol"; /// Debugging options for a standard console log over the interpreter state. /// - Stack: Log the entire stack, respects the current stack top, i.e. DOES NOT /// log every value of the underlying `uint256[]` unless the stack top points /// to the end of the array. /// - Constant: Log every constant available to the current expression. /// - Context: Log every column/row of context available to the current eval. /// - Source: Log all the raw bytes of the compiled sources being evaluated. enum DebugStyle { Stack, Constant, Context, Source } /// The standard in-memory representation of an interpreter that facilitates /// decoupled coordination between opcodes. Opcodes MAY: /// /// - push and pop values to the shared stack /// - read per-expression constants /// - write to the final state changes set within the fully qualified namespace /// - read per-eval context values /// - recursively evaluate any compiled source associated with the expression /// /// As the interpreter defines the opcodes it is its responsibility to ensure the /// opcodes are incapable of doing anything to undermine security or correctness. /// For example, a hypothetical opcode could modify the current namespace from /// the stack, but this would be a very bad idea as it would allow expressions /// to hijack storage values associated with other callers, fundamentally /// breaking the state sandbox model. /// /// The iterpreter MAY skip any runtime integrity checks that can be reasonably /// assumed to have been performed by a competent expression deployer, such as /// guarding against stack underflow. A competent expression deployer MAY NOT /// have deployed the currently evaluating expression, so the interpreter MUST /// avoid state changes during evaluation, but MAY return garbage data if the /// calling contract fails to leverage an appropriate expression deployer. /// /// @param stackBottom Opcodes write to the stack starting at the stack bottom, /// ideally using `LibStackPointer` to normalise push and pop behaviours. A /// competent expression deployer will calculate a memory preallocation that /// pushes and pops above the stack bottom effectively allocate and deallocate /// memory within. /// @param constantsBottom Opcodes read constants starting at the pointer to /// the bottom of the constants array. As the name implies the interpreter MUST /// NOT write to the constants, it is read only. /// @param stateKV The in memory key/value store that tracks reads/writes over /// the underlying interpreter storage for the duration of a single expression /// evaluation. /// @param namespace The fully qualified namespace that all state reads and /// writes MUST be performed under. /// @param store The store to reference ostensibly for gets but perhaps other /// things. /// @param context A 2-dimensional array of per-eval data provided by the calling /// contract. Opaque to the interpreter but presumably meaningful to the /// expression. /// @param compiledSources A list of sources that can be directly evaluated by /// the interpreter, either as a top level entrypoint or nested e.g. under a /// dispatch by `call`. struct InterpreterState { StackPointer stackBottom; StackPointer constantsBottom; MemoryKV stateKV; FullyQualifiedNamespace namespace; IInterpreterStoreV1 store; uint256[][] context; bytes[] compiledSources; } /// @dev squiggly lines to make the debug output easier to read. Intentionlly /// short to keep compiled code size down. string constant DEBUG_DELIMETER = "~~~"; /// @title LibInterpreterState /// @notice Main workhorse for `InterpeterState` including: /// /// - the standard `eval` loop /// - source compilation from opcodes /// - state (de)serialization (more gas efficient than abi encoding) /// - low level debugging utility /// /// Interpreters are designed to be highly moddable behind the `IInterpreterV1` /// interface, but pretty much any interpreter that uses `InterpreterState` will /// need these low level facilities verbatim. Further, these facilities /// (with possible exception of debugging logic), while relatively short in terms /// of lines of code, are surprisingly fragile to maintain in a gas efficient way /// so we don't recommend reinventing this wheel. library LibInterpreterState { using SafeCast for uint256; using LibMemorySize for uint256; using LibMemorySize for uint256[]; using LibMemorySize for bytes; using LibUint256Array for uint256[]; using LibUint256Array for uint256; using LibInterpreterState for StackPointer; using LibStackPointer for uint256[]; using LibStackPointer for StackPointer; using LibStackPointer for bytes; using LibCast for uint256; using LibCast for function( InterpreterState memory, SourceIndex, StackPointer ) view returns (StackPointer); using LibCast for function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer)[]; using LibConvert for uint256[]; /// Thin wrapper around hardhat's `console.log` that loops over any array /// and logs each value delimited by `DEBUG_DELIMITER`. /// @param array_ The array to debug. function debugArray(uint256[] memory array_) internal view { unchecked { console.log(DEBUG_DELIMETER); for (uint256 i_ = 0; i_ < array_.length; i_++) { console.log(i_, array_[i_]); } console.log(DEBUG_DELIMETER); } } /// Copies the stack to a new array then debugs it. Definitely NOT gas /// efficient, but affords simple and effective debugging. /// @param stackBottom_ Pointer to the bottom of the stack. /// @param stackTop_ Pointer to the top of the stack. function debugStack( StackPointer stackBottom_, StackPointer stackTop_ ) internal view returns (StackPointer) { uint256 length_ = stackBottom_.toIndex(stackTop_); debugArray( StackPointer.unwrap(stackTop_.down(length_)).copyToNewUint256Array( length_ ) ); return stackTop_; } /// Console log various aspects of the Interpreter state. Gas intensive and /// relies on hardhat console so not intended for production but great for /// debugging expressions. MAY be exposed as an opcode so expression authors /// can debug the expressions directly onchain. /// @param state_ The interpreter state to debug the internals of. /// @param stackTop_ Pointer to the current stack top. /// @param debugStyle_ Enum variant defining what should be debugged from the /// interpreter state. function debug( InterpreterState memory state_, StackPointer stackTop_, DebugStyle debugStyle_ ) internal view returns (StackPointer) { unchecked { if (debugStyle_ == DebugStyle.Source) { for (uint256 i_ = 0; i_ < state_.compiledSources.length; i_++) { console.logBytes(state_.compiledSources[i_]); } } else { if (debugStyle_ == DebugStyle.Stack) { state_.stackBottom.debugStack(stackTop_); } else if (debugStyle_ == DebugStyle.Constant) { debugArray(state_.constantsBottom.down().asUint256Array()); } else { for (uint256 i_ = 0; i_ < state_.context.length; i_++) { debugArray(state_.context[i_]); } } } return stackTop_; } } function serializeSize( bytes[] memory sources_, uint256[] memory constants_, uint256 stackLength_ ) internal pure returns (uint256) { uint256 size_ = 0; size_ += stackLength_.size(); size_ += constants_.size(); for (uint256 i_ = 0; i_ < sources_.length; i_++) { size_ += sources_[i_].size(); } return size_; } /// Efficiently serializes some `IInterpreterV1` state config into bytes that /// can be deserialized to an `InterpreterState` without memory allocation or /// copying of data on the return trip. This is achieved by mutating data in /// place for both serialization and deserialization so it is much more gas /// efficient than abi encode/decode but is NOT SAFE to use the /// `ExpressionConfig` after it has been serialized. Notably the index based /// opcodes in the sources in `ExpressionConfig` will be replaced by function /// pointer based opcodes in place, so are no longer usable in a portable /// format. /// @param sources_ As per `IExpressionDeployerV1`. /// @param constants_ As per `IExpressionDeployerV1`. /// @param stackLength_ Stack length calculated by `IExpressionDeployerV1` /// that will be used to allocate memory for the stack upon deserialization. /// @param opcodeFunctionPointers_ As per `IInterpreterV1.functionPointers`, /// bytes to be compiled into the final `InterpreterState.compiledSources`. function serialize( Pointer memPointer_, bytes[] memory sources_, uint256[] memory constants_, uint256 stackLength_, bytes memory opcodeFunctionPointers_ ) internal pure { unchecked { StackPointer pointer_ = StackPointer.wrap( Pointer.unwrap(memPointer_) ); // Copy stack length. pointer_ = pointer_.push(stackLength_); // Then the constants. pointer_ = pointer_.pushWithLength(constants_); // Last the sources. bytes memory source_; for (uint256 i_ = 0; i_ < sources_.length; i_++) { source_ = sources_[i_]; compile(source_, opcodeFunctionPointers_); pointer_ = pointer_.unalignedPushWithLength(source_); } } } /// Return trip from `serialize` but targets an `InterpreterState` NOT a /// `ExpressionConfig`. Allows serialized bytes to be written directly into /// contract code on the other side of an expression address, then loaded /// directly into an eval-able memory layout. The only allocation required /// is to initialise the stack for eval, there is no copying in memory from /// the serialized data as the deserialization merely calculates Solidity /// compatible pointers to positions in the raw serialized data. This is much /// more gas efficient than an equivalent abi.decode call which would involve /// more processing, copying and allocating. /// /// Note that per-eval data such as namespace and context is NOT initialised /// by the deserialization process and so will need to be handled by the /// interpreter as part of `eval`. /// /// @param serialized_ Bytes previously serialized by /// `LibInterpreterState.serialize`. /// @return An eval-able interpreter state with initialized stack. function deserialize( bytes memory serialized_ ) internal pure returns (InterpreterState memory) { unchecked { InterpreterState memory state_; // Context will probably be overridden by the caller according to the // context scratch that we deserialize so best to just set it empty // here. state_.context = new uint256[][](0); StackPointer cursor_ = serialized_.asStackPointer().up(); // The end of processing is the end of the state bytes. StackPointer end_ = cursor_.upBytes(cursor_.peek()); // Read the stack length and build a stack. cursor_ = cursor_.up(); uint256 stackLength_ = cursor_.peek(); // The stack is never stored in stack bytes so we allocate a new // array for it with length as per the indexes and point the state // at it. uint256[] memory stack_ = new uint256[](stackLength_); state_.stackBottom = stack_.asStackPointerUp(); // Reference the constants array and move cursor past it. cursor_ = cursor_.up(); state_.constantsBottom = cursor_; cursor_ = cursor_.up(cursor_.peek()); // Rebuild the sources array. uint256 i_ = 0; StackPointer lengthCursor_ = cursor_; uint256 sourcesLength_ = 0; while ( StackPointer.unwrap(lengthCursor_) < StackPointer.unwrap(end_) ) { lengthCursor_ = lengthCursor_ .upBytes(lengthCursor_.peekUp()) .up(); sourcesLength_++; } state_.compiledSources = new bytes[](sourcesLength_); while (StackPointer.unwrap(cursor_) < StackPointer.unwrap(end_)) { state_.compiledSources[i_] = cursor_.asBytes(); cursor_ = cursor_.upBytes(cursor_.peekUp()).up(); i_++; } return state_; } } /// Given a source in opcodes compile to an equivalent source with real /// function pointers for a given Interpreter contract. The "compilation" /// involves simply replacing the opcode with the pointer at the index of /// the opcode. i.e. opcode 4 will be replaced with `pointers_[4]`. /// Relies heavily on the integrity checks ensuring opcodes used are not OOB /// and that the pointers provided are valid and in the correct order. As the /// expression deployer is typically handling compilation during /// serialization, NOT the interpreter, the interpreter MUST guard against /// the compilation being garbage or outright hostile during `eval` by /// pointing to arbitrary internal functions of the interpreter. /// @param source_ The input source as index based opcodes. /// @param pointers_ The function pointers ordered by index to replace the /// index based opcodes with. function compile( bytes memory source_, bytes memory pointers_ ) internal pure { assembly ("memory-safe") { for { let replaceMask_ := 0xFFFF let preserveMask_ := not(replaceMask_) let sourceLength_ := mload(source_) let pointersBottom_ := add(pointers_, 2) let cursor_ := add(source_, 2) let end_ := add(source_, sourceLength_) } lt(cursor_, end_) { cursor_ := add(cursor_, 4) } { let data_ := mload(cursor_) let pointer_ := and( replaceMask_, mload( add(pointersBottom_, mul(2, and(data_, replaceMask_))) ) ) mstore(cursor_, or(and(data_, preserveMask_), pointer_)) } } } /// The main eval loop. Does as little as possible as it is an extremely hot /// performance and critical security path. Loads opcode/operand pairs from /// a precompiled source in the interpreter state and calls the function /// that the opcode points to. This function is in turn responsible for /// actually pushing/popping from the stack, etc. As `eval` receives the /// source index and stack top alongside its state, it supports recursive /// calls via. opcodes that can manage scoped substacks, etc. without `eval` /// needing to house that complexity itself. /// @param state_ The interpreter state to evaluate a source over. /// @param sourceIndex_ The index of the source to evaluate. MAY be an /// entrypoint or a nested call. /// @param stackTop_ The current stack top, MUST be equal to the stack bottom /// on the intepreter state if the current eval is for an entrypoint. function eval( InterpreterState memory state_, SourceIndex sourceIndex_, StackPointer stackTop_ ) internal view returns (StackPointer) { unchecked { uint256 cursor_; uint256 end_; assembly ("memory-safe") { cursor_ := mload( add( // MUST point to compiled sources. Needs updating if the // `IntepreterState` struct changes fields. mload(add(state_, 0xC0)), add(0x20, mul(0x20, sourceIndex_)) ) ) end_ := add(cursor_, mload(cursor_)) } // Loop until complete. while (cursor_ < end_) { function(InterpreterState memory, Operand, StackPointer) internal view returns (StackPointer) fn_; Operand operand_; cursor_ += 4; { uint256 op_; assembly ("memory-safe") { op_ := mload(cursor_) operand_ := and(op_, 0xFFFF) fn_ := and(shr(16, op_), 0xFFFF) } } stackTop_ = fn_(state_, operand_, stackTop_); } return stackTop_; } } /// Standard way to elevate a caller-provided state namespace to a universal /// namespace that is disjoint from all other caller-provided namespaces. /// Essentially just hashes the `msg.sender` into the state namespace as-is. /// /// This is deterministic such that the same combination of state namespace /// and caller will produce the same fully qualified namespace, even across /// multiple transactions/blocks. /// /// @param stateNamespace_ The state namespace as specified by the caller. /// @return A fully qualified namespace that cannot collide with any other /// state namespace specified by any other caller. function qualifyNamespace( StateNamespace stateNamespace_ ) internal view returns (FullyQualifiedNamespace) { return FullyQualifiedNamespace.wrap( uint256( keccak256( abi.encodePacked( msg.sender, StateNamespace.unwrap(stateNamespace_) ) ) ) ); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.17; import "../run/IInterpreterV1.sol"; /// @title IExpressionDeployerV1 /// @notice Companion to `IInterpreterV1` responsible for onchain static code /// analysis and deploying expressions. Each `IExpressionDeployerV1` is tightly /// coupled at the bytecode level to some interpreter that it knows how to /// analyse and deploy expressions for. The expression deployer can perform an /// integrity check "dry run" of candidate source code for the intepreter. The /// critical analysis/transformation includes: /// /// - Enforcement of no out of bounds memory reads/writes /// - Calculation of memory required to eval the stack with a single allocation /// - Replacing index based opcodes with absolute interpreter function pointers /// - Enforcement that all opcodes and operands used exist and are valid /// /// This analysis is highly sensitive to the specific implementation and position /// of all opcodes and function pointers as compiled into the interpreter. This /// is what makes the coupling between an interpreter and expression deployer /// so tight. Ideally all responsibilities would be handled by a single contract /// but this introduces code size issues quickly by roughly doubling the compiled /// logic of each opcode (half for the integrity check and half for evaluation). /// /// Interpreters MUST assume that expression deployers are malicious and fail /// gracefully if the integrity check is corrupt/bypassed and/or function /// pointers are incorrect, etc. i.e. the interpreter MUST always return a stack /// from `eval` in a read only way or error. I.e. it is the expression deployer's /// responsibility to do everything it can to prevent undefined behaviour in the /// interpreter, and the interpreter's responsibility to handle the expression /// deployer completely failing to do so. interface IExpressionDeployerV1 { /// This is the literal InterpreterOpMeta bytes to be used offchain to make /// sense of the opcodes in this interpreter deployment, as a human. For /// formats like json that make heavy use of boilerplate, repetition and /// whitespace, some kind of compression is recommended. /// @param sender The `msg.sender` providing the op meta. /// @param opMeta The raw binary data of the op meta. Maybe compressed data /// etc. and is intended for offchain consumption. event DISpair( address sender, address deployer, address interpreter, address store, bytes opMeta ); /// Expressions are expected to be deployed onchain as immutable contract /// code with a first class address like any other contract or account. /// Technically this is optional in the sense that all the tools required to /// eval some expression and define all its opcodes are available as /// libraries. /// /// In practise there are enough advantages to deploying the sources directly /// onchain as contract data and loading them from the interpreter at eval: /// /// - Loading and storing binary data is gas efficient as immutable contract /// data /// - Expressions need to be immutable between their deploy time integrity /// check and runtime evaluation /// - Passing the address of an expression through calldata to an interpreter /// is cheaper than passing an entire expression through calldata /// - Conceptually a very simple approach, even if implementations like /// SSTORE2 are subtle under the hood /// /// The expression deployer MUST perform an integrity check of the source /// code before it puts the expression onchain at a known address. The /// integrity check MUST at a minimum (it is free to do additional static /// analysis) calculate the memory required to be allocated for the stack in /// total, and that no out of bounds memory reads/writes occur within this /// stack. A simple example of an invalid source would be one that pushes one /// value to the stack then attempts to pops two values, clearly we cannot /// remove more values than we added. The `IExpressionDeployerV1` MUST revert /// in the case of any integrity failure, all integrity checks MUST pass in /// order for the deployment to complete. /// /// Once the integrity check is complete the `IExpressionDeployerV1` MUST do /// any additional processing required by its paired interpreter. /// For example, the `IExpressionDeployerV1` MAY NEED to replace the indexed /// opcodes in the `ExpressionConfig` sources with real function pointers /// from the corresponding interpreter. /// /// @param sources Sources verbatim. These sources MUST be provided in their /// sequential/index opcode form as the deployment process will need to index /// into BOTH the integrity check and the final runtime function pointers. /// This will be emitted in an event for offchain processing to use the /// indexed opcode sources. The first N sources are considered entrypoints /// and will be integrity checked by the expression deployer against a /// starting stack height of 0. Non-entrypoint sources MAY be provided for /// internal use such as the `call` opcode but will NOT be integrity checked /// UNLESS entered by an opcode in an entrypoint. /// @param constants Constants verbatim. Constants are provided alongside /// sources rather than inline as it allows us to avoid variable length /// opcodes and can be more memory efficient if the same constant is /// referenced several times from the sources. /// @param minOutputs The first N sources on the state config are entrypoints /// to the expression where N is the length of the `minOutputs` array. Each /// item in the `minOutputs` array specifies the number of outputs that MUST /// be present on the final stack for an evaluation of each entrypoint. The /// minimum output for some entrypoint MAY be zero if the expectation is that /// the expression only applies checks and error logic. Non-entrypoint /// sources MUST NOT have a minimum outputs length specified. /// @return interpreter The interpreter the deployer believes it is qualified /// to perform integrity checks on behalf of. /// @return store The interpreter store the deployer believes is compatible /// with the interpreter. /// @return expression The address of the deployed onchain expression. MUST /// be valid according to all integrity checks the deployer is aware of. function deployExpression( bytes[] memory sources, uint256[] memory constants, uint256[] memory minOutputs ) external returns ( IInterpreterV1 interpreter, IInterpreterStoreV1 store, address expression ); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "./IInterpreterV1.sol"; import "../../array/LibUint256Array.sol"; import "sol.lib.memory/LibMemory.sol"; /// Thrown when the length of an array as the result of an applied function does /// not match expectations. error UnexpectedResultLength(uint256 expectedLength, uint256 actualLength); /// Custom type to point to memory ostensibly in a stack. type StackPointer is uint256; /// @title LibStackPointer /// @notice A `StackPointer` is just a pointer to some memory. Ostensibly it is /// pointing at a stack item in memory used by the `RainInterpreter` so that /// means it can move "up" and "down" (increment and decrement) by `uint256` /// (32 bytes) increments. Structurally a stack is a `uint256[]` but we can save /// a lot of gas vs. default Solidity handling of array indexes by using assembly /// to bypass runtime bounds checks on every read and write. Of course, this /// means we have to introduce some mechanism that gives us equivalent guarantees /// and we do, in the form of the `IExpressionDeployerV1` integrity check. /// /// The pointer to the bottom of a stack points at the 0th item, NOT the length /// of the implied `uint256[]` and the top of a stack points AFTER the last item. /// e.g. consider a `uint256[]` in memory with values `3 A B C` and assume this /// starts at position `0` in memory, i.e. `0` points to value `3` for the /// array length. In this case the stack bottom would be /// `StackPointer.wrap(0x20)` (32 bytes above 0, past the length) and the stack /// top would be `StackPointer.wrap(0x80)` (96 bytes above the stack bottom). /// /// Most of the functions in this library are equivalent to each other via /// composition, i.e. everything could be achieved with just `up`, `down`, /// `pop`, `push`, `peek`. The reason there is so much overloaded/duplicated /// logic is that the Solidity compiler seems to fail at inlining equivalent /// logic quite a lot. Perhaps once the IR compilation of Solidity is better /// supported by tooling etc. we could remove a lot of this duplication as the /// compiler itself would handle the optimisations. library LibStackPointer { using LibStackPointer for StackPointer; using LibStackPointer for uint256[]; using LibStackPointer for bytes; using LibUint256Array for uint256[]; using LibMemory for uint256; /// Reads the value above the stack pointer. If the stack pointer is the /// current stack top this is an out of bounds read! The caller MUST ensure /// that this is not the case and that the stack pointer being read is within /// the stack and not after it. /// @param stackPointer_ Position to read past/above. function peekUp( StackPointer stackPointer_ ) internal pure returns (uint256) { uint256 a_; assembly ("memory-safe") { a_ := mload(stackPointer_) } return a_; } /// Read the value immediately below the given stack pointer. Equivalent to /// calling `pop` and discarding the `stackPointerAfter_` value, so may be /// less gas than setting and discarding a value. /// @param stackPointer_ The stack pointer to read below. /// @return a_ The value that was read. function peek(StackPointer stackPointer_) internal pure returns (uint256) { uint256 a_; assembly ("memory-safe") { a_ := mload(sub(stackPointer_, 0x20)) } return a_; } /// Reads 2 values below the given stack pointer. /// The following statements are equivalent but A may use gas if the /// compiler fails to inline some function calls. /// A: /// ``` /// (uint256 a_, uint256 b_) = stackPointer_.peek2(); /// ``` /// B: /// ``` /// uint256 b_; /// (stackPointer_, b_) = stackPointer_.pop(); /// uint256 a_ = stackPointer_.peek(); /// ``` /// @param stackPointer_ The stack top to peek below. function peek2( StackPointer stackPointer_ ) internal pure returns (uint256, uint256) { uint256 a_; uint256 b_; assembly ("memory-safe") { a_ := mload(sub(stackPointer_, 0x40)) b_ := mload(sub(stackPointer_, 0x20)) } return (a_, b_); } /// Read the value immediately below the given stack pointer and return the /// stack pointer that points to the value that was read alongside the value. /// The following are equivalent but A may be cheaper if the compiler /// fails to inline some function calls: /// A: /// ``` /// uint256 a_; /// (stackPointer_, a_) = stackPointer_.pop(); /// ``` /// B: /// ``` /// stackPointer_ = stackPointer_.down(); /// uint256 a_ = stackPointer_.peekUp(); /// ``` /// @param stackPointer_ The stack pointer to read below. /// @return stackPointerAfter_ Points to the value that was read. /// @return a_ The value that was read. function pop( StackPointer stackPointer_ ) internal pure returns (StackPointer, uint256) { StackPointer stackPointerAfter_; uint256 a_; assembly ("memory-safe") { stackPointerAfter_ := sub(stackPointer_, 0x20) a_ := mload(stackPointerAfter_) } return (stackPointerAfter_, a_); } /// Given two stack pointers that bound a stack build an array of all values /// above the given sentinel value. The sentinel will be _replaced_ by the /// length of the array, allowing for efficient construction of a valid /// `uint256[]` without additional allocation or copying in memory. As the /// returned value is a `uint256[]` it can be treated as a substack and the /// same (or different) sentinel can be consumed many times to build many /// arrays from the main stack. /// /// As the sentinel is mutated in place into a length it is NOT safe to call /// this in a context where the stack is expected to be immutable. /// /// The sentinel MUST be chosen to have a negligible chance of colliding with /// a real value in the array, otherwise an intended array item will be /// interpreted as a sentinel and the array will be split into two slices. /// /// If the sentinel is absent in the stack this WILL REVERT. The intent is /// to represent dynamic length arrays without forcing expression authors to /// calculate lengths on the stack. If the expression author wants to model /// an empty/optional/absent value they MAY provided a sentinel for a zero /// length array and the calling contract SHOULD handle this. /// /// @param stackTop_ Pointer to the top of the stack. /// @param stackBottom_ Pointer to the bottom of the stack. /// @param sentinel_ The value to expect as the sentinel. MUST be present in /// the stack or `consumeSentinel` will revert. MUST NOT collide with valid /// stack items (or be cryptographically improbable to do so). /// @param stepSize_ Number of items to move over in the array per loop /// iteration. If the array has a known multiple of items it can be more /// efficient to find a sentinel moving in N-item increments rather than /// reading every item individually. function consumeSentinel( StackPointer stackTop_, StackPointer stackBottom_, uint256 sentinel_, uint256 stepSize_ ) internal pure returns (StackPointer, uint256[] memory) { uint256[] memory array_; assembly ("memory-safe") { // Underflow is not allowed and pointing at position 0 in memory is // corrupt behaviour anyway. if iszero(stackBottom_) { revert(0, 0) } let sentinelLocation_ := 0 let length_ := 0 let step_ := mul(stepSize_, 0x20) for { stackTop_ := sub(stackTop_, 0x20) let end_ := sub(stackBottom_, 0x20) } gt(stackTop_, end_) { stackTop_ := sub(stackTop_, step_) length_ := add(length_, stepSize_) } { if eq(sentinel_, mload(stackTop_)) { sentinelLocation_ := stackTop_ break } } // Sentinel MUST exist in the stack if consumer expects it to there. if iszero(sentinelLocation_) { revert(0, 0) } mstore(sentinelLocation_, length_) array_ := sentinelLocation_ } return (stackTop_, array_); } /// Abstraction over `consumeSentinel` to build an array of solidity structs. /// Solidity won't exactly allow this due to its type system not supporting /// generics, so instead we return an array of references to struct data that /// can be assigned/cast to an array of structs easily with assembly. This /// is NOT intended to be a general purpose workhorse for this task, only /// structs of pointers to `uint256[]` values are supported. /// /// ``` /// struct Foo { /// uint256[] a; /// uint256[] b; /// } /// /// (StackPointer stackPointer_, uint256[] memory refs_) = consumeStructs(...); /// Foo[] memory foo_; /// assembly ("memory-safe") { /// mstore(foo_, refs_) /// } /// ``` /// /// @param stackTop_ The top of the stack as per `consumeSentinel`. /// @param stackBottom_ The bottom of the stack as per `consumeSentinel`. /// @param sentinel_ The sentinel as per `consumeSentinel`. /// @param structSize_ The number of `uint256[]` fields on the struct. function consumeStructs( StackPointer stackTop_, StackPointer stackBottom_, uint256 sentinel_, uint256 structSize_ ) internal pure returns (StackPointer, uint256[] memory) { (StackPointer stackTopAfter_, uint256[] memory tempArray_) = stackTop_ .consumeSentinel(stackBottom_, sentinel_, structSize_); uint256 structsLength_ = tempArray_.length / structSize_; uint256[] memory refs_ = new uint256[](structsLength_); assembly ("memory-safe") { for { let refCursor_ := add(refs_, 0x20) let refEnd_ := add(refCursor_, mul(mload(refs_), 0x20)) let tempCursor_ := add(tempArray_, 0x20) let tempStepSize_ := mul(structSize_, 0x20) } lt(refCursor_, refEnd_) { refCursor_ := add(refCursor_, 0x20) tempCursor_ := add(tempCursor_, tempStepSize_) } { mstore(refCursor_, tempCursor_) } } return (stackTopAfter_, refs_); } /// Write a value at the stack pointer. Typically only useful as intermediate /// logic within some opcode etc. as the value will be treated as an out of /// bounds for future reads unless the stack top after the opcode logic is /// above the pointer. /// @param stackPointer_ The stack top to write the value at. /// @param a_ The value to write. function set(StackPointer stackPointer_, uint256 a_) internal pure { assembly ("memory-safe") { mstore(stackPointer_, a_) } } /// Store a `uint256` at the stack pointer and return the stack pointer /// above the written value. The following statements are equivalent in /// functionality but A may be less gas if the compiler fails to inline /// some function calls. /// A: /// ``` /// stackPointer_ = stackPointer_.push(a_); /// ``` /// B: /// ``` /// stackPointer_.set(a_); /// stackPointer_ = stackPointer_.up(); /// ``` /// @param stackPointer_ The stack pointer to write at. /// @param a_ The value to write. /// @return The stack pointer above where `a_` was written to. function push( StackPointer stackPointer_, uint256 a_ ) internal pure returns (StackPointer) { assembly ("memory-safe") { mstore(stackPointer_, a_) stackPointer_ := add(stackPointer_, 0x20) } return stackPointer_; } /// Store a `uint256[]` at the stack pointer and return the stack pointer /// above the written values. The length of the array is NOT written to the /// stack, ONLY the array values are copied to the stack. The following /// statements are equivalent in functionality but A may be less gas if the /// compiler fails to inline some function calls. /// A: /// ``` /// stackPointer_ = stackPointer_.push(array_); /// ``` /// B: /// ``` /// unchecked { /// for (uint256 i_ = 0; i_ < array_.length; i_++) { /// stackPointer_ = stackPointer_.push(array_[i_]); /// } /// } /// ``` /// @param stackPointer_ The stack pointer to write at. /// @param array_ The array of values to write. /// @return The stack pointer above the array. function push( StackPointer stackPointer_, uint256[] memory array_ ) internal pure returns (StackPointer) { array_.unsafeCopyValuesTo(StackPointer.unwrap(stackPointer_)); return stackPointer_.up(array_.length); } /// Store a `uint256[]` at the stack pointer and return the stack pointer /// above the written values. The length of the array IS written to the /// stack. /// @param stackPointer_ The stack pointer to write at. /// @param array_ The array of values and length to write. /// @return The stack pointer above the array. function pushWithLength( StackPointer stackPointer_, uint256[] memory array_ ) internal pure returns (StackPointer) { return stackPointer_.push(array_.length).push(array_); } /// Store `bytes` at the stack pointer and return the stack pointer above /// the written bytes. The length of the bytes is NOT written to the stack, /// ONLY the bytes are written. As `bytes` may be of arbitrary length, i.e. /// it MAY NOT be a multiple of 32, the push is unaligned. The caller MUST /// ensure that this is safe in context of subsequent reads and writes. /// @param stackPointer_ The stack top to write at. /// @param bytes_ The bytes to write at the stack top. /// @return The stack top above the written bytes. function unalignedPush( StackPointer stackPointer_, bytes memory bytes_ ) internal pure returns (StackPointer) { LibMemory.unsafeCopyBytesTo( Pointer.wrap(StackPointer.unwrap(bytes_.asStackPointer().up())), Pointer.wrap(StackPointer.unwrap(stackPointer_)), bytes_.length ); return stackPointer_.upBytes(bytes_.length); } /// Store `bytes` at the stack pointer and return the stack top above the /// written bytes. The length of the bytes IS written to the stack in /// addition to the bytes. As `bytes` may be of arbitrary length, i.e. it /// MAY NOT be a multiple of 32, the push is unaligned. The caller MUST /// ensure that this is safe in context of subsequent reads and writes. /// @param stackPointer_ The stack pointer to write at. /// @param bytes_ The bytes to write with their length at the stack pointer. /// @return The stack pointer above the written bytes. function unalignedPushWithLength( StackPointer stackPointer_, bytes memory bytes_ ) internal pure returns (StackPointer) { return stackPointer_.push(bytes_.length).unalignedPush(bytes_); } /// Store 8x `uint256` at the stack pointer and return the stack pointer /// above the written value. The following statements are equivalent in /// functionality but A may be cheaper if the compiler fails to /// inline some function calls. /// A: /// ``` /// stackPointer_ = stackPointer_.push(a_, b_, c_, d_, e_, f_, g_, h_); /// ``` /// B: /// ``` /// stackPointer_ = stackPointer_ /// .push(a_) /// .push(b_) /// .push(c_) /// .push(d_) /// .push(e_) /// .push(f_) /// .push(g_) /// .push(h_); /// @param stackPointer_ The stack pointer to write at. /// @param a_ The first value to write. /// @param b_ The second value to write. /// @param c_ The third value to write. /// @param d_ The fourth value to write. /// @param e_ The fifth value to write. /// @param f_ The sixth value to write. /// @param g_ The seventh value to write. /// @param h_ The eighth value to write. /// @return The stack pointer above where `h_` was written. function push( StackPointer stackPointer_, uint256 a_, uint256 b_, uint256 c_, uint256 d_, uint256 e_, uint256 f_, uint256 g_, uint256 h_ ) internal pure returns (StackPointer) { assembly ("memory-safe") { mstore(stackPointer_, a_) mstore(add(stackPointer_, 0x20), b_) mstore(add(stackPointer_, 0x40), c_) mstore(add(stackPointer_, 0x60), d_) mstore(add(stackPointer_, 0x80), e_) mstore(add(stackPointer_, 0xA0), f_) mstore(add(stackPointer_, 0xC0), g_) mstore(add(stackPointer_, 0xE0), h_) stackPointer_ := add(stackPointer_, 0x100) } return stackPointer_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @return The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(uint256) internal view returns (uint256) fn_ ) internal view returns (StackPointer) { uint256 a_; uint256 location_; assembly ("memory-safe") { location_ := sub(stackTop_, 0x20) a_ := mload(location_) } a_ = fn_(a_); assembly ("memory-safe") { mstore(location_, a_) } return stackTop_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @return The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(Operand, uint256) internal view returns (uint256) fn_, Operand operand_ ) internal view returns (StackPointer) { uint256 a_; uint256 location_; assembly ("memory-safe") { location_ := sub(stackTop_, 0x20) a_ := mload(location_) } a_ = fn_(operand_, a_); assembly ("memory-safe") { mstore(location_, a_) } return stackTop_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @return The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(uint256, uint256) internal view returns (uint256) fn_ ) internal view returns (StackPointer) { uint256 a_; uint256 b_; uint256 location_; assembly ("memory-safe") { stackTop_ := sub(stackTop_, 0x20) location_ := sub(stackTop_, 0x20) a_ := mload(location_) b_ := mload(stackTop_) } a_ = fn_(a_, b_); assembly ("memory-safe") { mstore(location_, a_) } return stackTop_; } /// Reduce a function N times, reading and writing inputs and the accumulated /// result on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @param n_ The number of times to apply fn_ to accumulate a final result. /// @return stackTopAfter_ The new stack top above the outputs of fn_. function applyFnN( StackPointer stackTop_, function(uint256, uint256) internal view returns (uint256) fn_, uint256 n_ ) internal view returns (StackPointer) { unchecked { uint256 bottom_; uint256 cursor_; uint256 a_; uint256 b_; StackPointer stackTopAfter_; assembly ("memory-safe") { bottom_ := sub(stackTop_, mul(n_, 0x20)) a_ := mload(bottom_) stackTopAfter_ := add(bottom_, 0x20) cursor_ := stackTopAfter_ } while (cursor_ < StackPointer.unwrap(stackTop_)) { assembly ("memory-safe") { b_ := mload(cursor_) } a_ = fn_(a_, b_); cursor_ += 0x20; } assembly ("memory-safe") { mstore(bottom_, a_) } return stackTopAfter_; } } /// Reduce a function N times, reading and writing inputs and the accumulated /// result on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @param n_ The number of times to apply fn_ to accumulate a final result. /// @return stackTopAfter_ The new stack top above the outputs of fn_. function applyFnN( StackPointer stackTop_, function(uint256) internal view fn_, uint256 n_ ) internal view returns (StackPointer) { uint256 cursor_; uint256 a_; StackPointer stackTopAfter_; assembly ("memory-safe") { stackTopAfter_ := sub(stackTop_, mul(n_, 0x20)) cursor_ := stackTopAfter_ } while (cursor_ < StackPointer.unwrap(stackTop_)) { assembly ("memory-safe") { a_ := mload(cursor_) cursor_ := add(cursor_, 0x20) } fn_(a_); } return stackTopAfter_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @return The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(uint256, uint256, uint256) internal view returns (uint256) fn_ ) internal view returns (StackPointer) { uint256 a_; uint256 b_; uint256 c_; uint256 location_; assembly ("memory-safe") { stackTop_ := sub(stackTop_, 0x40) location_ := sub(stackTop_, 0x20) a_ := mload(location_) b_ := mload(stackTop_) c_ := mload(add(stackTop_, 0x20)) } a_ = fn_(a_, b_, c_); assembly ("memory-safe") { mstore(location_, a_) } return stackTop_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @return The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(uint256, uint256, uint256, uint256) internal view returns (uint256) fn_ ) internal view returns (StackPointer) { uint256 a_; uint256 b_; uint256 c_; uint256 d_; uint256 location_; assembly ("memory-safe") { stackTop_ := sub(stackTop_, 0x60) location_ := sub(stackTop_, 0x20) a_ := mload(location_) b_ := mload(stackTop_) c_ := mload(add(stackTop_, 0x20)) d_ := mload(add(stackTop_, 0x40)) } a_ = fn_(a_, b_, c_, d_); assembly ("memory-safe") { mstore(location_, a_) } return stackTop_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @param operand_ Operand is passed from the source instead of the stack. /// @return The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(Operand, uint256, uint256) internal view returns (uint256) fn_, Operand operand_ ) internal view returns (StackPointer) { uint256 a_; uint256 b_; uint256 location_; assembly ("memory-safe") { stackTop_ := sub(stackTop_, 0x20) location_ := sub(stackTop_, 0x20) a_ := mload(location_) b_ := mload(stackTop_) } a_ = fn_(operand_, a_, b_); assembly ("memory-safe") { mstore(location_, a_) } return stackTop_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @param length_ The length of the array to pass to fn_ from the stack. /// @return stackTopAfter_ The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(uint256[] memory) internal view returns (uint256) fn_, uint256 length_ ) internal view returns (StackPointer) { (uint256 a_, uint256[] memory tail_) = stackTop_.list(length_); uint256 b_ = fn_(tail_); return tail_.asStackPointer().push(a_).push(b_); } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @param length_ The length of the array to pass to fn_ from the stack. /// @return stackTopAfter_ The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(uint256, uint256, uint256[] memory) internal view returns (uint256) fn_, uint256 length_ ) internal view returns (StackPointer) { (uint256 b_, uint256[] memory tail_) = stackTop_.list(length_); StackPointer stackTopAfter_ = tail_.asStackPointer(); (StackPointer location_, uint256 a_) = stackTopAfter_.pop(); location_.set(fn_(a_, b_, tail_)); return stackTopAfter_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @param length_ The length of the array to pass to fn_ from the stack. /// @return The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(uint256, uint256, uint256, uint256[] memory) internal view returns (uint256) fn_, uint256 length_ ) internal view returns (StackPointer) { (uint256 c_, uint256[] memory tail_) = stackTop_.list(length_); (StackPointer stackTopAfter_, uint256 b_) = tail_ .asStackPointer() .pop(); uint256 a_ = stackTopAfter_.peek(); stackTopAfter_.down().set(fn_(a_, b_, c_, tail_)); return stackTopAfter_; } /// Execute a function, reading and writing inputs and outputs on the stack. /// The caller MUST ensure this does not result in unsafe reads and writes. /// @param stackTop_ The stack top to read and write to. /// @param fn_ The function to run on the stack. /// @param length_ The length of the arrays to pass to fn_ from the stack. /// @return The new stack top above the outputs of fn_. function applyFn( StackPointer stackTop_, function(uint256, uint256[] memory, uint256[] memory) internal view returns (uint256[] memory) fn_, uint256 length_ ) internal view returns (StackPointer) { StackPointer csStart_ = stackTop_.down(length_); uint256[] memory cs_ = LibUint256Array.copyToNewUint256Array( StackPointer.unwrap(csStart_), length_ ); (uint256 a_, uint256[] memory bs_) = csStart_.list(length_); uint256[] memory results_ = fn_(a_, bs_, cs_); if (results_.length != length_) { revert UnexpectedResultLength(length_, results_.length); } StackPointer bottom_ = bs_.asStackPointer(); LibUint256Array.unsafeCopyValuesTo( results_, StackPointer.unwrap(bottom_) ); return bottom_.up(length_); } /// Returns `length_` values from the stack as an array without allocating /// new memory. As arrays always start with their length, this requires /// writing the length value to the stack below the array values. The value /// that is overwritten in the process is also returned so that data is not /// lost. For example, imagine a stack `[ A B C D ]` and we list 2 values. /// This will write the stack to look like `[ A 2 C D ]` and return both `B` /// and a pointer to `2` represented as a `uint256[]`. /// The returned array is ONLY valid for as long as the stack DOES NOT move /// back into its memory. As soon as the stack moves up again and writes into /// the array it will be corrupt. The caller MUST ensure that it does not /// read from the returned array after it has been corrupted by subsequent /// stack writes. /// @param stackPointer_ The stack pointer to read the values below into an /// array. /// @param length_ The number of values to include in the returned array. /// @return head_ The value that was overwritten with the length. /// @return tail_ The array constructed from the stack memory. function list( StackPointer stackPointer_, uint256 length_ ) internal pure returns (uint256, uint256[] memory) { uint256 head_; uint256[] memory tail_; assembly ("memory-safe") { tail_ := sub(stackPointer_, add(0x20, mul(length_, 0x20))) head_ := mload(tail_) mstore(tail_, length_) } return (head_, tail_); } /// Cast a `uint256[]` array to a stack pointer. The stack pointer will /// point to the length of the array, NOT its first value. /// @param array_ The array to cast to a stack pointer. /// @return stackPointer_ The stack pointer that points to the length of the /// array. function asStackPointer( uint256[] memory array_ ) internal pure returns (StackPointer) { StackPointer stackPointer_; assembly ("memory-safe") { stackPointer_ := array_ } return stackPointer_; } /// Cast a stack pointer to an array. The value immediately above the stack /// pointer will be treated as the length of the array, so the proceeding /// length values will be the items of the array. The caller MUST ensure the /// values above the stack position constitute a valid array. The returned /// array will be corrupt if/when the stack subsequently moves into it and /// writes to those memory locations. The caller MUST ensure that it does /// NOT read from the returned array after the stack writes over it. /// @param stackPointer_ The stack pointer that will be cast to an array. /// @return array_ The array above the stack pointer. function asUint256Array( StackPointer stackPointer_ ) internal pure returns (uint256[] memory) { uint256[] memory array_; assembly ("memory-safe") { array_ := stackPointer_ } return array_; } /// Cast a stack position to bytes. The value immediately above the stack /// position will be treated as the length of the `bytes`, so the proceeding /// length bytes will be the data of the `bytes`. The caller MUST ensure the /// length and bytes above the stack top constitute valid `bytes` data. The /// returned `bytes` will be corrupt if/when the stack subsequently moves /// into it and writes to those memory locations. The caller MUST ensure // that it does NOT read from the returned bytes after the stack writes over /// it. /// @param stackPointer_ The stack pointer that will be cast to bytes. /// @return bytes_ The bytes above the stack top. function asBytes( StackPointer stackPointer_ ) internal pure returns (bytes memory) { bytes memory bytes_; assembly ("memory-safe") { bytes_ := stackPointer_ } return bytes_; } /// Cast a `uint256[]` array to a stack pointer after its length. The stack /// pointer will point to the first item of the array, NOT its length. /// @param array_ The array to cast to a stack pointer. /// @return stackPointer_ The stack pointer that points to the first item of /// the array. function asStackPointerUp( uint256[] memory array_ ) internal pure returns (StackPointer) { StackPointer stackPointer_; assembly ("memory-safe") { stackPointer_ := add(array_, 0x20) } return stackPointer_; } /// Cast a `uint256[]` array to a stack pointer after its items. The stack /// pointer will point after the last item of the array. It is out of bounds /// to read above the returned pointer. This can be interpreted as the stack /// top assuming the entire given array is a valid stack. /// @param array_ The array to cast to a stack pointer. /// @return stackPointer_ The stack pointer that points after the last item /// of the array. function asStackPointerAfter( uint256[] memory array_ ) internal pure returns (StackPointer) { StackPointer stackPointer_; assembly ("memory-safe") { stackPointer_ := add(array_, add(0x20, mul(mload(array_), 0x20))) } return stackPointer_; } /// Cast `bytes` to a stack pointer. The stack pointer will point to the /// length of the `bytes`, NOT the first byte. /// @param bytes_ The `bytes` to cast to a stack pointer. /// @return stackPointer_ The stack top that points to the length of the /// bytes. function asStackPointer( bytes memory bytes_ ) internal pure returns (StackPointer) { StackPointer stackPointer_; assembly ("memory-safe") { stackPointer_ := bytes_ } return stackPointer_; } /// Returns the stack pointer 32 bytes above/past the given stack pointer. /// @param stackPointer_ The stack pointer at the starting position. /// @return The stack pointer 32 bytes above the input stack pointer. function up( StackPointer stackPointer_ ) internal pure returns (StackPointer) { unchecked { return StackPointer.wrap(StackPointer.unwrap(stackPointer_) + 0x20); } } /// Returns the stack pointer `n_ * 32` bytes above/past the given stack /// pointer. /// @param stackPointer_ The stack pointer at the starting position. /// @param n_ The multiplier on the stack movement. MAY be zero. /// @return The stack pointer `n_ * 32` bytes above/past the input stack /// pointer. function up( StackPointer stackPointer_, uint256 n_ ) internal pure returns (StackPointer) { unchecked { return StackPointer.wrap( StackPointer.unwrap(stackPointer_) + 0x20 * n_ ); } } /// Returns the stack pointer `n_` bytes above/past the given stack pointer. /// The returned stack pointer MAY NOT be aligned with the given stack /// pointer for subsequent 32 byte reads and writes. The caller MUST ensure /// that it is safe to read and write data relative to the returned stack /// pointer. /// @param stackPointer_ The stack pointer at the starting position. /// @param n_ The number of bytes to move. /// @return The stack pointer `n_` bytes above/past the given stack pointer. function upBytes( StackPointer stackPointer_, uint256 n_ ) internal pure returns (StackPointer) { unchecked { return StackPointer.wrap(StackPointer.unwrap(stackPointer_) + n_); } } /// Returns the stack pointer 32 bytes below/before the given stack pointer. /// @param stackPointer_ The stack pointer at the starting position. /// @return The stack pointer 32 bytes below/before the given stack pointer. function down( StackPointer stackPointer_ ) internal pure returns (StackPointer) { unchecked { return StackPointer.wrap(StackPointer.unwrap(stackPointer_) - 0x20); } } /// Returns the stack pointer `n_ * 32` bytes below/before the given stack /// pointer. /// @param stackPointer_ The stack pointer at the starting position. /// @param n_ The multiplier on the movement. /// @return The stack pointer `n_ * 32` bytes below/before the given stack /// pointer. function down( StackPointer stackPointer_, uint256 n_ ) internal pure returns (StackPointer) { unchecked { return StackPointer.wrap( StackPointer.unwrap(stackPointer_) - 0x20 * n_ ); } } /// Convert two stack pointer values to a single stack index. A stack index /// is the distance in 32 byte increments between two stack pointers. The /// calculations assumes the two stack pointers are aligned. The caller MUST /// ensure the alignment of both values. The calculation is unchecked and MAY /// underflow. The caller MUST ensure that the stack top is always above the /// stack bottom. /// @param stackBottom_ The lower of the two values. /// @param stackTop_ The higher of the two values. /// @return The stack index as 32 byte distance between the top and bottom. function toIndex( StackPointer stackBottom_, StackPointer stackTop_ ) internal pure returns (uint256) { unchecked { return (StackPointer.unwrap(stackTop_) - StackPointer.unwrap(stackBottom_)) / 0x20; } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; /// Thrown if a truncated length is longer than the array being truncated. It is /// not possible to truncate something and increase its length as the memory /// region after the array MAY be allocated for something else already. error OutOfBoundsTruncate(uint256 arrayLength, uint256 truncatedLength); /// @title Uint256Array /// @notice Things we want to do carefully and efficiently with uint256 arrays /// that Solidity doesn't give us native tools for. library LibUint256Array { using LibUint256Array for uint256[]; /// Building arrays from literal components is a common task that introduces /// boilerplate that is either inefficient or error prone. /// @param a_ a single integer to build an array around. /// @return the newly allocated array including a_ as a single item. function arrayFrom(uint256 a_) internal pure returns (uint256[] memory) { uint256[] memory array_ = new uint256[](1); assembly ("memory-safe") { mstore(add(array_, 0x20), a_) } return array_; } /// Building arrays from literal components is a common task that introduces /// boilerplate that is either inefficient or error prone. /// @param a_ the first integer to build an array around. /// @param b_ the second integer to build an array around. /// @return the newly allocated array including a_ and b_ as the only items. function arrayFrom( uint256 a_, uint256 b_ ) internal pure returns (uint256[] memory) { uint256[] memory array_ = new uint256[](2); assembly ("memory-safe") { mstore(add(array_, 0x20), a_) mstore(add(array_, 0x40), b_) } return array_; } /// Building arrays from literal components is a common task that introduces /// boilerplate that is either inefficient or error prone. /// @param a_ the first integer to build an array around. /// @param b_ the second integer to build an array around. /// @param c_ the third integer to build an array around. /// @return the newly allocated array including a_, b_ and c_ as the only /// items. function arrayFrom( uint256 a_, uint256 b_, uint256 c_ ) internal pure returns (uint256[] memory) { uint256[] memory array_ = new uint256[](3); assembly ("memory-safe") { mstore(add(array_, 0x20), a_) mstore(add(array_, 0x40), b_) mstore(add(array_, 0x60), c_) } return array_; } /// Building arrays from literal components is a common task that introduces /// boilerplate that is either inefficient or error prone. /// @param a_ the first integer to build an array around. /// @param b_ the second integer to build an array around. /// @param c_ the third integer to build an array around. /// @param d_ the fourth integer to build an array around. /// @return the newly allocated array including a_, b_, c_ and d_ as the only /// items. function arrayFrom( uint256 a_, uint256 b_, uint256 c_, uint256 d_ ) internal pure returns (uint256[] memory) { uint256[] memory array_ = new uint256[](4); assembly ("memory-safe") { mstore(add(array_, 0x20), a_) mstore(add(array_, 0x40), b_) mstore(add(array_, 0x60), c_) mstore(add(array_, 0x80), d_) } return array_; } /// Building arrays from literal components is a common task that introduces /// boilerplate that is either inefficient or error prone. /// @param a_ the first integer to build an array around. /// @param b_ the second integer to build an array around. /// @param c_ the third integer to build an array around. /// @param d_ the fourth integer to build an array around. /// @param e_ the fifth integer to build an array around. /// @return the newly allocated array including a_, b_, c_, d_ and e_ as the /// only items. function arrayFrom( uint256 a_, uint256 b_, uint256 c_, uint256 d_, uint256 e_ ) internal pure returns (uint256[] memory) { uint256[] memory array_ = new uint256[](5); assembly ("memory-safe") { mstore(add(array_, 0x20), a_) mstore(add(array_, 0x40), b_) mstore(add(array_, 0x60), c_) mstore(add(array_, 0x80), d_) mstore(add(array_, 0xA0), e_) } return array_; } /// Building arrays from literal components is a common task that introduces /// boilerplate that is either inefficient or error prone. /// @param a_ the first integer to build an array around. /// @param b_ the second integer to build an array around. /// @param c_ the third integer to build an array around. /// @param d_ the fourth integer to build an array around. /// @param e_ the fifth integer to build an array around. /// @param f_ the sixth integer to build an array around. /// @return the newly allocated array including a_, b_, c_, d_, e_ and f_ as /// the only items. function arrayFrom( uint256 a_, uint256 b_, uint256 c_, uint256 d_, uint256 e_, uint256 f_ ) internal pure returns (uint256[] memory) { uint256[] memory array_ = new uint256[](6); assembly ("memory-safe") { mstore(add(array_, 0x20), a_) mstore(add(array_, 0x40), b_) mstore(add(array_, 0x60), c_) mstore(add(array_, 0x80), d_) mstore(add(array_, 0xA0), e_) mstore(add(array_, 0xC0), f_) } return array_; } /// Building arrays from literal components is a common task that introduces /// boilerplate that is either inefficient or error prone. /// @param a_ The head of the new array. /// @param tail_ The tail of the new array. /// @return The new array. function arrayFrom( uint256 a_, uint256[] memory tail_ ) internal pure returns (uint256[] memory) { uint256[] memory array_ = new uint256[](1); assembly ("memory-safe") { mstore(add(array_, 0x20), a_) } array_.extend(tail_); return array_; } /// Building arrays from literal components is a common task that introduces /// boilerplate that is either inefficient or error prone. /// @param a_ The first item of the new array. /// @param b_ The second item of the new array. /// @param tail_ The tail of the new array. /// @return The new array. function arrayFrom( uint256 a_, uint256 b_, uint256[] memory tail_ ) internal pure returns (uint256[] memory) { uint256[] memory array_ = new uint256[](2); assembly ("memory-safe") { mstore(add(array_, 0x20), a_) mstore(add(array_, 0x40), b_) } array_.extend(tail_); return array_; } /// 2-dimensional analogue of `arrayFrom`. Takes a 1-dimensional array and /// coerces it to a 2-dimensional matrix where the first and only item in the /// matrix is the 1-dimensional array. /// @param a_ The 1-dimensional array to coerce. /// @return The 2-dimensional matrix containing `a_`. function matrixFrom( uint256[] memory a_ ) internal pure returns (uint256[][] memory) { uint256[][] memory matrix_ = new uint256[][](1); assembly ("memory-safe") { mstore(add(matrix_, 0x20), a_) } return matrix_; } /// Solidity provides no way to change the length of in-memory arrays but /// it also does not deallocate memory ever. It is always safe to shrink an /// array that has already been allocated, with the caveat that the /// truncated items will effectively become inaccessible regions of memory. /// That is to say, we deliberately "leak" the truncated items, but that is /// no worse than Solidity's native behaviour of leaking everything always. /// The array is MUTATED in place so there is no return value and there is /// no new allocation or copying of data either. /// @param array_ The array to truncate. /// @param newLength_ The new length of the array after truncation. function truncate( uint256[] memory array_, uint256 newLength_ ) internal pure { if (newLength_ > array_.length) { revert OutOfBoundsTruncate(array_.length, newLength_); } assembly ("memory-safe") { mstore(array_, newLength_) } } /// Extends `base_` with `extend_` by allocating additional `extend_.length` /// uints onto `base_`. Reverts if some other memory has been allocated /// after `base_` already, in which case it is NOT safe to copy inline. /// If `base_` is large this MAY be significantly more efficient than /// allocating `base_.length + extend_.length` for an entirely new array and /// copying both `base_` and `extend_` into the new array one item at a /// time in Solidity. /// The Solidity compiler MAY rearrange sibling statements in a code block /// EVEN IF THE OPTIMIZER IS DISABLED such that it becomes unsafe to use /// `extend` for memory allocated in different code blocks. It is ONLY safe /// to `extend` arrays that were allocated in the same lexical scope and you /// WILL see subtle errors that revert transactions otherwise. /// i.e. the `new` keyword MUST appear in the same code block as `extend`. /// @param base_ The base integer array that will be extended by `extend_`. /// @param extend_ The integer array that extends `base_`. function extend( uint256[] memory base_, uint256[] memory extend_ ) internal pure { uint256 freeMemoryPointer_; assembly ("memory-safe") { // Solidity stores free memory pointer at 0x40 freeMemoryPointer_ := mload(0x40) let baseLength_ := mload(base_) let extendLength_ := mload(extend_) // The freeMemoryPointer_ does NOT point to the end of `base_` so // it is NOT safe to copy `extend_` over the top of already // allocated memory. This happens whenever some memory is allocated // after `base_` is allocated but before `extend` is called. if gt( freeMemoryPointer_, add(base_, add(0x20, mul(0x20, baseLength_))) ) { revert(0, 0) } // Move the free memory pointer by the length of extend_, excluding // the length slot of extend as that will NOT be copied to `base_`. mstore(0x40, add(freeMemoryPointer_, mul(0x20, extendLength_))) // Update the length of base to be the length of base+extend. mstore(base_, add(baseLength_, extendLength_)) } unsafeCopyValuesTo(extend_, freeMemoryPointer_); } /// Copies `inputs_` to `outputCursor_` with NO attempt to check that this /// is safe to do so. The caller MUST ensure that there exists allocated /// memory at `outputCursor_` in which it is safe and appropriate to copy /// ALL `inputs_` to. Anything that was already written to memory at /// `[outputCursor_:outputCursor_+(inputs_.length * 32 bytes)]` will be /// overwritten. The length of `inputs_` is NOT copied to the output /// location, ONLY the `uint256` values of the `inputs_` array are copied. /// There is no return value as memory is modified directly. /// @param inputs_ The input array that will be copied from EXCLUDING the /// length at the start of the array in memory. /// @param outputCursor_ Location in memory that the values will be copied /// to linearly. function unsafeCopyValuesTo( uint256[] memory inputs_, uint256 outputCursor_ ) internal pure { uint256 inputCursor_; assembly ("memory-safe") { inputCursor_ := add(inputs_, 0x20) } unsafeCopyValuesTo(inputCursor_, outputCursor_, inputs_.length); } /// Copies `length_` 32 byte words from `inputCursor_` to a newly allocated /// uint256[] array with NO attempt to check that the inputs are sane. /// This function is safe in that the outputs are guaranteed to be copied /// to newly allocated memory so no existing data will be overwritten. /// This function is subtle in that the `inputCursor_` is NOT validated in /// any way so the caller MUST ensure it points to a sensible memory /// location to read (e.g. to exclude the length from input arrays etc.). /// @param inputCursor_ The start of the memory that will be copied to the /// newly allocated array. /// @param length_ Number of 32 byte words to copy starting at /// `inputCursor_` to the items of the newly allocated array. /// @return The newly allocated `uint256[]` array. function copyToNewUint256Array( uint256 inputCursor_, uint256 length_ ) internal pure returns (uint256[] memory) { uint256[] memory outputs_ = new uint256[](length_); uint256 outputCursor_; assembly ("memory-safe") { outputCursor_ := add(outputs_, 0x20) } unsafeCopyValuesTo(inputCursor_, outputCursor_, length_); return outputs_; } /// Copies `length_` uint256 values starting from `inputsCursor_` to /// `outputCursor_` with NO attempt to check that this is safe to do so. /// The caller MUST ensure that there exists allocated memory at /// `outputCursor_` in which it is safe and appropriate to copy /// `length_ * 32` bytes to. Anything that was already written to memory at /// `[outputCursor_:outputCursor_+(length_ * 32 bytes)]` will be /// overwritten. /// There is no return value as memory is modified directly. /// @param inputCursor_ The starting position in memory that data will be /// copied from. /// @param outputCursor_ The starting position in memory that data will be /// copied to. /// @param length_ The number of 32 byte (i.e. `uint256`) values that will /// be copied. function unsafeCopyValuesTo( uint256 inputCursor_, uint256 outputCursor_, uint256 length_ ) internal pure { assembly ("memory-safe") { for { let end_ := add(inputCursor_, mul(0x20, length_)) } lt(inputCursor_, end_) { inputCursor_ := add(inputCursor_, 0x20) outputCursor_ := add(outputCursor_, 0x20) } { mstore(outputCursor_, mload(inputCursor_)) } } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.16; /// Thrown when asked to truncate data to a longer length. /// @param length Actual bytes length. /// @param truncate Attempted truncation length. error TruncateError(uint256 length, uint256 truncate); type Pointer is uint256; /// @title LibMemory /// @notice Tools for working directly with memory in a Solidity compatible way. library LibMemory { /// Copy an arbitrary number of bytes from one location in memory to another. /// As we can only read/write bytes in 32 byte chunks we first have to loop /// over 32 byte values to copy then handle any unaligned remaining data. The /// remaining data will be appropriately masked with the existing data in the /// final chunk so as to not write past the desired length. Note that the /// final unaligned write will be more gas intensive than the prior aligned /// writes. The writes are completely unsafe, the caller MUST ensure that /// sufficient memory is allocated and reading/writing the requested number /// of bytes from/to the requested locations WILL NOT corrupt memory in the /// opinion of solidity or other subsequent read/write operations. /// @param source_ The starting location in memory to read from. /// @param target_ The starting location in memory to write to. /// @param length_ The number of bytes to read/write. function unsafeCopyBytesTo(Pointer source_, Pointer target_, uint256 length_) internal pure { assembly ("memory-safe") { for {} iszero(lt(length_, 0x20)) { length_ := sub(length_, 0x20) source_ := add(source_, 0x20) target_ := add(target_, 0x20) } { mstore(target_, mload(source_)) } if iszero(iszero(length_)) { //slither-disable-next-line incorrect-shift let mask_ := shr(mul(length_, 8), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) // preserve existing bytes mstore( target_, or( // input and(mload(source_), not(mask_)), and(mload(target_), mask_) ) ) } } } /// Pointer to the data of a bytes array NOT the length prefix. function dataPointer(bytes memory data_) internal pure returns (Pointer pointer_) { assembly ("memory-safe") { pointer_ := add(data_, 0x20) } } function truncate(bytes memory bytes_, uint256 length_) internal pure { if (bytes_.length < length_) { revert TruncateError(bytes_.length, length_); } assembly ("memory-safe") { mstore(bytes_, length_) } } function asBytes(Pointer pointer_) internal pure returns (bytes memory bytes_) { assembly ("memory-safe") { bytes_ := pointer_ } } function asPointer(bytes memory bytes_) internal pure returns (Pointer pointer_) { assembly ("memory-safe") { pointer_ := bytes_ } } function addBytes(Pointer pointer_, uint256 bytes_) internal pure returns (Pointer) { unchecked { return Pointer.wrap(Pointer.unwrap(pointer_) + bytes_); } } function addWords(Pointer pointer_, uint256 words_) internal pure returns (Pointer) { unchecked { return Pointer.wrap(Pointer.unwrap(pointer_) + (words_ * 0x20)); } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../interpreter/run/LibStackPointer.sol"; import "../interpreter/run/LibInterpreterState.sol"; import "../interpreter/deploy/LibIntegrityCheck.sol"; /// @title LibCast /// @notice Additional type casting logic that the Solidity compiler doesn't /// give us by default. A type cast (vs. conversion) is considered one where the /// structure is unchanged by the cast. The cast does NOT (can't) check that the /// input is a valid output, for example any integer MAY be cast to a function /// pointer but almost all integers are NOT valid function pointers. It is the /// calling context that MUST ensure the validity of the data, the cast will /// merely retype the data in place, generally without additional checks. /// As most structures in solidity have the same memory structure as a `uint256` /// or fixed/dynamic array of `uint256` there are many conversions that can be /// done with near zero or minimal overhead. library LibCast { /// Retype an integer to an opcode function pointer. /// @param u_ The integer to cast to an opcode function pointer. /// @return fn_ The opcode function pointer. function asOpFunctionPointer( uint256 u_ ) internal pure returns ( function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer) fn_ ) { assembly ("memory-safe") { fn_ := u_ } } /// Retype an array of integers to an array of opcode function pointers. /// @param us_ The array of integers to cast to an array of opcode fuction /// pointers. /// @return fns_ The array of opcode function pointers. function asOpcodeFunctionPointers( uint256[] memory us_ ) internal pure returns ( function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer)[] memory fns_ ) { assembly ("memory-safe") { fns_ := us_ } } /// Retype an integer to an integrity function pointer. /// @param u_ The integer to cast to an integrity function pointer. /// @return fn_ The integrity function pointer. function asIntegrityFunctionPointer( uint256 u_ ) internal pure returns ( function(IntegrityCheckState memory, Operand, StackPointer) internal view returns (StackPointer) fn_ ) { assembly ("memory-safe") { fn_ := u_ } } /// Retype a list of integrity check function pointers to a `uint256[]`. /// @param fns_ The list of function pointers. /// @return us_ The list of pointers as `uint256[]`. function asUint256Array( function(IntegrityCheckState memory, Operand, StackPointer) internal view returns (StackPointer)[] memory fns_ ) internal pure returns (uint256[] memory us_) { assembly ("memory-safe") { us_ := fns_ } } /// Retype a list of interpreter opcode function pointers to a `uint256[]`. /// @param fns_ The list of function pointers. /// @return us_ The list of pointers as `uint256[]`. function asUint256Array( function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer)[] memory fns_ ) internal pure returns (uint256[] memory us_) { assembly ("memory-safe") { us_ := fns_ } } /// Retype a list of `uint256[]` to `address[]`. /// @param us_ The list of integers to cast to addresses. /// @return addresses_ The list of addresses cast from each integer. function asAddresses( uint256[] memory us_ ) internal pure returns (address[] memory addresses_) { assembly ("memory-safe") { addresses_ := us_ } } /// Retype a list of integers to integrity check function pointers. /// @param us_ The list of integers to use as function pointers. /// @return fns_ The list of integrity check function pointers. function asIntegrityPointers( uint256[] memory us_ ) internal pure returns ( function(IntegrityCheckState memory, Operand, StackPointer) view returns (StackPointer)[] memory fns_ ) { assembly ("memory-safe") { fns_ := us_ } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../run/LibStackPointer.sol"; import {MathUpgradeable as Math} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import "./IExpressionDeployerV1.sol"; import "../run/IInterpreterV1.sol"; /// @dev The virtual stack pointers are never read or written so don't need to /// point to a real location in memory. We only care that the stack never moves /// below its starting point at the stack bottom. For the virtual stack used by /// the integrity check we can start it in the middle of the `uint256` range and /// achieve something analogous to signed integers with unsigned integer types. StackPointer constant INITIAL_STACK_BOTTOM = StackPointer.wrap( type(uint256).max / 2 ); /// It is a misconfiguration to set the initial stack bottom to zero or some /// small value as this trivially exposes the integrity check to potential /// underflow issues that are gas intensive to repeatedly guard against on every /// pop. The initial stack bottom for an `IntegrityCheckState` should be /// `INITIAL_STACK_BOTTOM` to safely avoid the need for underflow checks due to /// pops and pushes. error MinStackBottom(); /// The virtual stack top has underflowed the stack highwater (or zero) during an /// integrity check. The highwater will initially be the stack bottom but MAY /// move higher due to certain operations such as placing multiple outputs on the /// stack or copying from a stack position. The highwater prevents subsequent /// popping of values that are considered immutable. /// @param stackHighwaterIndex Index of the stack highwater at the moment of /// underflow. /// @param stackTopIndex Index of the stack top at the moment of underflow. error StackPopUnderflow(uint256 stackHighwaterIndex, uint256 stackTopIndex); /// The final stack produced by some source did not hit the minimum required for /// its calling context. /// @param minStackOutputs The required minimum stack height. /// @param actualStackOutputs The final stack height after evaluating a source. /// Will be less than the min stack outputs if this error is thrown. error MinFinalStack(uint256 minStackOutputs, uint256 actualStackOutputs); /// Running an integrity check is a stateful operation. As well as the basic /// configuration of what is being checked such as the sources and size of the /// constants, the current and maximum stack height is being recomputed on every /// checked opcode. The stack is virtual during the integrity check so whatever /// the `StackPointer` values are during the check, it's always undefined /// behaviour to actually try to read/write to them. /// /// @param sources All the sources of the expression are provided to the /// integrity check as any entrypoint and non-entrypoint can `call` into some /// other source at any time, provided the overall inputs and outputs to the /// stack are valid. /// @param constantsLength The integrity check assumes the existence of some /// opcode that will read from a predefined list of constants. Technically this /// opcode MAY NOT exist in some interpreter but it seems highly likely to be /// included in most setups. The integrity check only needs the length of the /// constants array to check for out of bounds reads, which allows runtime /// behaviour to read without additional gas for OOB index checks. /// @param stackBottom Pointer to the bottom of the virtual stack that the /// integrity check uses to simulate a real eval. /// @param stackMaxTop Pointer to the maximum height the virtual stack has /// reached during the integrity check. The current virtual stack height will /// be handled separately to the state during the check. /// @param integrityFunctionPointers We pass an array of all the function /// pointers to per-opcode integrity checks around with the state to facilitate /// simple recursive integrity checking. struct IntegrityCheckState { // Sources in zeroth position as we read from it in assembly without paying // gas to calculate offsets. bytes[] sources; uint256 constantsLength; StackPointer stackBottom; StackPointer stackHighwater; StackPointer stackMaxTop; function(IntegrityCheckState memory, Operand, StackPointer) view returns (StackPointer)[] integrityFunctionPointers; } /// @title LibIntegrityCheck /// @notice "Dry run" versions of the key logic from `LibStackPointer` that /// allows us to simulate a virtual stack based on the Solidity type system /// itself. The core loop of an integrity check is to dispatch an integrity-only /// version of a runtime opcode that then uses `LibIntegrityCheck` to apply a /// function that simulates a stack movement. The simulated stack movement will /// move a pointer to memory in the same way as a real pop/push would at runtime /// but without any associated logic or even allocating and writing data in /// memory on the other side of the pointer. Every pop is checked for out of /// bounds reads, even if it is an intermediate pop within the logic of a single /// opcode. The _gross_ stack movement is just as important as the net movement. /// For example, consider a simple ERC20 total supply read. The _net_ movement /// of a total supply read is 0, it pops the token address then pushes the total /// supply. However the _gross_ movement is first -1 then +1, so we have to guard /// against the -1 underflowing while reading the token address _during_ the /// simulated opcode dispatch. In general this can be subtle, complex and error /// prone, which is why `LibIntegrityCheck` and `LibStackPointer` take function /// signatures as arguments, so that the overloading mechanism in Solidity itself /// enforces correct pop/push calculations for every opcode. library LibIntegrityCheck { using LibIntegrityCheck for IntegrityCheckState; using LibStackPointer for StackPointer; using Math for uint256; function newState( bytes[] memory sources_, uint256[] memory constants_, function(IntegrityCheckState memory, Operand, StackPointer) view returns (StackPointer)[] memory integrityFns_ ) internal pure returns (IntegrityCheckState memory) { return IntegrityCheckState( sources_, constants_.length, INITIAL_STACK_BOTTOM, // Highwater starts underneath stack bottom as it errors on an // greater than _or equal to_ check. INITIAL_STACK_BOTTOM.down(), INITIAL_STACK_BOTTOM, integrityFns_ ); } /// If the given stack pointer is above the current state of the max stack /// top, the max stack top will be moved to the stack pointer. /// i.e. this works like `stackMaxTop = stackMaxTop.max(stackPointer_)` but /// with the type unwrapping boilerplate included for convenience. /// @param integrityCheckState_ The state of the current integrity check /// including the current max stack top. /// @param stackPointer_ The stack pointer to compare and potentially swap /// the max stack top for. function syncStackMaxTop( IntegrityCheckState memory integrityCheckState_, StackPointer stackPointer_ ) internal pure { if ( StackPointer.unwrap(stackPointer_) > StackPointer.unwrap(integrityCheckState_.stackMaxTop) ) { integrityCheckState_.stackMaxTop = stackPointer_; } } /// The main integrity check loop. Designed so that it can be called /// recursively by the dispatched integrity opcodes to support arbitrary /// nesting of sources and substacks, loops, etc. /// If ANY of the integrity checks for ANY opcode fails the entire integrity /// check will revert. /// @param integrityCheckState_ Current state of the integrity check passed /// by reference to allow for recursive/nested integrity checking. /// @param sourceIndex_ The source to check the integrity of which can be /// either an entrypoint or a non-entrypoint source if this is a recursive /// call to `ensureIntegrity`. /// @param stackTop_ The current top of the virtual stack as a pointer. This /// can be manipulated to create effective substacks/scoped/immutable /// runtime values by restricting how the `stackTop_` can move at deploy /// time. /// @param minStackOutputs_ The minimum stack height required by the end of /// this integrity check. The caller MUST ensure that it sets this value high /// enough so that it can safely read enough values from the final stack /// without out of bounds reads. The external interface to the expression /// deployer accepts an array of minimum stack heights against entrypoints, /// but the internal checks can be recursive against non-entrypoints and each /// opcode such as `call` can build scoped stacks, etc. so here we just put /// defining the requirements back on the caller. function ensureIntegrity( IntegrityCheckState memory integrityCheckState_, SourceIndex sourceIndex_, StackPointer stackTop_, uint256 minStackOutputs_ ) internal view returns (StackPointer) { unchecked { // It's generally more efficient to ensure the stack bottom has // plenty of headroom to make underflows from pops impossible rather // than guard every single pop against underflow. if ( StackPointer.unwrap(integrityCheckState_.stackBottom) < StackPointer.unwrap(INITIAL_STACK_BOTTOM) ) { revert MinStackBottom(); } uint256 cursor_; uint256 end_; assembly ("memory-safe") { cursor_ := mload( add( mload(integrityCheckState_), add(0x20, mul(0x20, sourceIndex_)) ) ) end_ := add(cursor_, mload(cursor_)) } // Loop until complete. while (cursor_ < end_) { uint256 opcode_; Operand operand_; cursor_ += 4; assembly ("memory-safe") { let op_ := mload(cursor_) operand_ := and(op_, 0xFFFF) opcode_ := and(shr(16, op_), 0xFFFF) } // We index into the function pointers here rather than using raw // assembly to ensure that any opcodes that we don't have a // pointer for will error as a standard Solidity OOB read. stackTop_ = integrityCheckState_.integrityFunctionPointers[ opcode_ ](integrityCheckState_, operand_, stackTop_); } uint256 finalStackOutputs_ = integrityCheckState_ .stackBottom .toIndex(stackTop_); if (minStackOutputs_ > finalStackOutputs_) { revert MinFinalStack(minStackOutputs_, finalStackOutputs_); } return stackTop_; } } /// Push a single virtual item onto the virtual stack. /// Simply moves the stack top up one and syncs the interpreter max stack /// height with it if needed. /// @param integrityCheckState_ The state of the current integrity check. /// @param stackTop_ The pointer to the virtual stack top for the current /// integrity check. /// @return The stack top after it has pushed an item. function push( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_ ) internal pure returns (StackPointer) { stackTop_ = stackTop_.up(); integrityCheckState_.syncStackMaxTop(stackTop_); return stackTop_; } /// Overloaded `push` to support `n_` pushes in a single movement. /// `n_` MAY be 0 and this is a virtual noop stack movement. /// @param integrityCheckState_ as per `push`. /// @param stackTop_ as per `push`. /// @param n_ The number of items to push to the virtual stack. function push( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, uint256 n_ ) internal pure returns (StackPointer) { stackTop_ = stackTop_.up(n_); // Any time we push more than 1 item to the stack we move the highwater // to the last item, as nested multioutput is disallowed. if (n_ > 1) { integrityCheckState_.stackHighwater = StackPointer.wrap( StackPointer.unwrap(integrityCheckState_.stackHighwater).max( StackPointer.unwrap(stackTop_.down()) ) ); } integrityCheckState_.syncStackMaxTop(stackTop_); return stackTop_; } /// As push for 0+ values. Does NOT move the highwater. This may be useful if /// the highwater is already calculated somehow by the caller. This is also /// dangerous if used incorrectly as it could allow uncaught underflows to /// creep in. function pushIgnoreHighwater( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, uint256 n_ ) internal pure returns (StackPointer) { stackTop_ = stackTop_.up(n_); integrityCheckState_.syncStackMaxTop(stackTop_); return stackTop_; } /// Move the stock top down one item then check that it hasn't underflowed /// the stack bottom. If all virtual stack movements are defined in terms /// of pops and pushes this will enforce that the gross stack movements do /// not underflow, which would lead to out of bounds stack reads at runtime. /// @param integrityCheckState_ The state of the current integrity check. /// @param stackTop_ The virtual stack top before an item is popped. /// @return The virtual stack top after the pop. function pop( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_ ) internal pure returns (StackPointer) { stackTop_ = stackTop_.down(); integrityCheckState_.popUnderflowCheck(stackTop_); return stackTop_; } /// Overloaded `pop` to support `n_` pops in a single movement. /// `n_` MAY be 0 and this is a virtual noop stack movement. /// @param integrityCheckState_ as per `pop`. /// @param stackTop_ as per `pop`. /// @param n_ The number of items to pop off the virtual stack. function pop( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, uint256 n_ ) internal pure returns (StackPointer) { if (n_ > 0) { stackTop_ = stackTop_.down(n_); integrityCheckState_.popUnderflowCheck(stackTop_); } return stackTop_; } /// DANGEROUS pop that does no underflow/highwater checks. The caller MUST /// ensure that this does not result in illegal stack reads. /// @param stackTop_ as per `pop`. /// @param n_ as per `pop`. function popIgnoreHighwater( IntegrityCheckState memory, StackPointer stackTop_, uint256 n_ ) internal pure returns (StackPointer) { return stackTop_.down(n_); } /// Ensures that pops have not underflowed the stack, i.e. that the stack /// top is not below the stack bottom. We set a large stack bottom that is /// impossible to underflow within gas limits with realistic pops so that /// we don't have to deal with a numeric underflow of the stack top. /// @param integrityCheckState_ As per `pop`. /// @param stackTop_ as per `pop`. function popUnderflowCheck( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_ ) internal pure { if ( StackPointer.unwrap(stackTop_) <= StackPointer.unwrap(integrityCheckState_.stackHighwater) ) { revert StackPopUnderflow( integrityCheckState_.stackBottom.toIndex( integrityCheckState_.stackHighwater ), integrityCheckState_.stackBottom.toIndex(stackTop_) ); } } /// Maps `function(uint256, uint256) internal view returns (uint256)` to pops /// and pushes repeatedly N times. The function itself is irrelevant we only /// care about the signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @param n_ The number of times the function is applied to the stack. /// @return The stack top after the function has been applied n times. function applyFnN( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256, uint256) internal view returns (uint256), uint256 n_ ) internal pure returns (StackPointer) { return integrityCheckState_.push(integrityCheckState_.pop(stackTop_, n_)); } /// Maps `function(uint256) internal view` to pops and pushes repeatedly N /// times. The function itself is irrelevant we only care about the /// signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @param n_ The number of times the function is applied to the stack. /// @return The stack top after the function has been applied n times. function applyFnN( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256) internal view, uint256 n_ ) internal pure returns (StackPointer) { return integrityCheckState_.pop(stackTop_, n_); } /// Maps `function(uint256) internal view returns (uint256)` to pops and /// pushes once. The function itself is irrelevant we only care about the /// signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256) internal view returns (uint256) ) internal pure returns (StackPointer) { return integrityCheckState_.push(integrityCheckState_.pop(stackTop_)); } /// Maps `function(uint256, uint256) internal view` to pops and pushes once. /// The function itself is irrelevant we only care about the signature to /// know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256, uint256) internal view ) internal pure returns (StackPointer) { return integrityCheckState_.pop(stackTop_, 2); } /// Maps `function(uint256, uint256) internal view returns (uint256)` to /// pops and pushes once. The function itself is irrelevant we only care /// about the signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256, uint256) internal view returns (uint256) ) internal pure returns (StackPointer) { return integrityCheckState_.push(integrityCheckState_.pop(stackTop_, 2)); } /// Maps /// `function(uint256, uint256, uint256) internal view returns (uint256)` to /// pops and pushes once. The function itself is irrelevant we only care /// about the signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256, uint256, uint256) internal view returns (uint256) ) internal pure returns (StackPointer) { return integrityCheckState_.push(integrityCheckState_.pop(stackTop_, 3)); } /// Maps /// ``` /// function(uint256, uint256, uint256, uint256) /// internal /// view /// returns (uint256) /// ``` /// to pops and pushes once. The function itself is irrelevant we only care /// about the signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256, uint256, uint256, uint256) internal view returns (uint256) ) internal pure returns (StackPointer) { return integrityCheckState_.push(integrityCheckState_.pop(stackTop_, 4)); } /// Maps `function(uint256[] memory) internal view returns (uint256)` to /// pops and pushes once given that we know the length of the dynamic array /// at deploy time. The function itself is irrelevant we only care about the /// signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @param length_ The length of the dynamic input array. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256[] memory) internal view returns (uint256), uint256 length_ ) internal pure returns (StackPointer) { return integrityCheckState_.push( integrityCheckState_.pop(stackTop_, length_) ); } /// Maps /// ``` /// function(uint256, uint256, uint256[] memory) /// internal /// view /// returns (uint256) /// ``` /// to pops and pushes once given that we know the length of the dynamic /// array at deploy time. The function itself is irrelevant we only care /// about the signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @param length_ The length of the dynamic input array. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256, uint256, uint256[] memory) internal view returns (uint256), uint256 length_ ) internal pure returns (StackPointer) { unchecked { return integrityCheckState_.push( integrityCheckState_.pop(stackTop_, length_ + 2) ); } } /// Maps /// ``` /// function(uint256, uint256, uint256, uint256[] memory) /// internal /// view /// returns (uint256) /// ``` /// to pops and pushes once given that we know the length of the dynamic /// array at deploy time. The function itself is irrelevant we only care /// about the signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @param length_ The length of the dynamic input array. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256, uint256, uint256, uint256[] memory) internal view returns (uint256), uint256 length_ ) internal pure returns (StackPointer) { unchecked { return integrityCheckState_.push( integrityCheckState_.pop(stackTop_, length_ + 3) ); } } /// Maps /// ``` /// function(uint256, uint256[] memory, uint256[] memory) /// internal /// view /// returns (uint256[] memory) /// ``` /// to pops and pushes once given that we know the length of the dynamic /// array at deploy time. The function itself is irrelevant we only care /// about the signature to know how many items are popped/pushed. /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @param length_ The length of the dynamic input array. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(uint256, uint256[] memory, uint256[] memory) internal view returns (uint256[] memory), uint256 length_ ) internal pure returns (StackPointer) { unchecked { return integrityCheckState_.push( integrityCheckState_.pop(stackTop_, length_ * 2 + 1), length_ ); } } /// Maps `function(Operand, uint256) internal view returns (uint256)` to /// pops and pushes once. The function itself is irrelevant we only care /// about the signature to know how many items are popped/pushed. /// /// The operand MUST NOT influence the stack movements if this application /// is to be valid. /// /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(Operand, uint256) internal view returns (uint256) ) internal pure returns (StackPointer) { return integrityCheckState_.push(integrityCheckState_.pop(stackTop_)); } /// Maps /// `function(Operand, uint256, uint256) internal view returns (uint256)` to /// pops and pushes once. The function itself is irrelevant we only care /// about the signature to know how many items are popped/pushed. /// /// The operand MUST NOT influence the stack movements if this application /// is to be valid. /// /// @param integrityCheckState_ as per `pop` and `push`. /// @param stackTop_ as per `pop` and `push`. /// @return The stack top after the function has been applied once. function applyFn( IntegrityCheckState memory integrityCheckState_, StackPointer stackTop_, function(Operand, uint256, uint256) internal view returns (uint256) ) internal pure returns (StackPointer) { return integrityCheckState_.push(integrityCheckState_.pop(stackTop_, 2)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; /// @title LibConvert /// @notice Type conversions that require additional structural changes to /// complete safely. These are NOT mere type casts and involve additional /// reads and writes to complete, such as recalculating the length of an array. /// The convention "toX" is adopted from Rust to imply the additional costs and /// consumption of the source to produce the target. library LibConvert { /// Convert an array of integers to `bytes` data. This requires modifying /// the length in situ as the integer array length is measured in 32 byte /// increments while the length of `bytes` is the literal number of bytes. /// @return bytes_ The integer array converted to `bytes` data. function toBytes( uint256[] memory us_ ) internal pure returns (bytes memory bytes_) { assembly ("memory-safe") { bytes_ := us_ // Length in bytes is 32x the length in uint256 mstore(bytes_, mul(0x20, mload(bytes_))) } } /// Truncate `uint256[]` values down to `uint16[]` then pack this to `bytes` /// without padding or length prefix. Unsafe because the starting `uint256` /// values are not checked for overflow due to the truncation. The caller /// MUST ensure that all values fit in `type(uint16).max` or that silent /// overflow is safe. /// @param us_ The `uint256[]` to truncate and concatenate to 16 bit `bytes`. /// @return The concatenated 2-byte chunks. function unsafeTo16BitBytes( uint256[] memory us_ ) internal pure returns (bytes memory) { unchecked { // We will keep 2 bytes (16 bits) from each integer. bytes memory bytes_ = new bytes(us_.length * 2); assembly ("memory-safe") { let replaceMask_ := 0xFFFF let preserveMask_ := not(replaceMask_) for { let cursor_ := add(us_, 0x20) let end_ := add(cursor_, mul(mload(us_), 0x20)) let bytesCursor_ := add(bytes_, 0x02) } lt(cursor_, end_) { cursor_ := add(cursor_, 0x20) bytesCursor_ := add(bytesCursor_, 0x02) } { let data_ := mload(bytesCursor_) mstore( bytesCursor_, or(and(preserveMask_, data_), mload(cursor_)) ) } } return bytes_; } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.10; /// @title LibMemorySize /// @notice Reports the size in bytes of type data that represents contigious /// regions of memory. Pointers to regions of memory that may not be congigious /// are not supported, e.g. fields on structs may point to dynamic data that is /// separate to the struct. Length slots for dynamic data are included in the /// size and the size is always measured in bytes. library LibMemorySize { /// Reports the size of a `uint256` in bytes. Is always 32. /// @return 32. function size(uint256) internal pure returns (uint256) { return 0x20; } /// Reports the size of a `uint256[]` in bytes. Is the size of the length /// slot (32 bytes) plus the length of the array multiplied by 32 bytes per /// item. /// @return The size of the array data including its length slot size. function size(uint256[] memory array_) internal pure returns (uint256) { unchecked { return 0x20 + (array_.length * 0x20); } } /// Reports the size of `bytes` data. Is the size of the length slot /// (32 bytes) plus the number of bytes as per its length. /// @return The size of the `bytes` data including its length slot size. function size(bytes memory bytes_) internal pure returns (uint256) { unchecked { return 0x20 + bytes_.length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCastUpgradeable { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "sol.lib.binmaskflag/Binary.sol"; /// Thrown when attempting to read a value from the other side of a zero pointer. error InvalidPtr(MemoryKVPtr ptr); /// Entrypoint into the key/value store. Is a mutable pointer to the head of the /// linked list. Initially points to `0` for an empty list. The total length of /// the linked list is also encoded alongside the pointer to allow efficient O(1) /// memory allocation for a `uint256[]` in the case of a final snapshot/export. type MemoryKV is uint256; /// The key associated with the value for each item in the linked list. type MemoryKVKey is uint256; /// The pointer to the next item in the list. `0` signifies the end of the list. type MemoryKVPtr is uint256; /// The value associated with the key for each item in the linked list. type MemoryKVVal is uint256; /// @title LibMemoryKV /// @notice Implements an in-memory key/value store in terms of a linked list /// that can be snapshotted/exported to a `uint256[]` of pairwise keys/values as /// its items. Ostensibly supports reading/writing to storage within a read only /// context in an interpreter `eval` by tracking changes requested by an /// expression in memory as a cache-like structure over the underlying storage. /// /// A linked list is required because unlike stack movements we do NOT have any /// way to precalculate how many items will be included in the final set at /// deploy time. Any two writes may share the same key known only at runtime, so /// any two writes may result in either 2 or 1 insertions (and 0 or 1 updates). /// We could attempt to solve this by allowing duplicate keys and simply append /// values for each write, so two writes will always insert 2 values, but then /// looping constructs such as `OpDoWhile` and `OpFoldContext` with net 0 stack /// movements (i.e. predictably deallocateable memory) can still cause /// unbounded/unknown inserts for our state changes. The linked list allows us /// to both dedupe same-key writes and also safely handle an unknown /// (at deploy time) number of upserts. New items are inserted at the head of /// the list and a pointer to `0` is the sentinel that defines the end of the /// list. It is an error to dereference the `0` pointer. /// /// Currently implemented as O(n) where n is likely relatively small, in future /// could be reimplemented as 8 linked lists over a single `MemoryKV` by packing /// many `MemoryKVPtr` and using `%` to distribute keys between lists. The /// extremely high gas cost of writing to storage itself should be a natural /// disincentive for n getting large enough to cause the linked list traversal /// to be a significant gas cost itself. /// /// Currently implemented in terms of raw `uint256` custom types that represent /// keys, values and pointers. Could be reimplemented in terms of an equivalent /// struct with key, value and pointer fields. library LibMemoryKV { /// Reads the `MemoryKVVal` that some `MemoryKVPtr` is pointing to. It is an /// error to call this if `ptr_` is `0`. /// @param ptr_ The pointer to read the value function readPtrVal( MemoryKVPtr ptr_ ) internal pure returns (MemoryKVVal v_) { // This is ALWAYS a bug. It means the caller did not check if the ptr is // nonzero before trying to read from it. if (MemoryKVPtr.unwrap(ptr_) == 0) { revert InvalidPtr(ptr_); } assembly ("memory-safe") { v_ := mload(add(ptr_, 0x20)) } } /// Finds the pointer to the item that holds the value associated with the /// given key. Walks the linked list from the entrypoint into the key/value /// store until it finds the specified key. As the last pointer in the list /// is always `0`, `0` is what will be returned if the key is not found. Any /// non-zero pointer implies the value it points to is for the provided key. /// @param kv_ The entrypoint to the key/value store. /// @param k_ The key to lookup a pointer for. /// @return ptr_ The _pointer_ to the value for the key, if it exists, else /// a pointer to `0`. If the pointer is non-zero the associated value can be /// read to a `MemoryKVVal` with `LibMemoryKV.readPtrVal`. function getPtr( MemoryKV kv_, MemoryKVKey k_ ) internal pure returns (MemoryKVPtr ptr_) { uint256 mask_ = MASK_16BIT; assembly ("memory-safe") { // loop until k found or give up if ptr is zero for { ptr_ := and(kv_, mask_) } iszero(iszero(ptr_)) { ptr_ := mload(add(ptr_, 0x40)) } { if eq(k_, mload(ptr_)) { break } } } } /// Upserts a value in the set by its key. I.e. if the key exists then the /// associated value will be mutated in place, else a new key/value pair will /// be inserted. The key/value store pointer will be mutated and returned as /// it MAY point to a new list item in memory. /// @param kv_ The key/value store pointer to modify. /// @param k_ The key to upsert against. /// @param v_ The value to associate with the upserted key. /// @return The final value of `kv_` as it MAY be modified if the upsert /// resulted in an insert operation. function setVal( MemoryKV kv_, MemoryKVKey k_, MemoryKVVal v_ ) internal pure returns (MemoryKV) { MemoryKVPtr ptr_ = getPtr(kv_, k_); uint256 mask_ = MASK_16BIT; // update if (MemoryKVPtr.unwrap(ptr_) > 0) { assembly ("memory-safe") { mstore(add(ptr_, 0x20), v_) } } // insert else { assembly ("memory-safe") { // allocate new memory ptr_ := mload(0x40) mstore(0x40, add(ptr_, 0x60)) // set k/v/ptr mstore(ptr_, k_) mstore(add(ptr_, 0x20), v_) mstore(add(ptr_, 0x40), and(kv_, mask_)) // kv must point to new insertion and update array len kv_ := or( // inc len by 2 shl(16, add(shr(16, kv_), 2)), // set ptr ptr_ ) } } return kv_; } /// Export/snapshot the underlying linked list of the key/value store into /// a standard `uint256[]`. Reads the total length to preallocate the /// `uint256[]` then walks the entire linked list, copying every key and /// value into the array, until it reaches a pointer to `0`. Note this is a /// one time export, if the key/value store is subsequently mutated the built /// array will not reflect these mutations. /// @param kv_ The entrypoint into the key/value store. /// @return All the keys and values copied pairwise into a `uint256[]`. function toUint256Array( MemoryKV kv_ ) internal pure returns (uint256[] memory) { unchecked { uint256 ptr_ = MemoryKV.unwrap(kv_) & MASK_16BIT; uint256 length_ = MemoryKV.unwrap(kv_) >> 16; uint256[] memory arr_ = new uint256[](length_); assembly ("memory-safe") { for { let cursor_ := add(arr_, 0x20) let end_ := add(cursor_, mul(mload(arr_), 0x20)) } lt(cursor_, end_) { cursor_ := add(cursor_, 0x20) ptr_ := mload(add(ptr_, 0x40)) } { // key mstore(cursor_, mload(ptr_)) cursor_ := add(cursor_, 0x20) // value mstore(cursor_, mload(add(ptr_, 0x20))) } } return arr_; } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.16; /// @dev Binary 1. uint256 constant B_1 = 2 ** 1 - 1; /// @dev Binary 11. uint256 constant B_11 = 2 ** 2 - 1; /// @dev Binary 111. uint256 constant B_111 = 2 ** 3 - 1; /// @dev Binary 1111. uint256 constant B_1111 = 2 ** 4 - 1; /// @dev Binary 11111. uint256 constant B_11111 = 2 ** 5 - 1; /// @dev Binary 111111. uint256 constant B_111111 = 2 ** 6 - 1; /// @dev Binary 1111111. uint256 constant B_1111111 = 2 ** 7 - 1; /// @dev Binary 11111111. uint256 constant B_11111111 = 2 ** 8 - 1; /// @dev Binary 111111111. uint256 constant B_111111111 = 2 ** 9 - 1; /// @dev Binary 1111111111. uint256 constant B_1111111111 = 2 ** 10 - 1; /// @dev Binary 11111111111. uint256 constant B_11111111111 = 2 ** 11 - 1; /// @dev Binary 111111111111. uint256 constant B_111111111111 = 2 ** 12 - 1; /// @dev Binary 1111111111111. uint256 constant B_1111111111111 = 2 ** 13 - 1; /// @dev Binary 11111111111111. uint256 constant B_11111111111111 = 2 ** 14 - 1; /// @dev Binary 111111111111111. uint256 constant B_111111111111111 = 2 ** 15 - 1; /// @dev Binary 1111111111111111. uint256 constant B_1111111111111111 = 2 ** 16 - 1; /// @dev Bitmask for 1 bit. uint256 constant MASK_1BIT = B_1; /// @dev Bitmask for 2 bits. uint256 constant MASK_2BIT = B_11; /// @dev Bitmask for 3 bits. uint256 constant MASK_3BIT = B_111; /// @dev Bitmask for 4 bits. uint256 constant MASK_4BIT = B_1111; /// @dev Bitmask for 5 bits. uint256 constant MASK_5BIT = B_11111; /// @dev Bitmask for 6 bits. uint256 constant MASK_6BIT = B_111111; /// @dev Bitmask for 7 bits. uint256 constant MASK_7BIT = B_1111111; /// @dev Bitmask for 8 bits. uint256 constant MASK_8BIT = B_11111111; /// @dev Bitmask for 9 bits. uint256 constant MASK_9BIT = B_111111111; /// @dev Bitmask for 10 bits. uint256 constant MASK_10BIT = B_1111111111; /// @dev Bitmask for 11 bits. uint256 constant MASK_11BIT = B_11111111111; /// @dev Bitmask for 12 bits. uint256 constant MASK_12BIT = B_111111111111; /// @dev Bitmask for 13 bits. uint256 constant MASK_13BIT = B_1111111111111; /// @dev Bitmask for 14 bits. uint256 constant MASK_14BIT = B_11111111111111; /// @dev Bitmask for 15 bits. uint256 constant MASK_15BIT = B_111111111111111; /// @dev Bitmask for 16 bits. uint256 constant MASK_16BIT = B_1111111111111111;
// SPDX-License-Identifier: MIT pragma solidity >= 0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); function _sendLogPayload(bytes memory payload) private view { uint256 payloadLength = payload.length; address consoleAddress = CONSOLE_ADDRESS; assembly { let payloadStart := add(payload, 32) let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) } } function log() internal view { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int256 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); } function logUint(uint256 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function logString(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint256 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function log(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint256 p0, uint256 p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); } function log(uint256 p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); } function log(uint256 p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); } function log(uint256 p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); } function log(string memory p0, uint256 p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); } function log(string memory p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint256 p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); } function log(bool p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint256 p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); } function log(address p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint256 p0, uint256 p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); } function log(uint256 p0, string memory p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); } function log(uint256 p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); } function log(uint256 p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); } function log(uint256 p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); } function log(uint256 p0, bool p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); } function log(uint256 p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); } function log(uint256 p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); } function log(uint256 p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); } function log(uint256 p0, address p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); } function log(uint256 p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); } function log(uint256 p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); } function log(uint256 p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); } function log(string memory p0, uint256 p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); } function log(string memory p0, uint256 p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); } function log(string memory p0, uint256 p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); } function log(string memory p0, uint256 p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint256 p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); } function log(bool p0, uint256 p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); } function log(bool p0, uint256 p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); } function log(bool p0, uint256 p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint256 p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); } function log(address p0, uint256 p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); } function log(address p0, uint256 p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); } function log(address p0, uint256 p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint256 p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint256 p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "metadata": { "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 1000000, "details": { "peephole": true, "inliner": true, "jumpdestRemover": true, "orderLiterals": true, "deduplicate": true, "cse": true, "constantOptimizer": true } }, "evmVersion": "london", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"FullyQualifiedNamespace","name":"namespace_","type":"uint256"},{"internalType":"uint256","name":"key_","type":"uint256"}],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"StateNamespace","name":"namespace_","type":"uint256"},{"internalType":"uint256[]","name":"kvs_","type":"uint256[]"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50610397806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806301ffc9a714610046578063669e48aa1461006e578063946aadc6146100a5575b600080fd5b610059610054366004610248565b6100ba565b60405190151581526020015b60405180910390f35b61009761007c366004610291565b60009182526020828152604080842092845291905290205490565b604051908152602001610065565b6100b86100b33660046102b3565b610153565b005b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ff2f4e56c00000000000000000000000000000000000000000000000000000000148061014d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b60006101d0846040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16602082015260348101829052600090605401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012092915050565b905060005b82811015610241578383826001018181106101f2576101f2610332565b90506020020135600080848152602001908152602001600020600086868581811061021f5761021f610332565b60209081029290920135835250810191909152604001600020556002016101d5565b5050505050565b60006020828403121561025a57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461028a57600080fd5b9392505050565b600080604083850312156102a457600080fd5b50508035926020909101359150565b6000806000604084860312156102c857600080fd5b83359250602084013567ffffffffffffffff808211156102e757600080fd5b818601915086601f8301126102fb57600080fd5b81358181111561030a57600080fd5b8760208260051b850101111561031f57600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea26469706673582212203f4f175e40e67b781062c45d492dacc4cbe1dd7e0e459ade9b06539c7a09962864736f6c63430008120033
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.