Contract Overview
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
OrderBook
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 "./IOrderBookV1.sol"; import "./LibOrder.sol"; import "../interpreter/run/LibStackPointer.sol"; import "../math/LibFixedPointMath.sol"; import "../interpreter/caller/IInterpreterCallerV1.sol"; import "../interpreter/ops/AllStandardOps.sol"; import "./OrderBookFlashLender.sol"; import "../interpreter/run/LibEncodedDispatch.sol"; import "../interpreter/caller/LibContext.sol"; import "../interpreter/deploy/DeployerDiscoverableMetaV1.sol"; import "./LibOrderBook.sol"; import {MulticallUpgradeable as Multicall} from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol"; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {SafeERC20Upgradeable as SafeERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import {MathUpgradeable as Math} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import {ReentrancyGuardUpgradeable as ReentrancyGuard} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; /// Thrown when the `msg.sender` modifying an order is not its owner. /// @param sender `msg.sender` attempting to modify the order. /// @param owner The owner of the order. error NotOrderOwner(address sender, address owner); /// Thrown when the input and output tokens don't match, in either direction. /// @param aliceToken The input or output of one order. /// @param bobToken The input or output of the other order that doesn't match a. error TokenMismatch(address aliceToken, address bobToken); /// Thrown when the minimum input is not met. /// @param minimumInput The minimum input required. /// @param input The input that was achieved. error MinimumInput(uint256 minimumInput, uint256 input); /// Thrown when two orders have the same owner during clear. /// @param owner The owner of both orders. error SameOwner(address owner); /// @dev Hash of the caller contract metadata for construction. bytes32 constant CALLER_META_HASH = bytes32( 0x46fe110bf52ba709a3d80747fa101a615fc46eb9ff0fadd4a46d1def682f974f ); /// @dev Value that signifies that an order is live in the internal mapping. /// Anything nonzero is equally useful. uint256 constant LIVE_ORDER = 1; /// @dev Value that signifies that an order is dead in the internal mapping. uint256 constant DEAD_ORDER = 0; /// @dev Entrypoint to a calculate the amount and ratio of an order. SourceIndex constant CALCULATE_ORDER_ENTRYPOINT = SourceIndex.wrap(0); /// @dev Entrypoint to handle the final internal vault movements resulting from /// matching multiple calculated orders. SourceIndex constant HANDLE_IO_ENTRYPOINT = SourceIndex.wrap(1); /// @dev Minimum outputs for calculate order are the amount and ratio. uint256 constant CALCULATE_ORDER_MIN_OUTPUTS = 2; /// @dev Maximum outputs for calculate order are the amount and ratio. uint256 constant CALCULATE_ORDER_MAX_OUTPUTS = 2; /// @dev Handle IO has no outputs as it only responds to vault movements. uint256 constant HANDLE_IO_MIN_OUTPUTS = 0; /// @dev Handle IO has no outputs as it only response to vault movements. uint256 constant HANDLE_IO_MAX_OUTPUTS = 0; /// @dev Orderbook context is actually fairly complex. The calling context column /// is populated before calculate order, but the remaining columns are only /// available to handle IO as they depend on the full evaluation of calculuate /// order, and cross referencing against the same from the counterparty, as well /// as accounting limits such as current vault balances, etc. /// The token address and decimals for vault inputs and outputs IS available to /// the calculate order entrypoint, but not the final vault balances/diff. uint256 constant CALLING_CONTEXT_COLUMNS = 4; /// @dev Base context from LibContext. uint256 constant CONTEXT_BASE_COLUMN = 0; /// @dev Contextual data available to both calculate order and handle IO. The /// order hash, order owner and order counterparty. IMPORTANT NOTE that the /// typical base context of an order with the caller will often be an unrelated /// clearer of the order rather than the owner or counterparty. uint256 constant CONTEXT_CALLING_CONTEXT_COLUMN = 1; /// @dev Calculations column contains the DECIMAL RESCALED calculations but /// otherwise provided as-is according to calculate order entrypoint uint256 constant CONTEXT_CALCULATIONS_COLUMN = 2; /// @dev Vault inputs are the literal token amounts and vault balances before and /// after for the input token from the perspective of the order. MAY be /// significantly different to the calculated amount due to insufficient vault /// balances from either the owner or counterparty, etc. uint256 constant CONTEXT_VAULT_INPUTS_COLUMN = 3; /// @dev Vault outputs are the same as vault inputs but for the output token from /// the perspective of the order. uint256 constant CONTEXT_VAULT_OUTPUTS_COLUMN = 4; /// @dev Row of the token address for vault inputs and outputs columns. uint256 constant CONTEXT_VAULT_IO_TOKEN = 0; /// @dev Row of the token decimals for vault inputs and outputs columns. uint256 constant CONTEXT_VAULT_IO_TOKEN_DECIMALS = 1; /// @dev Row of the vault ID for vault inputs and outputs columns. uint256 constant CONTEXT_VAULT_IO_VAULT_ID = 2; /// @dev Row of the vault balance before the order was cleared for vault inputs /// and outputs columns. uint256 constant CONTEXT_VAULT_IO_BALANCE_BEFORE = 3; /// @dev Row of the vault balance difference after the order was cleared for /// vault inputs and outputs columns. The diff is ALWAYS POSITIVE as it is a /// `uint256` so it must be added to input balances and subtraced from output /// balances. uint256 constant CONTEXT_VAULT_IO_BALANCE_DIFF = 4; /// @dev Length of a vault IO column. uint256 constant CONTEXT_VAULT_IO_ROWS = 5; /// @title OrderBook /// See `IOrderBookV1` for more documentation. contract OrderBook is IOrderBookV1, ReentrancyGuard, Multicall, OrderBookFlashLender, IInterpreterCallerV1, DeployerDiscoverableMetaV1 { using LibInterpreterState for bytes; using LibStackPointer for StackPointer; using LibStackPointer for uint256[]; using LibUint256Array for uint256[]; using SafeERC20 for IERC20; using Math for uint256; using LibFixedPointMath for uint256; using LibOrder for Order; using LibInterpreterState for InterpreterState; using LibUint256Array for uint256; /// All hashes of all active orders. There's nothing interesting in the value /// it's just nonzero if the order is live. The key is the hash of the order. /// Removing an order sets the value back to zero so it is identical to the /// order never existing and gives a gas refund on removal. /// The order hash includes its owner so there's no need to build a multi /// level mapping, each order hash MUST uniquely identify the order globally. /// order hash => order is live mapping(uint256 => uint256) internal orders; /// @inheritdoc IOrderBookV1 mapping(address => mapping(address => mapping(uint256 => uint256))) public vaultBalance; /// Initializes the orderbook upon construction for compatibility with /// Open Zeppelin upgradeable contracts. Orderbook itself does NOT support /// factory deployments as each order is a unique expression deployment /// rather than needing to wrap up expressions with proxies. constructor( DeployerDiscoverableMetaV1ConstructionConfig memory config_ ) initializer DeployerDiscoverableMetaV1(CALLER_META_HASH, config_) { __ReentrancyGuard_init(); __Multicall_init(); } /// @inheritdoc IOrderBookV1 function deposit(DepositConfig calldata config_) external nonReentrant { // It is safest with vault deposits to move tokens in to the Orderbook // before updating internal vault balances although we have a reentrancy // guard in place anyway. emit Deposit(msg.sender, config_); IERC20(config_.token).safeTransferFrom( msg.sender, address(this), config_.amount ); vaultBalance[msg.sender][config_.token][config_.vaultId] += config_ .amount; } /// @inheritdoc IOrderBookV1 function withdraw(WithdrawConfig calldata config_) external nonReentrant { uint256 vaultBalance_ = vaultBalance[msg.sender][config_.token][ config_.vaultId ]; uint256 withdrawAmount_ = config_.amount.min(vaultBalance_); // The overflow check here is redundant with .min above, so technically // this is overly conservative but we REALLY don't want withdrawals to // exceed vault balances. vaultBalance[msg.sender][config_.token][config_.vaultId] = vaultBalance_ - withdrawAmount_; emit Withdraw(msg.sender, config_, withdrawAmount_); _decreaseFlashDebtThenSendToken( config_.token, msg.sender, withdrawAmount_ ); } /// @inheritdoc IOrderBookV1 function addOrder(OrderConfig calldata config_) external nonReentrant { ( IInterpreterV1 interpreter_, IInterpreterStoreV1 store_, address expression_ ) = config_.evaluableConfig.deployer.deployExpression( config_.evaluableConfig.sources, config_.evaluableConfig.constants, LibUint256Array.arrayFrom( CALCULATE_ORDER_MIN_OUTPUTS, HANDLE_IO_MIN_OUTPUTS ) ); Order memory order_ = Order( msg.sender, config_ .evaluableConfig .sources[SourceIndex.unwrap(HANDLE_IO_ENTRYPOINT)] .length > 0, Evaluable(interpreter_, store_, expression_), config_.validInputs, config_.validOutputs ); uint256 orderHash_ = order_.hash(); orders[orderHash_] = LIVE_ORDER; emit AddOrder( msg.sender, config_.evaluableConfig.deployer, order_, orderHash_ ); if (config_.meta.length > 0) { LibMeta.checkMetaUnhashed(config_.meta); emit MetaV1(msg.sender, orderHash_, config_.meta); } } function _calculateOrderDispatch( address expression_ ) internal pure returns (EncodedDispatch) { return LibEncodedDispatch.encode( expression_, CALCULATE_ORDER_ENTRYPOINT, CALCULATE_ORDER_MAX_OUTPUTS ); } function _handleIODispatch( address expression_ ) internal pure returns (EncodedDispatch) { return LibEncodedDispatch.encode( expression_, HANDLE_IO_ENTRYPOINT, HANDLE_IO_MAX_OUTPUTS ); } /// @inheritdoc IOrderBookV1 function removeOrder(Order calldata order_) external nonReentrant { if (msg.sender != order_.owner) { revert NotOrderOwner(msg.sender, order_.owner); } uint256 orderHash_ = order_.hash(); delete (orders[orderHash_]); emit RemoveOrder(msg.sender, order_, orderHash_); } /// @inheritdoc IOrderBookV1 function takeOrders( TakeOrdersConfig calldata takeOrders_ ) external nonReentrant returns (uint256 totalInput_, uint256 totalOutput_) { uint256 i_ = 0; TakeOrderConfig memory takeOrder_; Order memory order_; uint256 remainingInput_ = takeOrders_.maximumInput; while (i_ < takeOrders_.orders.length && remainingInput_ > 0) { takeOrder_ = takeOrders_.orders[i_]; order_ = takeOrder_.order; uint256 orderHash_ = order_.hash(); if (orders[orderHash_] == DEAD_ORDER) { emit OrderNotFound(msg.sender, order_.owner, orderHash_); } else { if ( order_.validInputs[takeOrder_.inputIOIndex].token != takeOrders_.output ) { revert TokenMismatch( order_.validInputs[takeOrder_.inputIOIndex].token, takeOrders_.output ); } if ( order_.validOutputs[takeOrder_.outputIOIndex].token != takeOrders_.input ) { revert TokenMismatch( order_.validOutputs[takeOrder_.outputIOIndex].token, takeOrders_.input ); } OrderIOCalculation memory orderIOCalculation_ = _calculateOrderIO( order_, takeOrder_.inputIOIndex, takeOrder_.outputIOIndex, msg.sender, takeOrder_.signedContext ); // Skip orders that are too expensive rather than revert as we have // no way of knowing if a specific order becomes too expensive // between submitting to mempool and execution, but other orders may // be valid so we want to take advantage of those if possible. if (orderIOCalculation_.IORatio > takeOrders_.maximumIORatio) { emit OrderExceedsMaxRatio( msg.sender, order_.owner, orderHash_ ); } else if (orderIOCalculation_.outputMax == 0) { emit OrderZeroAmount(msg.sender, order_.owner, orderHash_); } else { // Don't exceed the maximum total input. uint256 input_ = remainingInput_.min( orderIOCalculation_.outputMax ); // Always round IO calculations up. uint256 output_ = input_.fixedPointMul( orderIOCalculation_.IORatio, Math.Rounding.Up ); remainingInput_ -= input_; totalOutput_ += output_; _recordVaultIO( order_, output_, input_, orderIOCalculation_ ); emit TakeOrder(msg.sender, takeOrder_, input_, output_); } } unchecked { i_++; } } totalInput_ = takeOrders_.maximumInput - remainingInput_; if (totalInput_ < takeOrders_.minimumInput) { revert MinimumInput(takeOrders_.minimumInput, totalInput_); } // We already updated vault balances before we took tokens from // `msg.sender` which is usually NOT the correct order of operations for // depositing to a vault. We rely on reentrancy guards to make this safe. IERC20(takeOrders_.output).safeTransferFrom( msg.sender, address(this), totalOutput_ ); // Prioritise paying down any active flash loans before sending any // tokens to `msg.sender`. _decreaseFlashDebtThenSendToken( takeOrders_.input, msg.sender, totalInput_ ); } /// @inheritdoc IOrderBookV1 function clear( Order memory alice_, Order memory bob_, ClearConfig calldata clearConfig_, SignedContext[] memory aliceSignedContext_, SignedContext[] memory bobSignedContext_ ) external nonReentrant { { if (alice_.owner == bob_.owner) { revert SameOwner(alice_.owner); } if ( alice_.validOutputs[clearConfig_.aliceOutputIOIndex].token != bob_.validInputs[clearConfig_.bobInputIOIndex].token ) { revert TokenMismatch( alice_.validOutputs[clearConfig_.aliceOutputIOIndex].token, bob_.validInputs[clearConfig_.bobInputIOIndex].token ); } if ( bob_.validOutputs[clearConfig_.bobOutputIOIndex].token != alice_.validInputs[clearConfig_.aliceInputIOIndex].token ) { revert TokenMismatch( alice_.validInputs[clearConfig_.aliceInputIOIndex].token, bob_.validOutputs[clearConfig_.bobOutputIOIndex].token ); } // If either order is dead the clear is a no-op other than emitting // `OrderNotFound`. Returning rather than erroring makes it easier to // bulk clear using `Multicall`. if (orders[alice_.hash()] == DEAD_ORDER) { emit OrderNotFound(msg.sender, alice_.owner, alice_.hash()); return; } if (orders[bob_.hash()] == DEAD_ORDER) { emit OrderNotFound(msg.sender, bob_.owner, bob_.hash()); return; } // Emit the Clear event before `eval`. emit Clear(msg.sender, alice_, bob_, clearConfig_); } OrderIOCalculation memory aliceOrderIOCalculation_ = _calculateOrderIO( alice_, clearConfig_.aliceInputIOIndex, clearConfig_.aliceOutputIOIndex, bob_.owner, bobSignedContext_ ); OrderIOCalculation memory bobOrderIOCalculation_ = _calculateOrderIO( bob_, clearConfig_.bobInputIOIndex, clearConfig_.bobOutputIOIndex, alice_.owner, aliceSignedContext_ ); ClearStateChange memory clearStateChange_ = LibOrderBook ._clearStateChange( aliceOrderIOCalculation_, bobOrderIOCalculation_ ); _recordVaultIO( alice_, clearStateChange_.aliceInput, clearStateChange_.aliceOutput, aliceOrderIOCalculation_ ); _recordVaultIO( bob_, clearStateChange_.bobInput, clearStateChange_.bobOutput, bobOrderIOCalculation_ ); { // At least one of these will overflow due to negative bounties if // there is a spread between the orders. uint256 aliceBounty_ = clearStateChange_.aliceOutput - clearStateChange_.bobInput; uint256 bobBounty_ = clearStateChange_.bobOutput - clearStateChange_.aliceInput; if (aliceBounty_ > 0) { vaultBalance[msg.sender][ alice_.validOutputs[clearConfig_.aliceOutputIOIndex].token ][clearConfig_.aliceBountyVaultId] += aliceBounty_; } if (bobBounty_ > 0) { vaultBalance[msg.sender][ bob_.validOutputs[clearConfig_.bobOutputIOIndex].token ][clearConfig_.bobBountyVaultId] += bobBounty_; } } emit AfterClear(msg.sender, clearStateChange_); } /// Main entrypoint into an order calculates the amount and IO ratio. Both /// are always treated as 18 decimal fixed point values and then rescaled /// according to the order's definition of each token's actual fixed point /// decimals. /// @param order_ The order to evaluate. /// @param inputIOIndex_ The index of the input token being calculated for. /// @param outputIOIndex_ The index of the output token being calculated for. /// @param counterparty_ The counterparty of the order as it is currently /// being cleared against. /// @param signedContext_ Any signed context provided by the clearer/taker /// that the order may need for its calculations. function _calculateOrderIO( Order memory order_, uint256 inputIOIndex_, uint256 outputIOIndex_, address counterparty_, SignedContext[] memory signedContext_ ) internal view virtual returns (OrderIOCalculation memory) { unchecked { uint256 orderHash_ = order_.hash(); uint256[][] memory context_; { uint256[][] memory callingContext_ = new uint256[][]( CALLING_CONTEXT_COLUMNS ); callingContext_[ CONTEXT_CALLING_CONTEXT_COLUMN - 1 ] = LibUint256Array.arrayFrom( orderHash_, uint256(uint160(order_.owner)), uint256(uint160(counterparty_)) ); callingContext_[ CONTEXT_VAULT_INPUTS_COLUMN - 1 ] = LibUint256Array.arrayFrom( uint256(uint160(order_.validInputs[inputIOIndex_].token)), order_.validInputs[inputIOIndex_].decimals, order_.validInputs[inputIOIndex_].vaultId, vaultBalance[order_.owner][ order_.validInputs[inputIOIndex_].token ][order_.validInputs[inputIOIndex_].vaultId], // Don't know the balance diff yet! 0 ); callingContext_[ CONTEXT_VAULT_OUTPUTS_COLUMN - 1 ] = LibUint256Array.arrayFrom( uint256(uint160(order_.validOutputs[outputIOIndex_].token)), order_.validOutputs[outputIOIndex_].decimals, order_.validOutputs[outputIOIndex_].vaultId, vaultBalance[order_.owner][ order_.validOutputs[outputIOIndex_].token ][order_.validOutputs[outputIOIndex_].vaultId], // Don't know the balance diff yet! 0 ); context_ = LibContext.build( callingContext_, new uint256[](0), signedContext_ ); } // The state changes produced here are handled in _recordVaultIO so // that local storage writes happen before writes on the interpreter. StateNamespace namespace_ = StateNamespace.wrap( uint(uint160(order_.owner)) ); (uint256[] memory stack_, uint256[] memory kvs_) = order_ .evaluable .interpreter .eval( order_.evaluable.store, namespace_, _calculateOrderDispatch(order_.evaluable.expression), context_ ); uint256 orderOutputMax_ = stack_[stack_.length - 2]; uint256 orderIORatio_ = stack_[stack_.length - 1]; // Rescale order output max from 18 FP to whatever decimals the // output token is using. // Always round order output down. orderOutputMax_ = orderOutputMax_.scaleN( order_.validOutputs[outputIOIndex_].decimals, Math.Rounding.Down ); // Rescale the ratio from 18 FP according to the difference in // decimals between input and output. // Always round IO ratio up. orderIORatio_ = orderIORatio_.scaleRatio( order_.validOutputs[outputIOIndex_].decimals, order_.validInputs[inputIOIndex_].decimals, Math.Rounding.Up ); // The order owner can't send more than the smaller of their vault // balance or their per-order limit. orderOutputMax_ = orderOutputMax_.min( vaultBalance[order_.owner][ order_.validOutputs[outputIOIndex_].token ][order_.validOutputs[outputIOIndex_].vaultId] ); // Populate the context with the output max rescaled and vault capped // and the rescaled ratio. context_[CONTEXT_CALCULATIONS_COLUMN] = LibUint256Array.arrayFrom( orderOutputMax_, orderIORatio_ ); return OrderIOCalculation( orderOutputMax_, orderIORatio_, context_, namespace_, kvs_ ); } } /// Given an order, final input and output amounts and the IO calculation /// verbatim from `_calculateOrderIO`, dispatch the handle IO entrypoint if /// it exists and update the order owner's vault balances. /// @param order_ The order that is being cleared. /// @param input_ The exact token input amount to move into the owner's /// vault. /// @param output_ The exact token output amount to move out of the owner's /// vault. /// @param orderIOCalculation_ The verbatim order IO calculation returned by /// `_calculateOrderIO`. function _recordVaultIO( Order memory order_, uint256 input_, uint256 output_, OrderIOCalculation memory orderIOCalculation_ ) internal virtual { orderIOCalculation_.context[CONTEXT_VAULT_INPUTS_COLUMN][ CONTEXT_VAULT_IO_BALANCE_DIFF ] = input_; orderIOCalculation_.context[CONTEXT_VAULT_OUTPUTS_COLUMN][ CONTEXT_VAULT_IO_BALANCE_DIFF ] = output_; if (input_ > 0) { // IMPORTANT! THIS MATH MUST BE CHECKED TO AVOID OVERFLOW. vaultBalance[order_.owner][ address( uint160( orderIOCalculation_.context[ CONTEXT_VAULT_INPUTS_COLUMN ][CONTEXT_VAULT_IO_TOKEN] ) ) ][ orderIOCalculation_.context[CONTEXT_VAULT_INPUTS_COLUMN][ CONTEXT_VAULT_IO_VAULT_ID ] ] += input_; } if (output_ > 0) { // IMPORTANT! THIS MATH MUST BE CHECKED TO AVOID UNDERFLOW. vaultBalance[order_.owner][ address( uint160( orderIOCalculation_.context[ CONTEXT_VAULT_OUTPUTS_COLUMN ][CONTEXT_VAULT_IO_TOKEN] ) ) ][ orderIOCalculation_.context[CONTEXT_VAULT_OUTPUTS_COLUMN][ CONTEXT_VAULT_IO_VAULT_ID ] ] -= output_; } // Emit the context only once in its fully populated form rather than two // nearly identical emissions of a partial and full context. emit Context(msg.sender, orderIOCalculation_.context); // Apply state changes to the interpreter store after the vault balances // are updated, but before we call handle IO. We want handle IO to see // a consistent view on sets from calculate IO. if (orderIOCalculation_.kvs.length > 0) { order_.evaluable.store.set( orderIOCalculation_.namespace, orderIOCalculation_.kvs ); } // Only dispatch handle IO entrypoint if it is defined, otherwise it is // a waste of gas to hit the interpreter a second time. if (order_.handleIO) { // The handle IO eval is run under the same namespace as the // calculate order entrypoint. (, uint256[] memory handleIOKVs_) = order_ .evaluable .interpreter .eval( order_.evaluable.store, orderIOCalculation_.namespace, _handleIODispatch(order_.evaluable.expression), orderIOCalculation_.context ); // Apply state changes to the interpreter store from the handle IO // entrypoint. if (handleIOKVs_.length > 0) { order_.evaluable.store.set( orderIOCalculation_.namespace, handleIOKVs_ ); } } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../ierc3156/IERC3156FlashLender.sol"; import "../interpreter/deploy/IExpressionDeployerV1.sol"; import "../interpreter/run/IInterpreterV1.sol"; import "../interpreter/run/LibEvaluable.sol"; import "../interpreter/caller/IInterpreterCallerV1.sol"; /// Configuration for a deposit. All deposits are processed by and for /// `msg.sender` so the vaults are unambiguous here. /// @param token The token to deposit. /// @param vaultId The vault ID for the token to deposit. /// @param amount The amount of the token to deposit. struct DepositConfig { address token; uint256 vaultId; uint256 amount; } /// Configuration for a withdrawal. All withdrawals are processed by and for /// `msg.sender` so the vaults are unambiguous here. /// @param token The token to withdraw. /// @param vaultId The vault ID for the token to withdraw. /// @param amount The amount of the token to withdraw. struct WithdrawConfig { address token; uint256 vaultId; uint256 amount; } /// Configuration for a single input or output on an `Order`. /// @param token The token to either send from the owner as an output or receive /// from the counterparty to the owner as an input. The tokens are not moved /// during an order, only internal vault balances are updated, until a separate /// withdraw step. /// @param decimals The decimals to use for internal scaling calculations for /// `token`. This is provided directly in IO to save gas on external lookups and /// to respect the ERC20 spec that mandates NOT assuming or using the `decimals` /// method for onchain calculations. Ostensibly the decimals exists so that all /// calculate order entrypoints can treat amounts and ratios as 18 decimal fixed /// point values. Order max amounts MUST be rounded down and IO ratios rounded up /// to compensate for any loss of precision during decimal rescaling. /// @param vaultId The vault ID that tokens will move into if this is an input /// or move out from if this is an output. struct IO { address token; uint8 decimals; uint256 vaultId; } /// Config the order owner may provide to define their order. The `msg.sender` /// that adds an order cannot modify the owner nor bypass the integrity check of /// the expression deployer that they specify. However they MAY specify a /// deployer with a corrupt integrity check, so counterparties and clearers MUST /// check the DISpair of the order and avoid untrusted pairings. /// @param validInputs As per `validInputs` on the `Order`. /// @param validOutputs As per `validOutputs` on the `Order`. /// @param evaluableConfig Standard `EvaluableConfig` used to produce the /// `Evaluable` on the order. /// @param meta Arbitrary bytes that will NOT be used in the order evaluation /// but MUST be emitted as a Rain `MetaV1` when the order is placed so can be /// used by offchain processes. struct OrderConfig { IO[] validInputs; IO[] validOutputs; EvaluableConfig evaluableConfig; bytes meta; } /// Defines a fully deployed order ready to evaluate by Orderbook. /// @param owner The owner of the order is the `msg.sender` that added the order. /// @param handleIO true if there is a "handle IO" entrypoint to run. If false /// the order book MAY skip calling the interpreter to save gas. /// @param evaluable Standard `Evaluable` with entrypoints for both /// "calculate order" and "handle IO". The latter MAY be empty bytes, in which /// case it will be skipped at runtime to save gas. /// @param validInputs A list of input tokens that are economically equivalent /// for the purpose of processing this order. Inputs are relative to the order /// so these tokens will be sent to the owners vault. /// @param validOutputs A list of output tokens that are economically equivalent /// for the purpose of processing this order. Outputs are relative to the order /// so these tokens will be sent from the owners vault. struct Order { address owner; bool handleIO; Evaluable evaluable; IO[] validInputs; IO[] validOutputs; } /// Config for a list of orders to take sequentially as part of a `takeOrders` /// call. /// @param output Output token from the perspective of the order taker. /// @param input Input token from the perspective of the order taker. /// @param minimumInput Minimum input from the perspective of the order taker. /// @param maximumInput Maximum input from the perspective of the order taker. /// @param maximumIORatio Maximum IO ratio as calculated by the order being /// taken. The input is from the perspective of the order so higher ratio means /// worse deal for the order taker. /// @param orders Ordered list of orders that will be taken until the limit is /// hit. Takers are expected to prioritise orders that appear to be offering /// better deals i.e. lower IO ratios. This prioritisation and sorting MUST /// happen offchain, e.g. via. some simulator. struct TakeOrdersConfig { address output; address input; uint256 minimumInput; uint256 maximumInput; uint256 maximumIORatio; TakeOrderConfig[] orders; } /// Config for an individual take order from the overall list of orders in a /// call to `takeOrders`. /// @param order The order being taken this iteration. /// @param inputIOIndex The index of the input token in `order` to match with the /// take order output. /// @param outputIOIndex The index of the output token in `order` to match with /// the take order input. /// @param signedContext Optional additional signed context relevant to the /// taken order. struct TakeOrderConfig { Order order; uint256 inputIOIndex; uint256 outputIOIndex; SignedContext[] signedContext; } /// Additional config to a `clear` that allows two orders to be fully matched to /// a specific token moment. Also defines the bounty for the clearer. /// @param aliceInputIOIndex The index of the input token in order A. /// @param aliceOutputIOIndex The index of the output token in order A. /// @param bobInputIOIndex The index of the input token in order B. /// @param bobOutputIOIndex The index of the output token in order B. /// @param aliceBountyVaultId The vault ID that the bounty from order A should /// move to for the clearer. /// @param bobBountyVaultId The vault ID that the bounty from order B should move /// to for the clearer. struct ClearConfig { uint256 aliceInputIOIndex; uint256 aliceOutputIOIndex; uint256 bobInputIOIndex; uint256 bobOutputIOIndex; uint256 aliceBountyVaultId; uint256 bobBountyVaultId; } /// Summary of the vault state changes due to clearing an order. NOT the state /// changes sent to the interpreter store, these are the LOCAL CHANGES in vault /// balances. Note that the difference in inputs/outputs overall between the /// counterparties is the bounty paid to the entity that cleared the order. /// @param aliceOutput Amount of counterparty A's output token that moved out of /// their vault. /// @param bobOutput Amount of counterparty B's output token that moved out of /// their vault. /// @param aliceInput Amount of counterparty A's input token that moved into /// their vault. /// @param bobInput Amount of counterparty B's input token that moved into their /// vault. struct ClearStateChange { uint256 aliceOutput; uint256 bobOutput; uint256 aliceInput; uint256 bobInput; } /// @title IOrderBookV1 /// @notice An orderbook that deploys _strategies_ represented as interpreter /// expressions rather than individual orders. The order book contract itself /// behaves similarly to an `ERC4626` vault but with much more fine grained /// control over how tokens are allocated and moved internally by their owners, /// and without any concept of "shares". Token owners MAY deposit and withdraw /// their tokens under arbitrary vault IDs on a per-token basis, then define /// orders that specify how tokens move between vaults according to an expression. /// The expression returns a maximum amount and a token input/output ratio from /// the perpective of the order. When two expressions intersect, as in their /// ratios are the inverse of each other, then tokens can move between vaults. /// /// For example, consider order A with input TKNA and output TKNB with a constant /// ratio of 100:1. This order in isolation has no ability to move tokens. If /// an order B appears with input TKNB and output TKNA and a ratio of 1:100 then /// this is a perfect match with order A. In this case 100 TKNA will move from /// order B to order A and 1 TKNB will move from order A to order B. /// /// IO ratios are always specified as input:output and are 18 decimal fixed point /// values. The maximum amount that can be moved in the current clearance is also /// set by the order expression as an 18 decimal fixed point value. /// /// Typically orders will not clear when their match is exactly 1:1 as the /// clearer needs to pay gas to process the match. Each order will get exactly /// the ratio it calculates when it does clear so if there is _overlap_ in the /// ratios then the clearer keeps the difference. In our above example, consider /// order B asking a ratio of 1:110 instead of 1:100. In this case 100 TKNA will /// move from order B to order A and 10 TKNA will move to the clearer's vault and /// 1 TKNB will move from order A to order B. In the case of fixed prices this is /// not very interesting as order B could more simply take order A directly for /// cheaper rather than involving a third party. Indeed, Orderbook supports a /// direct "take orders" method that works similar to a "market buy". In the case /// of dynamic expression based ratios, it allows both order A and order B to /// clear non-interactively according to their strategy, trading off active /// management, dealing with front-running, MEV, etc. for zero-gas and /// exact-ratio clearance. /// /// The general invariant for clearing and take orders is: /// /// ``` /// ratioA = InputA / OutputA /// ratioB = InputB / OutputB /// ratioA * ratioB = ( InputA * InputB ) / ( OutputA * OutputB ) /// OutputA >= InputB /// OutputB >= InputA /// /// ∴ ratioA * ratioB <= 1 /// ``` /// /// Orderbook is `IERC3156FlashLender` compliant with a 0 fee flash loan /// implementation to allow external liquidity from other onchain DEXes to match /// against orderbook expressions. All deposited tokens across all vaults are /// available for flashloan, the flashloan MAY BE REPAID BY CALLING TAKE ORDER /// such that Orderbook's liability to its vaults is decreased by an incoming /// trade from the flashloan borrower. See `ZeroExOrderBookFlashBorrower` for /// an example of how this works in practise. /// /// Orderbook supports many to many input/output token relationship, for example /// some order can specify an array of stables it would be willing to accept in /// return for some ETH. This removes the need for a combinatorial explosion of /// order strategies between like assets but introduces the issue of token /// decimal handling. End users understand that "one" USDT is roughly equal to /// "one" DAI, but onchain this is incorrect by _12 orders of magnitude_. This /// is because "one" DAI is `1e18` tokens and "one" USDT is `1e6` tokens. The /// orderbook is allowing orders to deploy expressions that define _economic /// equivalence_ but this doesn't map 1:1 with numeric equivalence in a many to /// many setup behind token decimal convensions. The solution is to require that /// end users who place orders provide the decimals of each token they include /// in their valid IO lists, and to calculate all amounts and ratios in their /// expressions _as though they were 18 decimal fixed point values_. Orderbook /// will then automatically rescale the expression values before applying the /// final vault movements. If an order provides the "wrong" decimal values for /// some token then it will simply calculate its own ratios and amounts /// incorrectly which will either lead to no matching orders or a very bad trade /// for the order owner. There is no way that misrepresenting decimals can attack /// some other order by a counterparty. Orderbook DOES NOT read decimals from /// tokens onchain because A. this would be gas for an external call to a cold /// token contract and B. the ERC20 standard specifically states NOT to read /// decimals from the interface onchain. /// /// Token amounts and ratios returned by calculate order MUST be 18 decimal fixed /// point values. Token amounts input to handle IO MUST be the exact absolute /// values that move between the vaults, i.e. NOT rescaled to 18 decimals. The /// author of the handle IO expression MUST use the token decimals and amounts to /// rescale themselves if they want that logic, notably the expression author /// will need to specify the desired rounding behaviour in the rescaling process. /// /// When two orders clear there are NO TOKEN MOVEMENTS, only internal vault /// balances are updated from the input and output vaults. Typically this results /// in less gas per clear than calling external token transfers and also avoids /// issues with reentrancy, allowances, external balances etc. This also means /// that REBASING TOKENS AND TOKENS WITH DYNAMIC BALANCE ARE NOT SUPPORTED. /// Orderbook ONLY WORKS IF TOKEN BALANCES ARE 1:1 WITH ADDITION/SUBTRACTION PER /// VAULT MOVEMENT. /// /// Dust due to rounding errors always favours the order. Output max is rounded /// down and IO ratios are rounded up. Input and output amounts are always /// converted to absolute values before applying to vault balances such that /// orderbook always retains fully collateralised inventory of underlying token /// balances to support withdrawals, with the caveat that dynamic token balanes /// are not supported. /// /// When an order clears it is NOT removed. Orders remain active until the owner /// deactivates them. This is gas efficient as order owners MAY deposit more /// tokens in a vault with an order against it many times and the order strategy /// will continue to be clearable according to its expression. As vault IDs are /// `uint256` values there are effectively infinite possible vaults for any token /// so there is no limit to how many active orders any address can have at one /// time. This also allows orders to be daisy chained arbitrarily where output /// vaults for some order are the input vaults for some other order. /// /// Expression storage is namespaced by order owner, so gets and sets are unique /// to each onchain address. Order owners MUST TAKE CARE not to override their /// storage sets globally across all their orders, which they can do most simply /// by hashing the order hash into their get/set keys inside the expression. This /// gives maximum flexibility for shared state across orders without allowing /// order owners to attack and overwrite values stored by orders placed by their /// counterparty. /// /// Note that each order specifies its own interpreter and deployer so the /// owner is responsible for not corrupting their own calculations with bad /// interpreters. This also means the Orderbook MUST assume the interpreter, and /// notably the interpreter's store, is malicious and guard against reentrancy /// etc. /// /// As Orderbook supports any expression that can run on any `IInterpreterV1` and /// counterparties are available to the order, order strategies are free to /// implement KYC/membership, tracking, distributions, stock, buybacks, etc. etc. interface IOrderBookV1 is IERC3156FlashLender { /// Some tokens have been deposited to a vault. /// @param sender `msg.sender` depositing tokens. Delegated deposits are NOT /// supported. /// @param config All config sent to the `deposit` call. event Deposit(address sender, DepositConfig config); /// Some tokens have been withdrawn from a vault. /// @param sender `msg.sender` withdrawing tokens. Delegated withdrawals are /// NOT supported. /// @param config All config sent to the `withdraw` call. /// @param amount The amount of tokens withdrawn, can be less than the /// config amount if the vault does not have the funds available to cover /// the config amount. For example an active order might move tokens before /// the withdraw completes. event Withdraw(address sender, WithdrawConfig config, uint256 amount); /// An order has been added to the orderbook. The order is permanently and /// always active according to its expression until/unless it is removed. /// @param sender `msg.sender` adding the order and is owner of the order. /// @param expressionDeployer The expression deployer that ran the integrity /// check for this order. This is NOT included in the `Order` itself but is /// important for offchain processes to ignore untrusted deployers before /// interacting with them. /// @param order The newly added order. MUST be handed back as-is when /// clearing orders and contains derived information in addition to the order /// config that was provided by the order owner. /// @param orderHash The hash of the order as it is recorded onchain. Only /// the hash is stored in Orderbook storage to avoid paying gas to store the /// entire order. event AddOrder( address sender, IExpressionDeployerV1 expressionDeployer, Order order, uint256 orderHash ); /// An order has been removed from the orderbook. This effectively /// deactivates it. Orders can be added again after removal. /// @param sender `msg.sender` removing the order and is owner of the order. /// @param order The removed order. /// @param orderHash The hash of the removed order. event RemoveOrder(address sender, Order order, uint256 orderHash); /// Some order has been taken by `msg.sender`. This is the same as them /// placing inverse orders then immediately clearing them all, but costs less /// gas and is more convenient and reliable. Analogous to a market buy /// against the specified orders. Each order that is matched within a the /// `takeOrders` loop emits its own individual event. /// @param sender `msg.sender` taking the orders. /// @param config All config defining the orders to attempt to take. /// @param input The input amount from the perspective of sender. /// @param output The output amount from the perspective of sender. event TakeOrder( address sender, TakeOrderConfig config, uint256 input, uint256 output ); /// Emitted when attempting to match an order that either never existed or /// was removed. An event rather than an error so that we allow attempting /// many orders in a loop and NOT rollback on "best effort" basis to clear. /// @param sender `msg.sender` clearing the order that wasn't found. /// @param owner Owner of the order that was not found. /// @param orderHash Hash of the order that was not found. event OrderNotFound(address sender, address owner, uint256 orderHash); /// Emitted when an order evaluates to a zero amount. An event rather than an /// error so that we allow attempting many orders in a loop and NOT rollback /// on a "best effort" basis to clear. /// @param sender `msg.sender` clearing the order that had a 0 amount. /// @param owner Owner of the order that evaluated to a 0 amount. /// @param orderHash Hash of the order that evaluated to a 0 amount. event OrderZeroAmount(address sender, address owner, uint256 orderHash); /// Emitted when an order evaluates to a ratio exceeding the counterparty's /// maximum limit. An error rather than an error so that we allow attempting /// many orders in a loop and NOT rollback on a "best effort" basis to clear. /// @param sender `msg.sender` clearing the order that had an excess ratio. /// @param owner Owner of the order that had an excess ratio. /// @param orderHash Hash of the order that had an excess ratio. event OrderExceedsMaxRatio( address sender, address owner, uint256 orderHash ); /// Emitted before two orders clear. Covers both orders and includes all the /// state before anything is calculated. /// @param sender `msg.sender` clearing both orders. /// @param alice One of the orders. /// @param bob The other order. /// @param clearConfig Additional config required to process the clearance. event Clear( address sender, Order alice, Order bob, ClearConfig clearConfig ); /// Emitted after two orders clear. Includes all final state changes in the /// vault balances, including the clearer's vaults. /// @param sender `msg.sender` clearing the order. /// @param clearStateChange The final vault state changes from the clearance. event AfterClear(address sender, ClearStateChange clearStateChange); /// Get the current balance of a vault for a given owner, token and vault ID. /// @param owner The owner of the vault. /// @param token The token the vault is for. /// @param id The vault ID to read. /// @return balance The current balance of the vault. function vaultBalance( address owner, address token, uint256 id ) external view returns (uint256 balance); /// `msg.sender` deposits tokens according to config. The config specifies /// the vault to deposit tokens under. Delegated depositing is NOT supported. /// Depositing DOES NOT mint shares (unlike ERC4626) so the overall vaulted /// experience is much simpler as there is always a 1:1 relationship between /// deposited assets and vault balances globally and individually. This /// mitigates rounding/dust issues, speculative behaviour on derived assets, /// possible regulatory issues re: whether a vault share is a security, code /// bloat on the vault, complex mint/deposit/withdraw/redeem 4-way logic, /// the need for preview functions, etc. etc. /// At the same time, allowing vault IDs to be specified by the depositor /// allows much more granular and direct control over token movements within /// Orderbook than either ERC4626 vault shares or mere contract-level ERC20 /// allowances can facilitate. /// @param config All config for the deposit. function deposit(DepositConfig calldata config) external; /// Allows the sender to withdraw any tokens from their own vaults. If the /// withrawer has an active flash loan debt denominated in the same token /// being withdrawn then Orderbook will merely reduce the debt and NOT send /// the amount of tokens repaid to the flashloan debt. /// @param config All config required to withdraw. Notably if the amount /// is less than the current vault balance then the vault will be cleared /// to 0 rather than the withdraw transaction reverting. function withdraw(WithdrawConfig calldata config) external; /// Given an order config, deploys the expression and builds the full `Order` /// for the config, then records it as an active order. Delegated adding an /// order is NOT supported. The `msg.sender` that adds an order is ALWAYS /// the owner and all resulting vault movements are their own. /// @param config All config required to build an `Order`. function addOrder(OrderConfig calldata config) external; /// Order owner can remove their own orders. Delegated order removal is NOT /// supported and will revert. Removing an order multiple times or removing /// an order that never existed are valid, the event will be emitted and the /// transaction will complete with that order hash definitely, redundantly /// not live. /// @param order The `Order` data exactly as it was added. function removeOrder(Order calldata order) external; /// Allows `msg.sender` to attempt to fill a list of orders in sequence /// without needing to place their own order and clear them. This works like /// a market buy but against a specific set of orders. Every order will /// looped over and calculated individually then filled maximally until the /// request input is reached for the `msg.sender`. The `msg.sender` is /// responsible for selecting the best orders at the time according to their /// criteria and MAY specify a maximum IO ratio to guard against an order /// spiking the ratio beyond what the `msg.sender` expected and is /// comfortable with. As orders may be removed and calculate their ratios /// dynamically, all issues fulfilling an order other than misconfiguration /// by the `msg.sender` are no-ops and DO NOT revert the transaction. This /// allows the `msg.sender` to optimistically provide a list of orders that /// they aren't sure will completely fill at a good price, and fallback to /// more reliable orders further down their list. Misconfiguration such as /// token mismatches are errors that revert as this is known and static at /// all times to the `msg.sender` so MUST be provided correctly. `msg.sender` /// MAY specify a minimum input that MUST be reached across all orders in the /// list, otherwise the transaction will revert, this MAY be set to zero. /// /// Exactly like withdraw, if there is an active flash loan for `msg.sender` /// they will have their outstanding loan reduced by the final input amount /// preferentially before sending any tokens. Notably this allows arb bots /// implemented as flash loan borrowers to connect orders against external /// liquidity directly by paying back the loan with a `takeOrders` call and /// outputting the result of the external trade. /// /// Rounding errors always favour the order never the `msg.sender`. /// /// @param config The constraints and list of orders to take, orders are /// processed sequentially in order as provided, there is NO ATTEMPT onchain /// to predict/filter/sort these orders other than evaluating them as /// provided. Inputs and outputs are from the perspective of `msg.sender` /// except for values specified by the orders themselves which are the from /// the perspective of that order. /// @return totalInput Total tokens sent to `msg.sender`, taken from order /// vaults processed. /// @return totalOutput Total tokens taken from `msg.sender` and distributed /// between vaults. function takeOrders( TakeOrdersConfig calldata config ) external returns (uint256 totalInput, uint256 totalOutput); /// Allows `msg.sender` to match two live orders placed earlier by /// non-interactive parties and claim a bounty in the process. The clearer is /// free to select any two live orders on the order book for matching and as /// long as they have compatible tokens, ratios and amounts, the orders will /// clear. Clearing the orders DOES NOT remove them from the orderbook, they /// remain live until explicitly removed by their owner. Even if the input /// vault balances are completely emptied, the orders remain live until /// removed. This allows order owners to deploy a strategy over a long period /// of time and periodically top up the input vaults. Clearing two orders /// from the same owner is disallowed. /// /// Any mismatch in the ratios between the two orders will cause either more /// inputs than there are available outputs (transaction will revert) or less /// inputs than there are available outputs. In the latter case the excess /// outputs are given to the `msg.sender` of clear, to the vaults they /// specify in the clear config. This not only incentivises "automatic" clear /// calls for both alice and bob, but incentivises _prioritising greater /// ratio differences_ with a larger bounty. The second point is important /// because it implicitly prioritises orders that are further from the /// current market price, thus putting constant increasing pressure on the /// entire system the further it drifts from the norm, no matter how esoteric /// the individual order expressions and sizings might be. /// /// All else equal there are several factors that would impact how reliably /// some order clears relative to the wider market, such as: /// /// - Bounties are effectively percentages of cleared amounts so larger /// orders have larger bounties and cover gas costs more easily /// - High gas on the network means that orders are harder to clear /// profitably so the negative spread of the ratios will need to be larger /// - Complex and stateful expressions cost more gas to evalulate so the /// negative spread will need to be larger /// - Erratic behavior of the order owner could reduce the willingness of /// third parties to interact if it could result in wasted gas due to /// orders suddently being removed before clearance etc. /// - Dynamic and highly volatile words used in the expression could be /// ignored or low priority by clearers who want to be sure that they can /// accurately predict the ratios that they include in their clearance /// - Geopolitical issues such as sanctions and regulatory restrictions could /// cause issues for certain owners and clearers /// /// @param alice Some order to clear. /// @param bob Another order to clear. /// @param clearConfig Additional configuration for the clearance such as /// how to handle the bounty payment for the `msg.sender`. /// @param aliceSignedContext Optional signed context that is relevant to A. /// @param bobSignedContext Optional signed context that is relevant to B. function clear( Order memory alice, Order memory bob, ClearConfig calldata clearConfig, SignedContext[] memory aliceSignedContext, SignedContext[] memory bobSignedContext ) external; }
// SPDX-License-Identifier: CC0 // Alberto Cuesta Cañada, Fiona Kobayashi, fubuloubu, Austin Williams, "EIP-3156: Flash Loans," Ethereum Improvement Proposals, no. 3156, November 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3156. pragma solidity ^0.8.0; import "./IERC3156FlashBorrower.sol"; interface IERC3156FlashLender { /** * @dev The amount of currency available to be lent. * @param token The loan currency. * @return The amount of `token` that can be borrowed. */ function maxFlashLoan(address token) external view returns (uint256); /** * @dev The fee to be charged for a given loan. * @param token The loan currency. * @param amount The amount of tokens lent. * @return The amount of `token` to be charged for the loan, on top of the returned principal. */ function flashFee( address token, uint256 amount ) external view returns (uint256); /** * @dev Initiate a flash loan. * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. * @param token The loan currency. * @param amount The amount of tokens lent. * @param data Arbitrary data structure, intended to contain user-defined parameters. */ function flashLoan( IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data ) external returns (bool); }
// SPDX-License-Identifier: CC0 // Alberto Cuesta Cañada, Fiona Kobayashi, fubuloubu, Austin Williams, "EIP-3156: Flash Loans," Ethereum Improvement Proposals, no. 3156, November 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3156. pragma solidity ^0.8.0; interface IERC3156FlashBorrower { /** * @dev Receive a flash loan. * @param initiator The initiator of the loan. * @param token The loan currency. * @param amount The amount of tokens lent. * @param fee The additional amount of tokens to repay. * @param data Arbitrary data structure, intended to contain user-defined parameters. * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan" */ function onFlashLoan( address initiator, address token, uint256 amount, uint256 fee, bytes calldata data ) external returns (bytes32); }
// 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.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.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.18; import "../deploy/IExpressionDeployerV1.sol"; import "./IInterpreterV1.sol"; struct EvaluableConfig { IExpressionDeployerV1 deployer; bytes[] sources; uint256[] constants; } /// Struct over the return of `IExpressionDeployerV1.deployExpression` which adds /// which may be more convenient to work with than raw addresses. struct Evaluable { IInterpreterV1 interpreter; IInterpreterStoreV1 store; address expression; } library LibEvaluable { function hash(Evaluable memory evaluable_) internal pure returns (bytes32) { return keccak256(abi.encode(evaluable_)); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; /// Typed embodiment of some context data with associated signer and signature. /// The signature MUST be over the packed encoded bytes of the context array, /// i.e. the context array concatenated as bytes without the length prefix, then /// hashed, then handled as per EIP-191 to produce a final hash to be signed. /// /// The calling contract (likely with the help of `LibContext`) is responsible /// for ensuring the authenticity of the signature, but not authorizing _who_ can /// sign. IN ADDITION to authorisation of the signer to known-good entities the /// expression is also responsible for: /// /// - Enforcing the context is the expected data (e.g. with a domain separator) /// - Tracking and enforcing nonces if signed contexts are only usable one time /// - Tracking and enforcing uniqueness of signed data if relevant /// - Checking and enforcing expiry times if present and relevant in the context /// - Many other potential constraints that expressions may want to enforce /// /// EIP-1271 smart contract signatures are supported in addition to EOA /// signatures via. the Open Zeppelin `SignatureChecker` library, which is /// wrapped by `LibContext.build`. As smart contract signatures are checked /// onchain they CAN BE REVOKED AT ANY MOMENT as the smart contract can simply /// return `false` when it previously returned `true`. /// /// @param signer The account that produced the signature for `context`. The /// calling contract MUST authenticate that the signer produced the signature. /// @param signature The cryptographic signature for `context`. The calling /// contract MUST authenticate that the signature is valid for the `signer` and /// `context`. /// @param context The signed data in a format that can be merged into a /// 2-dimensional context matrix as-is. struct SignedContext { address signer; bytes signature; uint256[] context; } /// @title IInterpreterCallerV1 /// @notice A contract that calls an `IInterpreterV1` via. `eval`. There are near /// zero requirements on a caller other than: /// /// - Emit some meta about itself upon construction so humans know what the /// contract does /// - Provide the context, which can be built in a standard way by `LibContext` /// - Handle the stack array returned from `eval` /// - OPTIONALLY emit the `Context` event /// - OPTIONALLY set state on the `IInterpreterStoreV1` returned from eval. interface IInterpreterCallerV1 { /// Calling contracts SHOULD emit `Context` before calling `eval` if they /// are able. Notably `eval` MAY be called within a static call which means /// that events cannot be emitted, in which case this does not apply. It MAY /// NOT be useful to emit this multiple times for several eval calls if they /// all share a common context, in which case a single emit is sufficient. /// @param sender `msg.sender` building the context. /// @param context The context that was built. event Context(address sender, uint256[][] context); }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "./IOrderBookV1.sol"; /// @title LibOrder /// @notice Consistent handling of `Order` for where it matters w.r.t. /// determinism and security. library LibOrder { /// Hashes `Order` in a secure and deterministic way. Uses abi.encode rather /// than abi.encodePacked to guard against potential collisions where many /// inputs encode to the same output bytes. /// @param order_ The order to hash. /// @return The hash of `order_` as a `uint256` rather than `bytes32`. function hash(Order memory order_) internal pure returns (uint256) { return uint256(keccak256(abi.encode(order_))); } }
// 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.0; import {MathUpgradeable as Math} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import {SafeCastUpgradeable as SafeCast} from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; import "rain.math.saturating/SaturatingMath.sol"; /// @dev The scale of all fixed point math. This is adopting the conventions of /// both ETH (wei) and most ERC20 tokens, so is hopefully uncontroversial. uint256 constant FP_DECIMALS = 18; /// @dev The number `1` in the standard fixed point math scaling. Most of the /// differences between fixed point math and regular math is multiplying or /// dividing by `ONE` after the appropriate scaling has been applied. uint256 constant FP_ONE = 1e18; /// @title FixedPointMath /// @notice Sometimes we want to do math with decimal values but all we have /// are integers, typically uint256 integers. Floats are very complex so we /// don't attempt to simulate them. Instead we provide a standard definition of /// "one" as 10 ** 18 and scale everything up/down to this as fixed point math. /// /// Overflows SATURATE rather than error, e.g. scaling max uint256 up will result /// in max uint256. The max uint256 as decimal is roughly 1e77 so scaling values /// comparable to 1e18 is unlikely to ever saturate in practise. For a typical /// use case involving tokens, the entire supply of a token rescaled up a full /// 18 decimals would still put it "only" in the region of ~1e40 which has a full /// 30 orders of magnitude buffer before running into saturation issues. However, /// there's no theoretical reason that a token or any other use case couldn't use /// large numbers or extremely precise decimals that would push this library to /// saturation point, so it MUST be treated with caution around the edge cases. /// /// One case where values could come near the saturation/overflow point is phantom /// overflow. This is where an overflow happens during the internal logic of some /// operation like "fixed point multiplication" even though the final result fits /// within uint256. The fixed point multiplication and division functions are /// thin wrappers around Open Zeppelin's `mulDiv` function, that handles phantom /// overflow, reducing the problems of rescaling overflow/saturation to the input /// and output range rather than to the internal implementation details. For this /// library that gives an additional full 18 orders of magnitude for safe fixed /// point multiplication operations. /// /// Scaling down ANY fixed point decimal also reduces the precision which can /// lead to dust or in the worst case trapped funds if subsequent subtraction /// overflows a rounded-down number. Consider using saturating subtraction for /// safety against previously downscaled values, and whether trapped dust is a /// significant issue. If you need to retain full/arbitrary precision in the case /// of downscaling DO NOT use this library. /// /// All rescaling and/or division operations in this library require the rounding /// flag from Open Zeppelin math. This allows and forces the caller to specify /// where dust sits due to rounding. For example the caller could round up when /// taking tokens from `msg.sender` and round down when returning them, ensuring /// that any dust in the round trip accumulates in the contract rather than /// opening an exploit or reverting and trapping all funds. This is exactly how /// the ERC4626 vault spec handles dust and is a good reference point in general. /// Typically the contract holding tokens and non-interactive participants should /// be favoured by rounding calculations rather than active participants. This is /// because we assume that an active participant, e.g. `msg.sender`, knowns /// something we don't and is carefully crafting an attack, so we are most /// conservative and suspicious of their inputs and actions. library LibFixedPointMath { using Math for uint256; using SafeCast for int256; using SaturatingMath for uint256; /// Scale a fixed point decimal of some scale factor to match `DECIMALS`. /// @param a_ Some fixed point decimal value. /// @param aDecimals_ The number of fixed decimals of `a_`. /// @param rounding_ Rounding direction as per Open Zeppelin Math. /// @return `a_` scaled to match `DECIMALS`. function scale18( uint256 a_, uint256 aDecimals_, Math.Rounding rounding_ ) internal pure returns (uint256) { uint256 decimals_; if (FP_DECIMALS == aDecimals_) { return a_; } else if (FP_DECIMALS > aDecimals_) { unchecked { decimals_ = FP_DECIMALS - aDecimals_; } return a_.saturatingMul(10 ** decimals_); } else { unchecked { decimals_ = aDecimals_ - FP_DECIMALS; } return scaleDown(a_, decimals_, rounding_); } } /// Scale a fixed point decimals of `DECIMALS` to some other scale. /// @param a_ A `DECIMALS` fixed point decimals. /// @param targetDecimals_ The new scale of `a_`. /// @param rounding_ Rounding direction as per Open Zeppelin Math. /// @return `a_` rescaled from `DECIMALS` to `targetDecimals_`. function scaleN( uint256 a_, uint256 targetDecimals_, Math.Rounding rounding_ ) internal pure returns (uint256) { uint256 decimals_; if (targetDecimals_ == FP_DECIMALS) { return a_; } else if (FP_DECIMALS > targetDecimals_) { unchecked { decimals_ = FP_DECIMALS - targetDecimals_; } return scaleDown(a_, decimals_, rounding_); } else { unchecked { decimals_ = targetDecimals_ - FP_DECIMALS; } return a_.saturatingMul(10 ** decimals_); } } /// Scale a fixed point decimals of `DECIMALS` that represents a ratio of /// a_:b_ according to the decimals of a and b that MAY NOT be `DECIMALS`. /// i.e. a subsequent call to `a_.fixedPointMul(ratio_)` would yield the value /// that it would have as though `a_` and `b_` were both `DECIMALS` and we /// hadn't rescaled the ratio. /// @param ratio_ The ratio to be scaled. /// @param aDecimals_ The decimals of the ratio numerator. /// @param bDecimals_ The decimals of the ratio denominator. /// @param rounding_ Rounding direction as per Open Zeppelin Math. function scaleRatio( uint256 ratio_, uint256 aDecimals_, uint256 bDecimals_, Math.Rounding rounding_ ) internal pure returns (uint256) { return scaleBy( ratio_, (int256(bDecimals_) - int256(aDecimals_)).toInt8(), rounding_ ); } /// Scale a fixed point up or down by `scaleBy_` orders of magnitude. /// The caller MUST ensure the end result matches `DECIMALS` if other /// functions in this library are to work correctly. /// Notably `scaleBy` is a SIGNED integer so scaling down by negative OOMS /// is supported. /// @param a_ Some integer of any scale. /// @param scaleBy_ OOMs to scale `a_` up or down by. This is a SIGNED int8 /// which means it can be negative, and also means that sign extension MUST /// be considered if changing it to another type. /// @param rounding_ Rounding direction as per Open Zeppelin Math. /// @return `a_` rescaled according to `scaleBy_`. function scaleBy( uint256 a_, int8 scaleBy_, Math.Rounding rounding_ ) internal pure returns (uint256) { if (scaleBy_ == 0) { return a_; } else if (scaleBy_ > 0) { return a_.saturatingMul(10 ** uint8(scaleBy_)); } else { uint256 scaleDownBy_; unchecked { scaleDownBy_ = uint8(-1 * scaleBy_); } return scaleDown(a_, scaleDownBy_, rounding_); } } /// Scales `a_` down by a specified number of decimals, rounding in the /// specified direction. Used internally by several other functions in this /// lib. /// @param a_ The number to scale down. /// @param scaleDownBy_ Number of orders of magnitude to scale `a_` down by. /// @param rounding_ Rounding direction as per Open Zeppelin Math. /// @return `a_` scaled down by `scaleDownBy_` and rounded. function scaleDown( uint256 a_, uint256 scaleDownBy_, Math.Rounding rounding_ ) internal pure returns (uint256) { uint256 b_ = 10 ** scaleDownBy_; uint256 scaled_ = a_ / b_; if (rounding_ == Math.Rounding.Up && a_ != scaled_ * b_) { scaled_ += 1; } return scaled_; } /// Fixed point multiplication in native scale decimals. /// Both `a_` and `b_` MUST be `DECIMALS` fixed point decimals. /// @param a_ First term. /// @param b_ Second term. /// @param rounding_ Rounding direction as per Open Zeppelin Math. /// @return `a_` multiplied by `b_` to `DECIMALS` fixed point decimals. function fixedPointMul( uint256 a_, uint256 b_, Math.Rounding rounding_ ) internal pure returns (uint256) { return a_.mulDiv(b_, FP_ONE, rounding_); } /// Fixed point division in native scale decimals. /// Both `a_` and `b_` MUST be `DECIMALS` fixed point decimals. /// @param a_ First term. /// @param b_ Second term. /// @param rounding_ Rounding direction as per Open Zeppelin Math. /// @return `a_` divided by `b_` to `DECIMALS` fixed point decimals. function fixedPointDiv( uint256 a_, uint256 b_, Math.Rounding rounding_ ) internal pure returns (uint256) { return a_.mulDiv(FP_ONE, b_, rounding_); } }
// 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: 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.18; /// @title SaturatingMath /// @notice Sometimes we neither want math operations to error nor wrap around /// on an overflow or underflow. In the case of transferring assets an error /// may cause assets to be locked in an irretrievable state within the erroring /// contract, e.g. due to a tiny rounding/calculation error. We also can't have /// assets underflowing and attempting to approve/transfer "infinity" when we /// wanted "almost or exactly zero" but some calculation bug underflowed zero. /// Ideally there are no calculation mistakes, but in guarding against bugs it /// may be safer pragmatically to saturate arithmatic at the numeric bounds. /// Note that saturating div is not supported because 0/0 is undefined. library SaturatingMath { /// Saturating addition. /// @param a_ First term. /// @param b_ Second term. /// @return Minimum of a_ + b_ and max uint256. function saturatingAdd(uint256 a_, uint256 b_) internal pure returns (uint256) { unchecked { uint256 c_ = a_ + b_; return c_ < a_ ? type(uint256).max : c_; } } /// Saturating subtraction. /// @param a_ Minuend. /// @param b_ Subtrahend. /// @return Maximum of a_ - b_ and 0. function saturatingSub(uint256 a_, uint256 b_) internal pure returns (uint256) { unchecked { return a_ > b_ ? a_ - b_ : 0; } } /// Saturating multiplication. /// @param a_ First term. /// @param b_ Second term. /// @return Minimum of a_ * b_ and max uint256. function saturatingMul(uint256 a_, uint256 b_) internal pure returns (uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being // zero, but the benefit is lost if 'b' is also tested. // https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a_ == 0) return 0; uint256 c_ = a_ * b_; return c_ / a_ != b_ ? type(uint256).max : c_; } } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../type/LibCast.sol"; import "../../type/LibConvert.sol"; import "../../array/LibUint256Array.sol"; import "./bytes32/OpDecode256.sol"; import "./bytes32/OpEncode256.sol"; import "./bytes32/OpExplode32.sol"; import "./chainlink/OpChainlinkOraclePrice.sol"; import "./context/OpContext.sol"; import "./context/OpContextColumnHash.sol"; import "./context/OpContextRow.sol"; import "./context/OpFoldContext.sol"; import "./core/OpCall.sol"; import "./core/OpDebug.sol"; import "./core/OpDoWhile.sol"; import "./core/OpExtern.sol"; import "./core/OpLoopN.sol"; import "./core/OpReadMemory.sol"; import "./crypto/OpHash.sol"; import "./erc20/OpERC20BalanceOf.sol"; import "./erc20/OpERC20TotalSupply.sol"; import "./erc20/snapshot/OpERC20SnapshotBalanceOfAt.sol"; import "./erc20/snapshot/OpERC20SnapshotTotalSupplyAt.sol"; import "./erc721/OpERC721BalanceOf.sol"; import "./erc721/OpERC721OwnerOf.sol"; import "./erc1155/OpERC1155BalanceOf.sol"; import "./erc1155/OpERC1155BalanceOfBatch.sol"; import "./erc5313/OpERC5313Owner.sol"; import "./error/OpEnsure.sol"; import "./evm/OpBlockNumber.sol"; import "./evm/OpTimestamp.sol"; import "./math/fixedPoint/OpFixedPointScale18.sol"; import "./math/fixedPoint/OpFixedPointScale18Div.sol"; import "./math/fixedPoint/OpFixedPointScale18Dynamic.sol"; import "./math/fixedPoint/OpFixedPointScale18Mul.sol"; import "./math/fixedPoint/OpFixedPointScaleBy.sol"; import "./math/fixedPoint/OpFixedPointScaleN.sol"; import "./math/logic/OpAny.sol"; import "./math/logic/OpEagerIf.sol"; import "./math/logic/OpEqualTo.sol"; import "./math/logic/OpEvery.sol"; import "./math/logic/OpGreaterThan.sol"; import "./math/logic/OpIsZero.sol"; import "./math/logic/OpLessThan.sol"; import "./math/prb/OpPRBAvg.sol"; import "./math/prb/OpPRBCeil.sol"; import "./math/prb/OpPRBDiv.sol"; import "./math/prb/OpPRBExp.sol"; import "./math/prb/OpPRBExp2.sol"; import "./math/prb/OpPRBFloor.sol"; import "./math/prb/OpPRBFrac.sol"; import "./math/prb/OpPRBGm.sol"; import "./math/prb/OpPRBInv.sol"; import "./math/prb/OpPRBLn.sol"; import "./math/prb/OpPRBLog10.sol"; import "./math/prb/OpPRBLog2.sol"; import "./math/prb/OpPRBMul.sol"; import "./math/prb/OpPRBPow.sol"; import "./math/prb/OpPRBPowu.sol"; import "./math/prb/OpPRBSqrt.sol"; import "./math/saturating/OpSaturatingAdd.sol"; import "./math/saturating/OpSaturatingMul.sol"; import "./math/saturating/OpSaturatingSub.sol"; import "./math/OpAdd.sol"; import "./math/OpDiv.sol"; import "./math/OpExp.sol"; import "./math/OpMax.sol"; import "./math/OpMin.sol"; import "./math/OpMod.sol"; import "./math/OpMul.sol"; import "./math/OpSub.sol"; import "./rain/IOrderBookV1/OpIOrderBookV1VaultBalance.sol"; import "./rain/ISaleV2/OpISaleV2RemainingTokenInventory.sol"; import "./rain/ISaleV2/OpISaleV2Reserve.sol"; import "./rain/ISaleV2/OpISaleV2SaleStatus.sol"; import "./rain/ISaleV2/OpISaleV2Token.sol"; import "./rain/ISaleV2/OpISaleV2TotalReserveReceived.sol"; import "./rain/IVerifyV1/OpIVerifyV1AccountStatusAtTime.sol"; import "./store/OpGet.sol"; import "./store/OpSet.sol"; import "./tier/OpITierV2Report.sol"; import "./tier/OpITierV2ReportTimeForTier.sol"; import "./tier/OpSaturatingDiff.sol"; import "./tier/OpSelectLte.sol"; import "./tier/OpUpdateTimesForTierRange.sol"; /// Thrown when a dynamic length array is NOT 1 more than a fixed length array. /// Should never happen outside a major breaking change to memory layouts. error BadDynamicLength(uint256 dynamicLength, uint256 standardOpsLength); /// @dev Number of ops currently provided by `AllStandardOps`. uint256 constant ALL_STANDARD_OPS_LENGTH = 81; /// @title AllStandardOps /// @notice Every opcode available from the core repository laid out as a single /// array to easily build function pointers for `IInterpreterV1`. library AllStandardOps { using LibCast for uint256; using LibCast for function(uint256) pure returns (uint256); using LibCast for function(InterpreterState memory, uint256, StackPointer) view returns (StackPointer); using LibCast for function(InterpreterState memory, uint256, StackPointer) pure returns (StackPointer); using LibCast for function(InterpreterState memory, uint256, StackPointer) view returns (StackPointer)[]; using AllStandardOps for function( IntegrityCheckState memory, Operand, StackPointer ) view returns (StackPointer)[ALL_STANDARD_OPS_LENGTH + 1]; using AllStandardOps for function( InterpreterState memory, Operand, StackPointer ) view returns (StackPointer)[ALL_STANDARD_OPS_LENGTH + 1]; using AllStandardOps for uint256[ALL_STANDARD_OPS_LENGTH + 1]; using LibUint256Array for uint256[]; using LibConvert for uint256[]; using LibCast for uint256[]; using LibCast for function( IntegrityCheckState memory, Operand, StackPointer ) view returns (StackPointer); using LibCast for function( IntegrityCheckState memory, Operand, StackPointer ) pure returns (StackPointer); using LibCast for function( IntegrityCheckState memory, Operand, StackPointer ) view returns (StackPointer)[]; using LibCast for function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer)[]; /// An oddly specific length conversion between a fixed and dynamic `uint256` /// array. This is useful for the purpose of building metadata for bounds /// checks and dispatch of all the standard ops provided by `Rainterpreter`. /// The cast will fail if the length of the dynamic array doesn't match the /// first item of the fixed array; it relies on differences in memory /// layout in Solidity that MAY change in the future. The rollback guards /// against changes in Solidity memory layout silently breaking this cast. /// @param fixed_ The fixed size `uint256` array to cast to a dynamic /// `uint256` array. Specifically the size is fixed to match the number of /// standard ops. /// @param dynamic_ The dynamic `uint256` array with length of the standard /// ops. function asUint256Array( function(IntegrityCheckState memory, Operand, StackPointer) view returns (StackPointer)[ALL_STANDARD_OPS_LENGTH + 1] memory fixed_ ) internal pure returns (uint256[] memory dynamic_) { assembly ("memory-safe") { dynamic_ := fixed_ } if (dynamic_.length != ALL_STANDARD_OPS_LENGTH) { revert BadDynamicLength(dynamic_.length, ALL_STANDARD_OPS_LENGTH); } } /// An oddly specific conversion between a fixed and dynamic `uint256` array. /// This is useful for the purpose of building function pointers for the /// runtime dispatch of all the standard ops provided by `Rainterpreter`. /// The cast will fail if the length of the dynamic array doesn't match the /// first item of the fixed array; it relies on differences in memory /// layout in Solidity that MAY change in the future. The rollback guards /// against changes in Solidity memory layout silently breaking this cast. /// @param fixed_ The fixed size `uint256` array to cast to a dynamic /// `uint256` array. Specifically the size is fixed to match the number of /// standard ops. /// @param dynamic_ The dynamic `uint256` array with length of the standard /// ops. function asUint256Array( function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer)[ALL_STANDARD_OPS_LENGTH + 1] memory fixed_ ) internal pure returns (uint256[] memory dynamic_) { assembly ("memory-safe") { dynamic_ := fixed_ } if (dynamic_.length != ALL_STANDARD_OPS_LENGTH) { revert BadDynamicLength(dynamic_.length, ALL_STANDARD_OPS_LENGTH); } } function integrityFunctionPointers( function(IntegrityCheckState memory, Operand, StackPointer) view returns (StackPointer)[] memory locals_ ) internal pure returns ( function(IntegrityCheckState memory, Operand, StackPointer) view returns (StackPointer)[] memory ) { unchecked { function(IntegrityCheckState memory, Operand, StackPointer) view returns (StackPointer)[ALL_STANDARD_OPS_LENGTH + 1] memory pointersFixed_ = [ ALL_STANDARD_OPS_LENGTH.asIntegrityFunctionPointer(), OpDecode256.integrity, OpEncode256.integrity, OpExplode32.integrity, OpChainlinkOraclePrice.integrity, OpContext.integrity, OpContextColumnHash.integrity, OpContextRow.integrity, OpFoldContext.integrity, OpCall.integrity, OpDebug.integrity, OpDoWhile.integrity, OpExtern.integrity, OpLoopN.integrity, OpReadMemory.integrity, OpHash.integrity, OpERC1155BalanceOf.integrity, OpERC1155BalanceOfBatch.integrity, OpERC20BalanceOf.integrity, OpERC20TotalSupply.integrity, OpERC20SnapshotBalanceOfAt.integrity, OpERC20SnapshotTotalSupplyAt.integrity, OpERC5313Owner.integrity, OpERC721BalanceOf.integrity, OpERC721OwnerOf.integrity, OpEnsure.integrity, OpBlockNumber.integrity, OpTimestamp.integrity, OpAdd.integrity, OpDiv.integrity, OpExp.integrity, OpMax.integrity, OpMin.integrity, OpMod.integrity, OpMul.integrity, OpSub.integrity, OpFixedPointScale18.integrity, OpFixedPointScale18Div.integrity, OpFixedPointScale18Dynamic.integrity, OpFixedPointScale18Mul.integrity, OpFixedPointScaleBy.integrity, OpFixedPointScaleN.integrity, OpAny.integrity, OpEagerIf.integrity, OpEqualTo.integrity, OpEvery.integrity, OpGreaterThan.integrity, OpIsZero.integrity, OpLessThan.integrity, OpPRBAvg.integrity, OpPRBCeil.integrity, OpPRBDiv.integrity, OpPRBExp.integrity, OpPRBExp2.integrity, OpPRBFloor.integrity, OpPRBFrac.integrity, OpPRBGm.integrity, OpPRBInv.integrity, OpPRBLn.integrity, OpPRBLog10.integrity, OpPRBLog2.integrity, OpPRBMul.integrity, OpPRBPow.integrity, OpPRBPowu.integrity, OpPRBSqrt.integrity, OpSaturatingAdd.integrity, OpSaturatingMul.integrity, OpSaturatingSub.integrity, OpIOrderBookV1VaultBalance.integrity, OpISaleV2RemainingTokenInventory.integrity, OpISaleV2Reserve.integrity, OpISaleV2SaleStatus.integrity, OpISaleV2Token.integrity, OpISaleV2TotalReserveReceived.integrity, OpIVerifyV1AccountStatusAtTime.integrity, // Store OpGet.integrity, OpSet.integrity, OpITierV2Report.integrity, OpITierV2ReportTimeForTier.integrity, OpSaturatingDiff.integrity, OpSelectLte.integrity, OpUpdateTimesForTierRange.integrity ]; uint256[] memory pointers_ = pointersFixed_.asUint256Array(); pointers_.extend(locals_.asUint256Array()); return pointers_.asIntegrityPointers(); } } function opcodeFunctionPointers( function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer)[] memory locals_ ) internal pure returns ( function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer)[] memory opcodeFunctionPointers_ ) { unchecked { function(InterpreterState memory, Operand, StackPointer) view returns (StackPointer)[ALL_STANDARD_OPS_LENGTH + 1] memory pointersFixed_ = [ ALL_STANDARD_OPS_LENGTH.asOpFunctionPointer(), OpDecode256.run, OpEncode256.run, OpExplode32.run, OpChainlinkOraclePrice.run, OpContext.run, OpContextColumnHash.run, OpContextRow.run, OpFoldContext.run, OpCall.run, // 1.001kb OpDebug.run, OpDoWhile.run, OpExtern.intern, OpLoopN.run, OpReadMemory.run, OpHash.run, OpERC1155BalanceOf.run, OpERC1155BalanceOfBatch.run, OpERC20BalanceOf.run, OpERC20TotalSupply.run, OpERC20SnapshotBalanceOfAt.run, OpERC20SnapshotTotalSupplyAt.run, OpERC5313Owner.run, OpERC721BalanceOf.run, OpERC721OwnerOf.run, OpEnsure.run, OpBlockNumber.run, OpTimestamp.run, OpAdd.run, OpDiv.run, OpExp.run, OpMax.run, OpMin.run, OpMod.run, OpMul.run, OpSub.run, OpFixedPointScale18.run, OpFixedPointScale18Div.run, OpFixedPointScale18Dynamic.run, OpFixedPointScale18Mul.run, OpFixedPointScaleBy.run, OpFixedPointScaleN.run, OpAny.run, OpEagerIf.run, OpEqualTo.run, OpEvery.run, OpGreaterThan.run, OpIsZero.run, OpLessThan.run, OpPRBAvg.run, OpPRBCeil.run, OpPRBDiv.run, OpPRBExp.run, OpPRBExp2.run, OpPRBFloor.run, OpPRBFrac.run, OpPRBGm.run, OpPRBInv.run, OpPRBLn.run, // 3.683kb OpPRBLog10.run, OpPRBLog2.run, OpPRBMul.run, OpPRBPow.run, OpPRBPowu.run, OpPRBSqrt.run, OpSaturatingAdd.run, OpSaturatingMul.run, OpSaturatingSub.run, OpIOrderBookV1VaultBalance.run, OpISaleV2RemainingTokenInventory.run, OpISaleV2Reserve.run, OpISaleV2SaleStatus.run, OpISaleV2Token.run, OpISaleV2TotalReserveReceived.run, OpIVerifyV1AccountStatusAtTime.run, // Store OpGet.run, OpSet.run, OpITierV2Report.run, OpITierV2ReportTimeForTier.run, OpSaturatingDiff.run, OpSelectLte.run, OpUpdateTimesForTierRange.run ]; uint256[] memory pointers_ = pointersFixed_.asUint256Array(); pointers_.extend(locals_.asUint256Array()); opcodeFunctionPointers_ = pointers_.asOpcodeFunctionPointers(); } } }
// 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/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.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: 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: 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: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "sol.lib.binmaskflag/Binary.sol"; import "./OpEncode256.sol"; /// @title OpDecode256 /// @notice Opcode for decoding binary data from a 256 bit value that was encoded /// with OpEncode256. library OpDecode256 { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( Operand operand_, uint256 source_ ) internal pure returns (uint256) { unchecked { uint256 startBit_ = (Operand.unwrap(operand_) >> 8) & MASK_8BIT; uint256 length_ = Operand.unwrap(operand_) & MASK_8BIT; // Build a bitmask of desired length. Max length is uint8 max which // is 255. A 256 length doesn't really make sense as that isn't an // encoding anyway, it's just the source_ verbatim. uint256 mask_ = (2 ** length_ - 1); return (source_ >> startBit_) & mask_; } } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { unchecked { uint256 startBit_ = (Operand.unwrap(operand_) >> 8) & MASK_8BIT; uint256 length_ = Operand.unwrap(operand_) & MASK_8BIT; if (startBit_ + length_ > 256) { revert TruncatedEncoding(startBit_, length_); } return integrityCheckState_.applyFn(stackTop_, f); } } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "sol.lib.binmaskflag/Binary.sol"; /// Thrown during integrity check when the encoding is truncated due to the end /// bit being over 256. /// @param startBit The start of the OOB encoding. /// @param length The length of the OOB encoding. error TruncatedEncoding(uint256 startBit, uint256 length); /// @title OpEncode256 /// @notice Opcode for encoding binary data into a 256 bit value. library OpEncode256 { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( Operand operand_, uint256 source_, uint256 target_ ) internal pure returns (uint256) { unchecked { uint256 startBit_ = (Operand.unwrap(operand_) >> 8) & MASK_8BIT; uint256 length_ = Operand.unwrap(operand_) & MASK_8BIT; // Build a bitmask of desired length. Max length is uint8 max which // is 255. A 256 length doesn't really make sense as that isn't an // encoding anyway, it's just the source_ verbatim. uint256 mask_ = (2 ** length_ - 1); return // Punch a mask sized hole in target. (target_ & ~(mask_ << startBit_)) | // Fill the hole with masked bytes from source. ((source_ & mask_) << startBit_); } } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { unchecked { uint256 startBit_ = (Operand.unwrap(operand_) >> 8) & MASK_8BIT; uint256 length_ = Operand.unwrap(operand_) & MASK_8BIT; if (startBit_ + length_ > 256) { revert TruncatedEncoding(startBit_, length_); } return integrityCheckState_.applyFn(stackTop_, f); } } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../../array/LibUint256Array.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpExplode /// @notice Opcode for exploding a single value into 8x 32 bit integers. library OpExplode32 { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.push(integrityCheckState_.pop(stackTop_), 8); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { (StackPointer location_, uint256 i_) = stackTop_.pop(); uint256 mask_ = uint256(type(uint32).max); return location_.push( i_ & mask_, (i_ >> 0x20) & mask_, (i_ >> 0x40) & mask_, (i_ >> 0x60) & mask_, (i_ >> 0x80) & mask_, (i_ >> 0xA0) & mask_, (i_ >> 0xC0) & mask_, (i_ >> 0xE0) & mask_ ); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {LibChainlink} from "../../../chainlink/LibChainlink.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpChainlinkOraclePrice /// @notice Opcode for chainlink oracle prices. library OpChainlinkOraclePrice { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 feed_, uint256 staleAfter_ ) internal view returns (uint256) { return LibChainlink.price(address(uint160(feed_)), staleAfter_); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; import "../math/LibFixedPointMath.sol"; /// Thrown if a price is zero or negative as this is probably not anticipated or /// useful for most users of a price feed. Of course there are use cases where /// zero or negative _oracle values_ in general are useful, such as negative /// temperatures from a thermometer, but these are unlikely to be useful _prices_ /// for assets. Zero value prices are likely to result in division by zero /// downstream or giving away assets for free, negative price values could result /// in even weirder behaviour due to token amounts being `uint256` and the /// subtleties of signed vs. unsigned integer conversions. /// @param price The price that is not a positive integer. error NotPosIntPrice(int256 price); /// Thrown when the updatedAt time from the Chainlink oracle is more than /// staleAfter seconds prior to the current block timestamp. Prevents stale /// prices from being used within the constraints set by the caller. /// @param updatedAt The latest time the oracle was updated according to the /// oracle. /// @param staleAfter The maximum number of seconds the caller allows between /// the block timestamp and the updated time. error StalePrice(uint256 updatedAt, uint256 staleAfter); library LibChainlink { using SafeCast for int256; using LibFixedPointMath for uint256; function price( address feed_, uint256 staleAfter_ ) internal view returns (uint256) { (, int256 answer_, , uint256 updatedAt_, ) = AggregatorV3Interface( feed_ ).latestRoundData(); if (answer_ <= 0) { revert NotPosIntPrice(answer_); } // Checked time comparison ensures no updates from the future as that // would overflow, and no stale prices. // solhint-disable-next-line not-rely-on-time if (block.timestamp - updatedAt_ > staleAfter_) { revert StalePrice(updatedAt_, staleAfter_); } // Safely cast the answer to uint256 and scale it to 18 decimal FP. // We round up because reporting a non-zero price as zero can cause // issues downstream. This rounding up only happens if the values are // being scaled down. return answer_.toUint256().scale18( AggregatorV3Interface(feed_).decimals(), Math.Rounding.Up ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "sol.lib.binmaskflag/Binary.sol"; /// @title OpContext /// @notice Opcode for stacking from the context. Context requires slightly /// different handling to other memory reads as it is working with data that /// is provided at runtime from the calling contract on a per-eval basis so /// cannot be predicted at deploy time. library OpContext { using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; using LibIntegrityCheck for IntegrityCheckState; /// Interpreter integrity logic. /// Context pushes a single value to the stack from the context array. function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { // Note that a expression with context can error at runtime due to OOB // reads that we don't know about here. return integrityCheckState_.push(stackTop_); } /// Stack a value from the context WITH OOB checks from solidity. /// The bounds checks are done at runtime because context MAY be provided /// by the end user with arbitrary length. function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { // The indexing syntax here enforces OOB checks at runtime. return stackTop_.push( state_.context[Operand.unwrap(operand_) >> 8][ Operand.unwrap(operand_) & MASK_8BIT ] ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../deploy/LibIntegrityCheck.sol"; import "../../run/LibInterpreterState.sol"; /// @title OpContextColumnHash /// @notice Hashes a single context column. Useful for snapshotting values /// provided by users, whether signed by a third party or provided by the caller. /// More gas efficient than individually snapshotting each context row and /// handles dynamic length columns without an expensive fold operation. library OpContextColumnHash { using LibIntegrityCheck for IntegrityCheckState; using LibStackPointer for StackPointer; function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { // Note that a expression with context can error at runtime due to OOB // reads that we don't know about here. return integrityCheckState_.push(stackTop_); } function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return stackTop_.push( uint256( keccak256( // Using encodePacked here instead of encode so that we // really only hash the values of the column and not the // leading length bytes. // Typically we would NOT use encodePacked for a dynamic // type due to the potential for accidentally introducing // hash collisions between multiple adjacent dynamic // types, e.g. "ab" + "c" and "a" + "bc". In this case we // are producing hashes over a single list at a time, and // hash("ab") + hash("c") and hash("a") + hash("bc") do // not collide, so there is no ambiguity even with many // lists being hashed this way. abi.encodePacked( state_.context[Operand.unwrap(operand_)] ) ) ) ); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "sol.lib.binmaskflag/Binary.sol"; /// @title OpContextRow /// @notice Opcode for stacking a dynamic row from the context. Context requires /// slightly different handling to other memory reads as it is working with data /// that is provided at runtime. `OpContextRow` works exactly like `OpContext` /// but the row is provided from the stack instead of the operand. We rely on /// Solidity OOB checks at runtime to enforce that the index from the stack is /// within bounds at runtime. As we do NOT know statically which row will be read /// the context reads is set to the entire column. library OpContextRow { using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; using LibIntegrityCheck for IntegrityCheckState; /// Interpreter integrity logic. /// Context pushes a single value to the stack from memory. function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { // Note that a expression with context can error at runtime due to OOB // reads that we don't know about here. function(uint256) internal pure returns (uint256) fn_; return integrityCheckState_.applyFn(stackTop_, fn_); } /// Stack a value from the context WITH OOB checks from solidity. /// The bounds checks are done at runtime because context MAY be provided /// by the end user with arbitrary length. function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { // The indexing syntax here enforces OOB checks at runtime. (StackPointer location_, uint256 row_) = stackTop_.pop(); location_.set(state_.context[Operand.unwrap(operand_)][row_]); return stackTop_; } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "../core/OpCall.sol"; /// @title OpFoldContext /// Folds over columns of context from their start to end. Expressions do not /// have a good way of handling dynamic lengths of things, and that is /// intentional to avoid end users having to write out looping constructs of the /// form `i = 0; i < length; i++` is is so tedious and error prone in software /// development generally. It is very easy to implement "off by one" errors in /// this form, and requires sourcing a length from somewhere. This opcode exposes /// a pretty typical fold as found elsewhere in functional programming. A start /// column and width of columns can be specified, the rows will be iterated and /// pushed to the stack on top of any additional inputs specified by the /// expression. The additional inputs are the accumulators and so the number of /// outputs in the called source needs to match the number of accumulator inputs. library OpFoldContext { using LibIntegrityCheck for IntegrityCheckState; using LibStackPointer for StackPointer; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { unchecked { uint256 sourceIndex_ = Operand.unwrap(operand_) & MASK_4BIT; // We don't use the column for anything in the integrity check. // uint256 column_ = (Operand.unwrap(operand_) >> 4) & MASK_4BIT; uint256 width_ = (Operand.unwrap(operand_) >> 8) & MASK_4BIT; uint256 inputs_ = Operand.unwrap(operand_) >> 12; uint256 callInputs_ = width_ + inputs_; // Outputs for call is the same as the inputs. Operand callOperand_ = Operand.wrap( (sourceIndex_ << 8) | (inputs_ << 4) | callInputs_ ); // First the width of the context columns being folded is pushed to // the stack. Ignore the highwater here as `OpCall.integrity` has its // own internal highwater handling over all its inputs and outputs. stackTop_ = integrityCheckState_.pushIgnoreHighwater( stackTop_, width_ ); // Then we loop over call taking the width and extra inputs, then // returning the same number of outputs as non-width inputs. return OpCall.integrity(integrityCheckState_, callOperand_, stackTop_); } } function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { unchecked { uint256 sourceIndex_ = Operand.unwrap(operand_) & MASK_4BIT; uint256 column_ = (Operand.unwrap(operand_) >> 4) & MASK_4BIT; uint256 width_ = (Operand.unwrap(operand_) >> 8) & MASK_4BIT; uint256 inputs_ = Operand.unwrap(operand_) >> 12; // Call will take the width of the context rows being copied and the // base inputs that will be the accumulators of the fold. uint256 callInputs_ = width_ + inputs_; // Fold over the entire context. This will error with an OOB index // if the context columns are not of the same length. for (uint256 i_ = 0; i_ < state_.context[column_].length; i_++) { // Push the width of the context columns onto the stack as rows. for (uint256 j_ = 0; j_ < width_; j_++) { stackTop_ = stackTop_.push( state_.context[column_ + j_][i_] ); } // The outputs of call are the same as the base inputs, this is // similar to `OpDoWhile` so that we don't have to care how many // iterations there are in order to calculate the stack. Operand callOperand_ = Operand.wrap( (sourceIndex_ << 8) | (inputs_ << 4) | callInputs_ ); stackTop_ = OpCall.run(state_, callOperand_, stackTop_); } return stackTop_; } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../../array/LibUint256Array.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "sol.lib.binmaskflag/Binary.sol"; /// @title OpCall /// @notice Opcode for calling eval with a new scope. The construction of this /// scope is split across integrity and runtime responsibilities. When the /// integrity checks are done the expression being called has all its integrity /// logic run, recursively if needed. The integrity checks are run against the /// integrity state as it is but with the stack bottom set below the inputs to /// the called source. This ensures that the sub-integrity checks do not /// underflow what they perceive as a fresh stack, and it ensures that we set the /// stack length long enough to cover all sub-executions as a single array in /// memory. At runtime we trust the integrity checks have allocated enough runway /// in the stack for all our recursive sub-calls so we simply move the stack /// bottom in the state below the inputs during the call and move it back to /// where it was after the call. Notably this means that reading from the stack /// in the called source will 0 index from the first input, NOT the bottom of /// the calling stack. library OpCall { using LibIntegrityCheck for IntegrityCheckState; using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; using LibUint256Array for uint256; /// Interpreter integrity logic. /// The basic movements on the outer stack are to pop the inputs and push the /// outputs, but the called source doesn't have access to a separately /// allocated region of memory. There's only a single shared memory /// allocation for all executions and sub-executions, so we recursively run /// integrity checks on the called source relative to the current stack /// position. /// @param integrityCheckState_ The state of the current integrity check. /// @param operand_ The operand associated with this call. /// @param stackTop_ The current stack top within the integrity check. /// @return stackTopAfter_ The stack top after the call movements are applied. function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { // Unpack the operand to get IO and the source to be called. uint256 inputs_ = Operand.unwrap(operand_) & MASK_4BIT; uint256 outputs_ = (Operand.unwrap(operand_) >> 4) & MASK_4BIT; SourceIndex callSourceIndex_ = SourceIndex.wrap( Operand.unwrap(operand_) >> 8 ); // Remember the outer stack bottom and highwater. StackPointer stackBottom_ = integrityCheckState_.stackBottom; StackPointer stackHighwater_ = integrityCheckState_.stackHighwater; // Set the inner stack bottom to below the inputs and highwater to // protect the inputs from being popped internally. integrityCheckState_.stackBottom = integrityCheckState_.pop( stackTop_, inputs_ ); integrityCheckState_.stackHighwater = stackTop_.down(); // Ensure the integrity of the inner source on the current state using // the stack top above the inputs as the starting stack top. // Contraints namespace is irrelevant here. integrityCheckState_.ensureIntegrity( callSourceIndex_, stackTop_, outputs_ ); // Reinstate the original highwater before handling outputs as single // outputs can be nested but multioutput will move the highwater. integrityCheckState_.stackHighwater = stackHighwater_; // The outer stack top will move above the outputs relative to the inner // stack bottom. At runtime any values that are not outputs will be // removed so they do not need to be accounted for here. stackTop_ = integrityCheckState_.push( integrityCheckState_.stackBottom, outputs_ ); // Reinstate the outer stack bottom. integrityCheckState_.stackBottom = stackBottom_; return stackTop_; } /// Call eval with a new scope. /// @param state_ The state of the current evaluation. /// @param operand_ The operand associated with this call. /// @param stackTop_ The current stack top within the evaluation. /// @return stackTopAfter_ The stack top after the call is evaluated. function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { // Unpack the operand to get IO and the source to be called. uint256 inputs_ = Operand.unwrap(operand_) & MASK_4BIT; uint256 outputs_ = (Operand.unwrap(operand_) >> 4) & MASK_4BIT; SourceIndex callSourceIndex_ = SourceIndex.wrap( Operand.unwrap(operand_) >> 8 ); // Remember the outer stack bottom. StackPointer stackBottom_ = state_.stackBottom; // Set the inner stack bottom to below the inputs. state_.stackBottom = stackTop_.down(inputs_); // Eval the source from the operand on the current state using the stack // top above the inputs as the starting stack top. The final stack top // is where we will read outputs from below. StackPointer stackTopEval_ = state_.eval(callSourceIndex_, stackTop_); // Normalize the inner final stack so that it contains only the outputs // starting from the inner stack bottom. LibUint256Array.unsafeCopyValuesTo( StackPointer.unwrap(stackTopEval_.down(outputs_)), StackPointer.unwrap(state_.stackBottom), outputs_ ); // The outer stack top should now point above the outputs. stackTopAfter_ = state_.stackBottom.up(outputs_); // The outer stack bottom needs to be reinstated as it was before eval. state_.stackBottom = stackBottom_; } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpDebug /// @notice Opcode for debugging state. Uses the standard debugging logic from /// InterpreterState.debug. library OpDebug { using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; /// Interpreter integrity for debug. /// Debug doesn't modify the stack. function integrity( IntegrityCheckState memory, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { // Try to build a debug style from the operand to ensure we can enumerate // it at runtime. DebugStyle(Operand.unwrap(operand_)); return stackTop_; } /// Debug the current state. function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { DebugStyle debugStyle_ = DebugStyle(Operand.unwrap(operand_)); state_.debug(stackTop_, debugStyle_); return stackTop_; } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "./OpCall.sol"; /// More inputs were encoded in the operand than can be dispatched internally by /// a do-while loop. error DoWhileMaxInputs(uint256 inputs); /// @title OpDoWhile /// @notice Opcode for looping while the stack top is nonzero. As we pre-allocate /// all the memory for execution during integrity checks we have an apparent /// contradiction here. If we do not know how many times the loop will run then /// we cannot calculate the final stack height or intermediate pops and pushes. /// To solve this we simply wrap `OpCall` which already has fixed inputs and /// outputs and enforce that the outputs of each iteration is 1 more than the /// inputs. We then consume the extra output as the condition for the decision /// to loop again, thus the outputs = inputs for every iteration. If the stack /// height does not change between iterations we do not care how many times we /// loop (although the user paying gas might). library OpDoWhile { using LibIntegrityCheck for IntegrityCheckState; using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; /// Interpreter integrity for do while. /// The loop itself pops a single value from the stack to determine whether /// it should run another iteration of the loop. The source called by the /// loop must then put a value back on the stack in the same position to /// either continue or break the loop. function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { unchecked { uint256 inputs_ = Operand.unwrap(operand_) & MASK_8BIT; /// We need outputs to be _larger than_ inputs so inputs must be /// _strictly less than_ the max value possible in 4 bits or outputs /// will overflow. if (inputs_ >= MASK_4BIT) { revert DoWhileMaxInputs(inputs_); } uint256 outputs_ = inputs_ + 1; Operand callOperand_ = Operand.wrap( Operand.unwrap(operand_) | (outputs_ << 4) ); // Stack height changes are deterministic so if we call once we've // called a thousand times. Also we pop one output off the result of // the call to check the while condition. // // We IGNORE THE HIGHWATER on the pop here because we always set the // outputs to inputs + 1 and the highwater check can error due to // trying to pop a multioutput return value which is normally // disallowed but is required by the internal runtime behaviour. return integrityCheckState_.popIgnoreHighwater( OpCall.integrity( integrityCheckState_, callOperand_, stackTop_ ), 1 ); } } /// Loop the stack while the stack top is true. function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { unchecked { uint256 inputs_ = Operand.unwrap(operand_) & MASK_8BIT; uint256 outputs_ = inputs_ + 1; Operand callOperand_ = Operand.wrap( Operand.unwrap(operand_) | (outputs_ << 4) ); uint256 do_; (stackTop_, do_) = stackTop_.pop(); while (do_ > 0) { stackTop_ = OpCall.run(state_, callOperand_, stackTop_); (stackTop_, do_) = stackTop_.pop(); } return stackTop_; } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "sol.lib.binmaskflag/Binary.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "./OpReadMemory.sol"; import "../../extern/LibExtern.sol"; import "../../run/LibStackPointer.sol"; /// Thrown when the length of results from an extern don't match what the operand /// defines. This is bad because it implies our integrity check miscalculated the /// stack which is undefined behaviour. /// @param expected The length we expected based on the operand. /// @param actual The length that was returned from the extern. error BadExternResultsLength(uint256 expected, uint256 actual); library OpExtern { using LibIntegrityCheck for IntegrityCheckState; using LibStackPointer for StackPointer; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { uint256 inputs_ = Operand.unwrap(operand_) & MASK_5BIT; uint256 outputs_ = (Operand.unwrap(operand_) >> 5) & MASK_5BIT; uint256 offset_ = Operand.unwrap(operand_) >> 10; if (offset_ >= integrityCheckState_.constantsLength) { revert OutOfBoundsConstantsRead( integrityCheckState_.constantsLength, offset_ ); } return integrityCheckState_.push( integrityCheckState_.pop(stackTop_, inputs_), outputs_ ); } function intern( InterpreterState memory interpreterState_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { IInterpreterExternV1 interpreterExtern_; ExternDispatch externDispatch_; uint256 head_; uint256[] memory tail_; { uint256 inputs_ = Operand.unwrap(operand_) & MASK_5BIT; uint256 offset_ = (Operand.unwrap(operand_) >> 10); // Mirrors constant opcode. EncodedExternDispatch encodedDispatch_; assembly ("memory-safe") { encodedDispatch_ := mload( add(mload(add(interpreterState_, 0x20)), mul(0x20, offset_)) ) } (interpreterExtern_, externDispatch_) = LibExtern.decode( encodedDispatch_ ); (head_, tail_) = stackTop_.list(inputs_); stackTop_ = stackTop_.down(inputs_).down().push(head_); } { uint256 outputs_ = (Operand.unwrap(operand_) >> 5) & MASK_5BIT; uint256[] memory results_ = interpreterExtern_.extern( externDispatch_, tail_ ); if (results_.length != outputs_) { revert BadExternResultsLength(outputs_, results_.length); } stackTop_ = stackTop_.push(results_); } return stackTop_; } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "sol.lib.binmaskflag/Binary.sol"; import {MathUpgradeable as Math} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; /// Thrown when a stack read index is outside the current stack top. error OutOfBoundsStackRead(uint256 stackTopIndex, uint256 stackRead); /// Thrown when a constant read index is outside the constants array. error OutOfBoundsConstantsRead(uint256 constantsLength, uint256 constantsRead); /// @dev Read a value from the stack. uint256 constant OPERAND_MEMORY_TYPE_STACK = 0; /// @dev Read a value from the constants. uint256 constant OPERAND_MEMORY_TYPE_CONSTANT = 1; /// @title OpReadMemory /// @notice Opcode for stacking from the interpreter state in memory. This can /// either be copying values from anywhere in the stack or from the constants /// array by index. library OpReadMemory { using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; using LibIntegrityCheck for IntegrityCheckState; using Math for uint256; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { uint256 type_ = Operand.unwrap(operand_) & MASK_1BIT; uint256 offset_ = Operand.unwrap(operand_) >> 1; if (type_ == OPERAND_MEMORY_TYPE_STACK) { uint256 stackTopIndex_ = integrityCheckState_.stackBottom.toIndex( stackTop_ ); if (offset_ >= stackTopIndex_) { revert OutOfBoundsStackRead(stackTopIndex_, offset_); } // Ensure that highwater is moved past any stack item that we // read so that copied values cannot later be consumed. integrityCheckState_.stackHighwater = StackPointer.wrap( StackPointer.unwrap(integrityCheckState_.stackHighwater).max( StackPointer.unwrap( integrityCheckState_.stackBottom.up(offset_) ) ) ); } else { if (offset_ >= integrityCheckState_.constantsLength) { revert OutOfBoundsConstantsRead( integrityCheckState_.constantsLength, offset_ ); } } return integrityCheckState_.push(stackTop_); } function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { unchecked { uint256 type_ = Operand.unwrap(operand_) & MASK_1BIT; uint256 offset_ = Operand.unwrap(operand_) >> 1; assembly ("memory-safe") { mstore( stackTop_, mload( add( mload(add(state_, mul(0x20, type_))), mul(0x20, offset_) ) ) ) } return StackPointer.wrap(StackPointer.unwrap(stackTop_) + 0x20); } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "./IInterpreterExternV1.sol"; library LibExtern { function decode( EncodedExternDispatch dispatch_ ) internal pure returns (IInterpreterExternV1, ExternDispatch) { return ( IInterpreterExternV1( address(uint160(EncodedExternDispatch.unwrap(dispatch_))) ), ExternDispatch.wrap(EncodedExternDispatch.unwrap(dispatch_) >> 160) ); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; type EncodedExternDispatch is uint256; type ExternDispatch is uint256; /// @title IInterpreterExternV1 /// Handle a single dispatch from some calling contract with an array of /// inputs and array of outputs. Ostensibly useful to build "word packs" for /// `IInterpreterV1` so that less frequently used words can be provided in /// a less efficient format, but without bloating the base interpreter in /// terms of code size. Effectively allows unlimited words to exist as externs /// alongside interpreters. interface IInterpreterExternV1 { /// Handles a single dispatch. /// @param dispatch_ Encoded information about the extern to dispatch. /// Analogous to the opcode/operand in the interpreter. /// @param inputs_ The array of inputs for the dispatched logic. /// @return outputs_ The result of the dispatched logic. function extern( ExternDispatch dispatch_, uint256[] memory inputs_ ) external view returns (uint256[] memory outputs_); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "./OpCall.sol"; /// Thrown if there are fewer outputs than inputs which is currently unsupported. error InsufficientLoopOutputs(uint256 inputs, uint256 outputs); /// @title OpLoopN /// @notice Opcode for looping a static number of times. A thin wrapper around /// `OpCall` with the 4 high bits as a number of times to loop. Each iteration /// will use the outputs of the previous iteration as its inputs so the inputs /// to call must be greater or equal to the outputs. If the outputs exceed the /// inputs then each subsequent call will take as many inputs as it needs from /// the top of the intermediate stack. The net outputs to the stack will include /// all the intermediate excess outputs as: /// `outputs + (inputs - outputs) * n` library OpLoopN { using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { unchecked { uint256 n_ = Operand.unwrap(operand_) >> 12; uint256 inputs_ = Operand.unwrap(operand_) & MASK_4BIT; uint256 outputs_ = (Operand.unwrap(operand_) >> 4) & MASK_4BIT; if (outputs_ < inputs_) { revert InsufficientLoopOutputs(inputs_, outputs_); } Operand callOperand_ = Operand.wrap( Operand.unwrap(operand_) & MASK_12BIT ); StackPointer highwater_ = integrityCheckState_.stackHighwater; for (uint256 i_ = 0; i_ < n_; i_++) { // Ignore intermediate highwaters because call will set it past // the inputs and then the outputs each time. integrityCheckState_.stackHighwater = highwater_; stackTop_ = OpCall.integrity( integrityCheckState_, callOperand_, stackTop_ ); } return stackTop_; } } function run( InterpreterState memory state_, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { uint256 n_ = Operand.unwrap(operand_) >> 12; Operand callOperand_ = Operand.wrap( Operand.unwrap(operand_) & MASK_12BIT ); for (uint256 i_ = 0; i_ < n_; i_++) { stackTop_ = OpCall.run(state_, callOperand_, stackTop_); } return stackTop_; } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../run/LibStackPointer.sol"; import "../../../array/LibUint256Array.sol"; import "../../../type/LibCast.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpHash /// @notice Opcode for hashing a list of values. library OpHash { using LibStackPointer for StackPointer; using LibCast for uint256[]; using LibIntegrityCheck for IntegrityCheckState; function f(uint256[] memory values_) internal pure returns (uint256) { return uint256(keccak256(abi.encodePacked(values_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn( stackTop_, f, Operand.unwrap(operand_) ); } // Stack the return of `balanceOfBatch`. // Operand will be the length function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpERC20BalanceOf /// @notice Opcode for ERC20 `balanceOf`. library OpERC20BalanceOf { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 token_, uint256 account_ ) internal view returns (uint256) { return IERC20(address(uint160(token_))).balanceOf( address(uint160(account_)) ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpERC20TotalSupply /// @notice Opcode for ERC20 `totalSupply`. library OpERC20TotalSupply { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 token_) internal view returns (uint256) { return IERC20(address(uint160(token_))).totalSupply(); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {ERC20SnapshotUpgradeable as ERC20Snapshot} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpERC20SnapshotBalanceOfAt /// @notice Opcode for Open Zeppelin `ERC20Snapshot.balanceOfAt`. /// https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#ERC20Snapshot library OpERC20SnapshotBalanceOfAt { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 token_, uint256 account_, uint256 snapshotId_ ) internal view returns (uint256) { return ERC20Snapshot(address(uint160(token_))).balanceOfAt( address(uint160(account_)), snapshotId_ ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/extensions/ERC20Snapshot.sol) pragma solidity ^0.8.0; import "../ERC20Upgradeable.sol"; import "../../../utils/ArraysUpgradeable.sol"; import "../../../utils/CountersUpgradeable.sol"; import "../../../proxy/utils/Initializable.sol"; /** * @dev This contract extends an ERC20 token with a snapshot mechanism. When a snapshot is created, the balances and * total supply at the time are recorded for later access. * * This can be used to safely create mechanisms based on token balances such as trustless dividends or weighted voting. * In naive implementations it's possible to perform a "double spend" attack by reusing the same balance from different * accounts. By using snapshots to calculate dividends or voting power, those attacks no longer apply. It can also be * used to create an efficient ERC20 forking mechanism. * * Snapshots are created by the internal {_snapshot} function, which will emit the {Snapshot} event and return a * snapshot id. To get the total supply at the time of a snapshot, call the function {totalSupplyAt} with the snapshot * id. To get the balance of an account at the time of a snapshot, call the {balanceOfAt} function with the snapshot id * and the account address. * * NOTE: Snapshot policy can be customized by overriding the {_getCurrentSnapshotId} method. For example, having it * return `block.number` will trigger the creation of snapshot at the beginning of each new block. When overriding this * function, be careful about the monotonicity of its result. Non-monotonic snapshot ids will break the contract. * * Implementing snapshots for every block using this method will incur significant gas costs. For a gas-efficient * alternative consider {ERC20Votes}. * * ==== Gas Costs * * Snapshots are efficient. Snapshot creation is _O(1)_. Retrieval of balances or total supply from a snapshot is _O(log * n)_ in the number of snapshots that have been created, although _n_ for a specific account will generally be much * smaller since identical balances in subsequent snapshots are stored as a single entry. * * There is a constant overhead for normal ERC20 transfers due to the additional snapshot bookkeeping. This overhead is * only significant for the first transfer that immediately follows a snapshot for a particular account. Subsequent * transfers will have normal cost until the next snapshot, and so on. */ abstract contract ERC20SnapshotUpgradeable is Initializable, ERC20Upgradeable { function __ERC20Snapshot_init() internal onlyInitializing { } function __ERC20Snapshot_init_unchained() internal onlyInitializing { } // Inspired by Jordi Baylina's MiniMeToken to record historical balances: // https://github.com/Giveth/minime/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol using ArraysUpgradeable for uint256[]; using CountersUpgradeable for CountersUpgradeable.Counter; // Snapshotted values have arrays of ids and the value corresponding to that id. These could be an array of a // Snapshot struct, but that would impede usage of functions that work on an array. struct Snapshots { uint256[] ids; uint256[] values; } mapping(address => Snapshots) private _accountBalanceSnapshots; Snapshots private _totalSupplySnapshots; // Snapshot ids increase monotonically, with the first value being 1. An id of 0 is invalid. CountersUpgradeable.Counter private _currentSnapshotId; /** * @dev Emitted by {_snapshot} when a snapshot identified by `id` is created. */ event Snapshot(uint256 id); /** * @dev Creates a new snapshot and returns its snapshot id. * * Emits a {Snapshot} event that contains the same id. * * {_snapshot} is `internal` and you have to decide how to expose it externally. Its usage may be restricted to a * set of accounts, for example using {AccessControl}, or it may be open to the public. * * [WARNING] * ==== * While an open way of calling {_snapshot} is required for certain trust minimization mechanisms such as forking, * you must consider that it can potentially be used by attackers in two ways. * * First, it can be used to increase the cost of retrieval of values from snapshots, although it will grow * logarithmically thus rendering this attack ineffective in the long term. Second, it can be used to target * specific accounts and increase the cost of ERC20 transfers for them, in the ways specified in the Gas Costs * section above. * * We haven't measured the actual numbers; if this is something you're interested in please reach out to us. * ==== */ function _snapshot() internal virtual returns (uint256) { _currentSnapshotId.increment(); uint256 currentId = _getCurrentSnapshotId(); emit Snapshot(currentId); return currentId; } /** * @dev Get the current snapshotId */ function _getCurrentSnapshotId() internal view virtual returns (uint256) { return _currentSnapshotId.current(); } /** * @dev Retrieves the balance of `account` at the time `snapshotId` was created. */ function balanceOfAt(address account, uint256 snapshotId) public view virtual returns (uint256) { (bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]); return snapshotted ? value : balanceOf(account); } /** * @dev Retrieves the total supply at the time `snapshotId` was created. */ function totalSupplyAt(uint256 snapshotId) public view virtual returns (uint256) { (bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnapshots); return snapshotted ? value : totalSupply(); } // Update balance and/or total supply snapshots before the values are modified. This is implemented // in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations. function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override { super._beforeTokenTransfer(from, to, amount); if (from == address(0)) { // mint _updateAccountSnapshot(to); _updateTotalSupplySnapshot(); } else if (to == address(0)) { // burn _updateAccountSnapshot(from); _updateTotalSupplySnapshot(); } else { // transfer _updateAccountSnapshot(from); _updateAccountSnapshot(to); } } function _valueAt(uint256 snapshotId, Snapshots storage snapshots) private view returns (bool, uint256) { require(snapshotId > 0, "ERC20Snapshot: id is 0"); require(snapshotId <= _getCurrentSnapshotId(), "ERC20Snapshot: nonexistent id"); // When a valid snapshot is queried, there are three possibilities: // a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never // created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds // to this id is the current one. // b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the // requested id, and its value is the one to return. // c) More snapshots were created after the requested one, and the queried value was later modified. There will be // no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is // larger than the requested one. // // In summary, we need to find an element in an array, returning the index of the smallest value that is larger if // it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does // exactly this. uint256 index = snapshots.ids.findUpperBound(snapshotId); if (index == snapshots.ids.length) { return (false, 0); } else { return (true, snapshots.values[index]); } } function _updateAccountSnapshot(address account) private { _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account)); } function _updateTotalSupplySnapshot() private { _updateSnapshot(_totalSupplySnapshots, totalSupply()); } function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue) private { uint256 currentId = _getCurrentSnapshotId(); if (_lastSnapshotId(snapshots.ids) < currentId) { snapshots.ids.push(currentId); snapshots.values.push(currentValue); } } function _lastSnapshotId(uint256[] storage ids) private view returns (uint256) { if (ids.length == 0) { return 0; } else { return ids[ids.length - 1]; } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[46] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Arrays.sol) pragma solidity ^0.8.0; import "./StorageSlotUpgradeable.sol"; import "./math/MathUpgradeable.sol"; /** * @dev Collection of functions related to array types. */ library ArraysUpgradeable { using StorageSlotUpgradeable for bytes32; /** * @dev Searches a sorted `array` and returns the first index that contains * a value greater or equal to `element`. If no such index exists (i.e. all * values in the array are strictly less than `element`), the array length is * returned. Time complexity O(log n). * * `array` is expected to be sorted in ascending order, and to contain no * repeated elements. */ function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { if (array.length == 0) { return 0; } uint256 low = 0; uint256 high = array.length; while (low < high) { uint256 mid = MathUpgradeable.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds down (it does integer division with truncation). if (unsafeAccess(array, mid).value > element) { high = mid; } else { low = mid + 1; } } // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. if (low > 0 && unsafeAccess(array, low - 1).value == element) { return low - 1; } else { return low; } } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlotUpgradeable.AddressSlot storage) { bytes32 slot; /// @solidity memory-safe-assembly assembly { mstore(0, arr.slot) slot := add(keccak256(0, 0x20), pos) } return slot.getAddressSlot(); } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlotUpgradeable.Bytes32Slot storage) { bytes32 slot; /// @solidity memory-safe-assembly assembly { mstore(0, arr.slot) slot := add(keccak256(0, 0x20), pos) } return slot.getBytes32Slot(); } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlotUpgradeable.Uint256Slot storage) { bytes32 slot; /// @solidity memory-safe-assembly assembly { mstore(0, arr.slot) slot := add(keccak256(0, 0x20), pos) } return slot.getUint256Slot(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library CountersUpgradeable { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {ERC20SnapshotUpgradeable as ERC20Snapshot} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpERC20SnapshotTotalSupplyAt /// @notice Opcode for Open Zeppelin `ERC20Snapshot.totalSupplyAt`. /// https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#ERC20Snapshot library OpERC20SnapshotTotalSupplyAt { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 token_, uint256 snapshotId_ ) internal view returns (uint256) { return ERC20Snapshot(address(uint160(token_))).totalSupplyAt(snapshotId_); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC721Upgradeable as IERC721} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpERC721BalanceOf /// @notice Opcode for getting the current erc721 balance of an account. library OpERC721BalanceOf { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 token_, uint256 account_ ) internal view returns (uint256) { return IERC721(address(uint160(token_))).balanceOf( address(uint160(account_)) ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// 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); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC721Upgradeable as IERC721} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpERC721OwnerOf /// @notice Opcode for getting the current erc721 owner of an account. library OpERC721OwnerOf { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 token_, uint256 id_) internal view returns (uint256) { return uint256(uint160(IERC721(address(uint160(token_))).ownerOf(id_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC1155Upgradeable as IERC1155} from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpERC1155BalanceOf /// @notice Opcode for getting the current erc1155 balance of an account. library OpERC1155BalanceOf { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 token_, uint256 account_, uint256 id_ ) internal view returns (uint256) { return IERC1155(address(uint160(token_))).balanceOf( address(uint160(account_)), id_ ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155Upgradeable is IERC165Upgradeable { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC1155Upgradeable as IERC1155} from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../../array/LibUint256Array.sol"; import "../../../type/LibCast.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpERC1155BalanceOfBatch /// @notice Opcode for getting the current erc1155 balance of an accounts batch. library OpERC1155BalanceOfBatch { using LibStackPointer for StackPointer; using LibCast for uint256[]; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 token_, uint256[] memory accounts_, uint256[] memory ids_ ) internal view returns (uint256[] memory) { return IERC1155(address(uint160(token_))).balanceOfBatch( accounts_.asAddresses(), ids_ ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn( stackTop_, f, Operand.unwrap(operand_) ); } // Operand will be the length function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../ierc5313/IERC5313.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "../../run/LibInterpreterState.sol"; /// @title OpERC5313Owner /// @notice Opcode for ERC5313 `owner`. library OpERC5313Owner { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 contract_) internal view returns (uint256) { return uint256( uint160(address(EIP5313(address(uint160(contract_))).owner())) ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.15; /// @title EIP-5313 Light Contract Ownership Standard interface EIP5313 { /// @notice Get the address of the owner /// @return The address of the owner function owner() external view returns (address); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../run/LibStackPointer.sol"; import "../../../array/LibUint256Array.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpEnsure /// @notice Opcode for requiring some truthy values. library OpEnsure { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure { assembly ("memory-safe") { if iszero(a_) { revert(0, 0) } } } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpBlockNumber /// @notice Opcode for getting the current block number. library OpBlockNumber { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.push(stackTop_); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.push(block.number); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpTimestamp /// @notice Opcode for getting the current timestamp. library OpTimestamp { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.push(stackTop_); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.push(block.timestamp); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../math/LibFixedPointMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpFixedPointScale18 /// @notice Opcode for scaling a number to 18 decimal fixed point. library OpFixedPointScale18 { using LibFixedPointMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(Operand operand_, uint256 a_) internal pure returns (uint256) { return a_.scale18( Operand.unwrap(operand_) >> 1, Math.Rounding(Operand.unwrap(operand_) & MASK_1BIT) ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../math/LibFixedPointMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpFixedPointScale18Div /// @notice Opcode for performing scale 18 fixed point division. library OpFixedPointScale18Div { using LibFixedPointMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( Operand operand_, uint256 a_, uint256 b_ ) internal pure returns (uint256) { return a_ .scale18(Operand.unwrap(operand_), Math.Rounding.Down) .fixedPointDiv(b_, Math.Rounding.Down); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../math/LibFixedPointMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpFixedPointScale18Dynamic /// @notice Opcode for scaling a number to 18 decimal fixed point. Identical to /// `OpFixedPointScale18` but the scale value is taken from the stack instead of /// the operand. library OpFixedPointScale18Dynamic { using LibFixedPointMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( Operand operand_, uint256 scale_, uint256 a_ ) internal pure returns (uint256) { return a_.scale18( scale_, Math.Rounding(Operand.unwrap(operand_) & MASK_1BIT) ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../math/LibFixedPointMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpFixedPointScale18Mul /// @notice Opcode for performing scale 18 fixed point multiplication. library OpFixedPointScale18Mul { using LibFixedPointMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( Operand operand_, uint256 a_, uint256 b_ ) internal pure returns (uint256) { return a_ .scale18(Operand.unwrap(operand_), Math.Rounding.Down) .fixedPointMul(b_, Math.Rounding.Down); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../math/LibFixedPointMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpFixedPointScaleBy /// @notice Opcode for scaling a number by some OOMs. library OpFixedPointScaleBy { using LibFixedPointMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(Operand operand_, uint256 a_) internal pure returns (uint256) { return a_.scaleBy( int8(uint8(Operand.unwrap(operand_))), Math.Rounding.Down ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../math/LibFixedPointMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpFixedPointScaleN /// @notice Opcode for scaling a number to N fixed point. library OpFixedPointScaleN { using LibFixedPointMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(Operand operand_, uint256 a_) internal pure returns (uint256) { return a_.scaleN(Operand.unwrap(operand_), Math.Rounding.Down); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpAny /// @notice Opcode to compare the top N stack values. library OpAny { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { function(uint256[] memory) internal view returns (uint256) fn_; return integrityCheckState_.applyFn( stackTop_, fn_, Operand.unwrap(operand_) ); } // ANY // ANY is the first nonzero item, else 0. // operand_ id the length of items to check. function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { StackPointer bottom_ = stackTop_.down(Operand.unwrap(operand_)); for ( StackPointer i_ = bottom_; StackPointer.unwrap(i_) < StackPointer.unwrap(stackTop_); i_ = i_.up() ) { uint256 item_ = i_.peekUp(); if (item_ > 0) { return bottom_.push(item_); } } return bottom_.up(); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpEagerIf /// @notice Opcode for selecting a value based on a condition. library OpEagerIf { using LibIntegrityCheck for IntegrityCheckState; using LibStackPointer for StackPointer; function f( uint256 a_, uint256[] memory bs_, uint256[] memory cs_ ) internal pure returns (uint256[] memory) { return a_ > 0 ? bs_ : cs_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn( stackTop_, f, Operand.unwrap(operand_) + 1 ); } /// Eager because BOTH x_ and y_ must be eagerly evaluated /// before EAGER_IF will select one of them. If both x_ and y_ /// are cheap (e.g. constant values) then this may also be the /// simplest and cheapest way to select one of them. function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { unchecked { return stackTop_.applyFn(f, Operand.unwrap(operand_) + 1); } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../run/LibStackPointer.sol"; import "../../../../type/LibCast.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpEqualTo /// @notice Opcode to compare the top two stack values. library OpEqualTo { using LibCast for bool; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256 c_) { // Perhaps surprisingly it seems to require assembly to efficiently get // a `uint256` from boolean equality. assembly ("memory-safe") { c_ := eq(a_, b_) } } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpEvery /// @notice Opcode to compare the top N stack values. library OpEvery { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { function(uint256[] memory) internal view returns (uint256) fn_; return integrityCheckState_.applyFn( stackTop_, fn_, Operand.unwrap(operand_) ); } // EVERY // EVERY is either the first item if every item is nonzero, else 0. // operand_ is the length of items to check. function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { StackPointer bottom_ = stackTop_.down(Operand.unwrap(operand_)); for ( StackPointer i_ = bottom_; StackPointer.unwrap(i_) < StackPointer.unwrap(stackTop_); i_ = i_.up() ) { if (i_.peekUp() == 0) { return bottom_.push(0); } } return bottom_.up(); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../run/LibStackPointer.sol"; import "../../../../type/LibCast.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpGreaterThan /// @notice Opcode to compare the top two stack values. library OpGreaterThan { using LibCast for bool; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256 c_) { assembly ("memory-safe") { c_ := gt(a_, b_) } } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../run/LibStackPointer.sol"; import "../../../../type/LibCast.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpIsZero /// @notice Opcode for checking if the stack top is zero. library OpIsZero { using LibCast for bool; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256 b_) { assembly ("memory-safe") { b_ := iszero(a_) } } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../run/LibStackPointer.sol"; import "../../../../type/LibCast.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpLessThan /// @notice Opcode to compare the top two stack values. library OpLessThan { using LibStackPointer for StackPointer; using LibCast for bool; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256 c_) { assembly ("memory-safe") { c_ := lt(a_, b_) } } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, avg} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBAvg { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return UD60x18.unwrap(avg(UD60x18.wrap(a_), UD60x18.wrap(b_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { msb, mulDiv, mulDiv18, prbExp2, prbSqrt } from "../Common.sol"; import { unwrap, wrap } from "./Casting.sol"; import { uHALF_UNIT, uLOG2_10, uLOG2_E, uMAX_UD60x18, uMAX_WHOLE_UD60x18, UNIT, uUNIT, ZERO } from "./Constants.sol"; import { PRBMath_UD60x18_Ceil_Overflow, PRBMath_UD60x18_Exp_InputTooBig, PRBMath_UD60x18_Exp2_InputTooBig, PRBMath_UD60x18_Gm_Overflow, PRBMath_UD60x18_Log_InputTooSmall, PRBMath_UD60x18_Sqrt_Overflow } from "./Errors.sol"; import { UD60x18 } from "./ValueType.sol"; /*////////////////////////////////////////////////////////////////////////// MATHEMATICAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @notice Calculates the arithmetic average of x and y, rounding down. /// /// @dev Based on the formula: /// /// $$ /// avg(x, y) = (x & y) + ((xUint ^ yUint) / 2) /// $$ // /// In English, what this formula does is: /// /// 1. AND x and y. /// 2. Calculate half of XOR x and y. /// 3. Add the two results together. /// /// This technique is known as SWAR, which stands for "SIMD within a register". You can read more about it here: /// https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223 /// /// @param x The first operand as an UD60x18 number. /// @param y The second operand as an UD60x18 number. /// @return result The arithmetic average as an UD60x18 number. function avg(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); uint256 yUint = unwrap(y); unchecked { result = wrap((xUint & yUint) + ((xUint ^ yUint) >> 1)); } } /// @notice Yields the smallest whole UD60x18 number greater than or equal to x. /// /// @dev This is optimized for fractional value inputs, because for every whole value there are "1e18 - 1" fractional /// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be less than or equal to `MAX_WHOLE_UD60x18`. /// /// @param x The UD60x18 number to ceil. /// @param result The least number greater than or equal to x, as an UD60x18 number. function ceil(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); if (xUint > uMAX_WHOLE_UD60x18) { revert PRBMath_UD60x18_Ceil_Overflow(x); } assembly ("memory-safe") { // Equivalent to "x % UNIT" but faster. let remainder := mod(x, uUNIT) // Equivalent to "UNIT - remainder" but faster. let delta := sub(uUNIT, remainder) // Equivalent to "x + delta * (remainder > 0 ? 1 : 0)" but faster. result := add(x, mul(delta, gt(remainder, 0))) } } /// @notice Divides two UD60x18 numbers, returning a new UD60x18 number. Rounds towards zero. /// /// @dev Uses `mulDiv` to enable overflow-safe multiplication and division. /// /// Requirements: /// - The denominator cannot be zero. /// /// @param x The numerator as an UD60x18 number. /// @param y The denominator as an UD60x18 number. /// @param result The quotient as an UD60x18 number. function div(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(mulDiv(unwrap(x), uUNIT, unwrap(y))); } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the formula: /// /// $$ /// e^x = 2^{x * log_2{e}} /// $$ /// /// Requirements: /// - All from `log2`. /// - x must be less than 133.084258667509499441. /// /// @param x The exponent as an UD60x18 number. /// @return result The result as an UD60x18 number. function exp(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); // Without this check, the value passed to `exp2` would be greater than 192. if (xUint >= 133_084258667509499441) { revert PRBMath_UD60x18_Exp_InputTooBig(x); } unchecked { // We do the fixed-point multiplication inline rather than via the `mul` function to save gas. uint256 doubleUnitProduct = xUint * uLOG2_E; result = exp2(wrap(doubleUnitProduct / uUNIT)); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within `MAX_UD60x18`. /// /// @param x The exponent as an UD60x18 number. /// @return result The result as an UD60x18 number. function exp2(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); // Numbers greater than or equal to 2^192 don't fit within the 192.64-bit format. if (xUint >= 192e18) { revert PRBMath_UD60x18_Exp2_InputTooBig(x); } // Convert x to the 192.64-bit fixed-point format. uint256 x_192x64 = (xUint << 64) / uUNIT; // Pass x to the `prbExp2` function, which uses the 192.64-bit fixed-point number representation. result = wrap(prbExp2(x_192x64)); } /// @notice Yields the greatest whole UD60x18 number less than or equal to x. /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// @param x The UD60x18 number to floor. /// @param result The greatest integer less than or equal to x, as an UD60x18 number. function floor(UD60x18 x) pure returns (UD60x18 result) { assembly ("memory-safe") { // Equivalent to "x % UNIT" but faster. let remainder := mod(x, uUNIT) // Equivalent to "x - remainder * (remainder > 0 ? 1 : 0)" but faster. result := sub(x, mul(remainder, gt(remainder, 0))) } } /// @notice Yields the excess beyond the floor of x. /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part. /// @param x The UD60x18 number to get the fractional part of. /// @param result The fractional part of x as an UD60x18 number. function frac(UD60x18 x) pure returns (UD60x18 result) { assembly ("memory-safe") { result := mod(x, uUNIT) } } /// @notice Calculates the geometric mean of x and y, i.e. $$sqrt(x * y)$$, rounding down. /// /// @dev Requirements: /// - x * y must fit within `MAX_UD60x18`, lest it overflows. /// /// @param x The first operand as an UD60x18 number. /// @param y The second operand as an UD60x18 number. /// @return result The result as an UD60x18 number. function gm(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); uint256 yUint = unwrap(y); if (xUint == 0 || yUint == 0) { return ZERO; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. uint256 xyUint = xUint * yUint; if (xyUint / xUint != yUint) { revert PRBMath_UD60x18_Gm_Overflow(x, y); } // We don't need to multiply the result by `UNIT` here because the x*y product had picked up a factor of `UNIT` // during multiplication. See the comments in the `prbSqrt` function. result = wrap(prbSqrt(xyUint)); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The UD60x18 number for which to calculate the inverse. /// @return result The inverse as an UD60x18 number. function inv(UD60x18 x) pure returns (UD60x18 result) { unchecked { // 1e36 is UNIT * UNIT. result = wrap(1e36 / unwrap(x)); } } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the formula: /// /// $$ /// ln{x} = log_2{x} / log_2{e}$$. /// $$ /// /// Requirements: /// - All from `log2`. /// /// Caveats: /// - All from `log2`. /// - This doesn't return exactly 1 for 2.718281828459045235, for that more fine-grained precision is needed. /// /// @param x The UD60x18 number for which to calculate the natural logarithm. /// @return result The natural logarithm as an UD60x18 number. function ln(UD60x18 x) pure returns (UD60x18 result) { unchecked { // We do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value // that `log2` can return is 196.205294292027477728. result = wrap((unwrap(log2(x)) * uUNIT) / uLOG2_E); } } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the formula: /// /// $$ /// log_{10}{x} = log_2{x} / log_2{10} /// $$ /// /// Requirements: /// - All from `log2`. /// /// Caveats: /// - All from `log2`. /// /// @param x The UD60x18 number for which to calculate the common logarithm. /// @return result The common logarithm as an UD60x18 number. function log10(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); if (xUint < uUNIT) { revert PRBMath_UD60x18_Log_InputTooSmall(x); } // Note that the `mul` in this assembly block is the assembly multiplication operation, not the UD60x18 `mul`. // prettier-ignore assembly ("memory-safe") { switch x case 1 { result := mul(uUNIT, sub(0, 18)) } case 10 { result := mul(uUNIT, sub(1, 18)) } case 100 { result := mul(uUNIT, sub(2, 18)) } case 1000 { result := mul(uUNIT, sub(3, 18)) } case 10000 { result := mul(uUNIT, sub(4, 18)) } case 100000 { result := mul(uUNIT, sub(5, 18)) } case 1000000 { result := mul(uUNIT, sub(6, 18)) } case 10000000 { result := mul(uUNIT, sub(7, 18)) } case 100000000 { result := mul(uUNIT, sub(8, 18)) } case 1000000000 { result := mul(uUNIT, sub(9, 18)) } case 10000000000 { result := mul(uUNIT, sub(10, 18)) } case 100000000000 { result := mul(uUNIT, sub(11, 18)) } case 1000000000000 { result := mul(uUNIT, sub(12, 18)) } case 10000000000000 { result := mul(uUNIT, sub(13, 18)) } case 100000000000000 { result := mul(uUNIT, sub(14, 18)) } case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) } case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) } case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := uUNIT } case 100000000000000000000 { result := mul(uUNIT, 2) } case 1000000000000000000000 { result := mul(uUNIT, 3) } case 10000000000000000000000 { result := mul(uUNIT, 4) } case 100000000000000000000000 { result := mul(uUNIT, 5) } case 1000000000000000000000000 { result := mul(uUNIT, 6) } case 10000000000000000000000000 { result := mul(uUNIT, 7) } case 100000000000000000000000000 { result := mul(uUNIT, 8) } case 1000000000000000000000000000 { result := mul(uUNIT, 9) } case 10000000000000000000000000000 { result := mul(uUNIT, 10) } case 100000000000000000000000000000 { result := mul(uUNIT, 11) } case 1000000000000000000000000000000 { result := mul(uUNIT, 12) } case 10000000000000000000000000000000 { result := mul(uUNIT, 13) } case 100000000000000000000000000000000 { result := mul(uUNIT, 14) } case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) } case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) } case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) } case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) } case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) } case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) } case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) } case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) } case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) } case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) } case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) } case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) } case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 59) } default { result := uMAX_UD60x18 } } if (unwrap(result) == uMAX_UD60x18) { unchecked { // Do the fixed-point division inline to save gas. result = wrap((unwrap(log2(x)) * uUNIT) / uLOG2_10); } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than or equal to UNIT, otherwise the result would be negative. /// /// Caveats: /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The UD60x18 number for which to calculate the binary logarithm. /// @return result The binary logarithm as an UD60x18 number. function log2(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); if (xUint < uUNIT) { revert PRBMath_UD60x18_Log_InputTooSmall(x); } unchecked { // Calculate the integer part of the logarithm, add it to the result and finally calculate y = x * 2^(-n). uint256 n = msb(xUint / uUNIT); // This is the integer part of the logarithm as an UD60x18 number. The operation can't overflow because n // n is maximum 255 and UNIT is 1e18. uint256 resultUint = n * uUNIT; // This is $y = x * 2^{-n}$. uint256 y = xUint >> n; // If y is 1, the fractional part is zero. if (y == uUNIT) { return wrap(resultUint); } // Calculate the fractional part via the iterative approximation. // The "delta.rshift(1)" part is equivalent to "delta /= 2", but shifting bits is faster. uint256 DOUBLE_UNIT = 2e18; for (uint256 delta = uHALF_UNIT; delta > 0; delta >>= 1) { y = (y * y) / uUNIT; // Is y^2 > 2 and so in the range [2,4)? if (y >= DOUBLE_UNIT) { // Add the 2^{-m} factor to the logarithm. resultUint += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } result = wrap(resultUint); } } /// @notice Multiplies two UD60x18 numbers together, returning a new UD60x18 number. /// @dev See the documentation for the `Common.mulDiv18` function. /// @param x The multiplicand as an UD60x18 number. /// @param y The multiplier as an UD60x18 number. /// @return result The product as an UD60x18 number. function mul(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(mulDiv18(unwrap(x), unwrap(y))); } /// @notice Raises x to the power of y. /// /// @dev Based on the formula: /// /// $$ /// x^y = 2^{log_2{x} * y} /// $$ /// /// Requirements: /// - All from `exp2`, `log2` and `mul`. /// /// Caveats: /// - All from `exp2`, `log2` and `mul`. /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as an UD60x18 number. /// @param y Exponent to raise x to, as an UD60x18 number. /// @return result x raised to power y, as an UD60x18 number. function pow(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); uint256 yUint = unwrap(y); if (xUint == 0) { result = yUint == 0 ? UNIT : ZERO; } else { if (yUint == uUNIT) { result = x; } else { result = exp2(mul(log2(x), y)); } } } /// @notice Raises x (an UD60x18 number) to the power y (unsigned basic integer) using the famous algorithm /// "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - The result must fit within `MAX_UD60x18`. /// /// Caveats: /// - All from "Common.mulDiv18". /// - Assumes 0^0 is 1. /// /// @param x The base as an UD60x18 number. /// @param y The exponent as an uint256. /// @return result The result as an UD60x18 number. function powu(UD60x18 x, uint256 y) pure returns (UD60x18 result) { // Calculate the first iteration of the loop in advance. uint256 xUint = unwrap(x); uint256 resultUint = y & 1 > 0 ? xUint : uUNIT; // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. for (y >>= 1; y > 0; y >>= 1) { xUint = mulDiv18(xUint, xUint); // Equivalent to "y % 2 == 1" but faster. if (y & 1 > 0) { resultUint = mulDiv18(resultUint, xUint); } } result = wrap(resultUint); } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x must be less than `MAX_UD60x18` divided by `UNIT`. /// /// @param x The UD60x18 number for which to calculate the square root. /// @return result The result as an UD60x18 number. function sqrt(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); unchecked { if (xUint > uMAX_UD60x18 / uUNIT) { revert PRBMath_UD60x18_Sqrt_Overflow(x); } // Multiply x by `UNIT` to account for the factor of `UNIT` that is picked up when multiplying two UD60x18 // numbers together (in this case, the two numbers are both the square root). result = wrap(prbSqrt(xUint * uUNIT)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; /// Common mathematical functions used in both SD59x18 and UD60x18. Note that these global functions do not /// always operate with SD59x18 and UD60x18 numbers. /*////////////////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////////////////*/ /// @notice Emitted when the ending result in the fixed-point version of `mulDiv` would overflow uint256. error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y); /// @notice Emitted when the ending result in `mulDiv` would overflow uint256. error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator); /// @notice Emitted when attempting to run `mulDiv` with one of the inputs `type(int256).min`. error PRBMath_MulDivSigned_InputTooSmall(); /// @notice Emitted when the ending result in the signed version of `mulDiv` would overflow int256. error PRBMath_MulDivSigned_Overflow(int256 x, int256 y); /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ /// @dev The maximum value an uint128 number can have. uint128 constant MAX_UINT128 = type(uint128).max; /// @dev The maximum value an uint40 number can have. uint40 constant MAX_UINT40 = type(uint40).max; /// @dev How many trailing decimals can be represented. uint256 constant UNIT = 1e18; /// @dev Largest power of two that is a divisor of `UNIT`. uint256 constant UNIT_LPOTD = 262144; /// @dev The `UNIT` number inverted mod 2^256. uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @notice Finds the zero-based index of the first one in the binary representation of x. /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set /// /// Each of the steps in this implementation is equivalent to this high-level code: /// /// ```solidity /// if (x >= 2 ** 128) { /// x >>= 128; /// result += 128; /// } /// ``` /// /// Where 128 is swapped with each respective power of two factor. See the full high-level implementation here: /// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948 /// /// A list of the Yul instructions used below: /// - "gt" is "greater than" /// - "or" is the OR bitwise operator /// - "shl" is "shift left" /// - "shr" is "shift right" /// /// @param x The uint256 number for which to find the index of the most significant bit. /// @return result The index of the most significant bit as an uint256. function msb(uint256 x) pure returns (uint256 result) { // 2^128 assembly ("memory-safe") { let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^64 assembly ("memory-safe") { let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^32 assembly ("memory-safe") { let factor := shl(5, gt(x, 0xFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^16 assembly ("memory-safe") { let factor := shl(4, gt(x, 0xFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^8 assembly ("memory-safe") { let factor := shl(3, gt(x, 0xFF)) x := shr(factor, x) result := or(result, factor) } // 2^4 assembly ("memory-safe") { let factor := shl(2, gt(x, 0xF)) x := shr(factor, x) result := or(result, factor) } // 2^2 assembly ("memory-safe") { let factor := shl(1, gt(x, 0x3)) x := shr(factor, x) result := or(result, factor) } // 2^1 // No need to shift x any more. assembly ("memory-safe") { let factor := gt(x, 0x1) result := or(result, factor) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Requirements: /// - The denominator cannot be zero. /// - The result must fit within uint256. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The multiplicand as an uint256. /// @param y The multiplier as an uint256. /// @param denominator The divisor as an uint256. /// @return result The result as an uint256. function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) { // 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 ("memory-safe") { 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) { unchecked { return prod0 / denominator; } } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath_MulDiv_Overflow(x, y, denominator); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly ("memory-safe") { // Compute remainder using the mulmod Yul instruction. 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. unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 lpotdod = denominator & (~denominator + 1); assembly ("memory-safe") { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one. lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * lpotdod; // 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; } } /// @notice Calculates floor(x*y÷1e18) with full precision. /// /// @dev Variant of `mulDiv` with constant folding, i.e. in which the denominator is always 1e18. Before returning the /// final result, we add 1 if `(x * y) % UNIT >= HALF_UNIT`. Without this adjustment, 6.6e-19 would be truncated to 0 /// instead of being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717. /// /// Requirements: /// - The result must fit within uint256. /// /// Caveats: /// - The body is purposely left uncommented; to understand how this works, see the NatSpec comments in `mulDiv`. /// - It is assumed that the result can never be `type(uint256).max` when x and y solve the following two equations: /// 1. x * y = type(uint256).max * UNIT /// 2. (x * y) % UNIT >= UNIT / 2 /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly ("memory-safe") { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 >= UNIT) { revert PRBMath_MulDiv18_Overflow(x, y); } uint256 remainder; assembly ("memory-safe") { remainder := mulmod(x, y, UNIT) } if (prod1 == 0) { unchecked { return prod0 / UNIT; } } assembly ("memory-safe") { result := mul( or( div(sub(prod0, remainder), UNIT_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1)) ), UNIT_INVERSE ) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev An extension of `mulDiv` for signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - None of the inputs can be `type(int256).min`. /// - The result must fit within int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath_MulDivSigned_InputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 absX; uint256 absY; uint256 absD; unchecked { absX = x < 0 ? uint256(-x) : uint256(x); absY = y < 0 ? uint256(-y) : uint256(y); absD = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of (x*y)÷denominator. The result must fit within int256. uint256 rAbs = mulDiv(absX, absY, absD); if (rAbs > uint256(type(int256).max)) { revert PRBMath_MulDivSigned_Overflow(x, y); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly ("memory-safe") { // This works thanks to two's complement. // "sgt" stands for "signed greater than" and "sub(0,1)" is max uint256. sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs. // If there are, the result should be negative. Otherwise, it should be positive. unchecked { result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. /// See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function prbExp2(uint256 x) pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows // because the initial result is 2^191 and all magic factors are less than 2^65. if (x & 0xFF00000000000000 > 0) { if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } } if (x & 0xFF000000000000 > 0) { if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } } if (x & 0xFF0000000000 > 0) { if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } } if (x & 0xFF00000000 > 0) { if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } } if (x & 0xFF00000000 > 0) { if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } } if (x & 0xFF0000 > 0) { if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } } if (x & 0xFF00 > 0) { if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } } if (x & 0xFF > 0) { if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } } // We're doing two things at the same time: // // 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191 // rather than 192. // 2. Convert the result to the unsigned 60.18-decimal fixed-point format. // // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n". result *= UNIT; result >>= (191 - (x >> 64)); } } /// @notice Calculates the square root of x, rounding down if x is not a perfect square. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// Credits to OpenZeppelin for the explanations in code comments below. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function prbSqrt(uint256 x) pure returns (uint256 result) { if (x == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of x. // // We know that the "msb" (most significant bit) of x is a power of 2 such that we have: // // $$ // msb(x) <= x <= 2*msb(x)$ // $$ // // We write $msb(x)$ as $2^k$ and we get: // // $$ // k = log_2(x) // $$ // // Thus we can write the initial inequality as: // // $$ // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\ // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\ // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1} // $$ // // Consequently, $2^{log_2(x) /2}` is a good first approximation of sqrt(x) with at least one correct bit. uint256 xAux = uint256(x); result = 1; if (xAux >= 2 ** 128) { xAux >>= 128; result <<= 64; } if (xAux >= 2 ** 64) { xAux >>= 64; result <<= 32; } if (xAux >= 2 ** 32) { xAux >>= 32; result <<= 16; } if (xAux >= 2 ** 16) { xAux >>= 16; result <<= 8; } if (xAux >= 2 ** 8) { xAux >>= 8; result <<= 4; } if (xAux >= 2 ** 4) { xAux >>= 4; result <<= 2; } if (xAux >= 2 ** 2) { result <<= 1; } // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at // most 128 bits, 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 + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Round down the result in case x is not a perfect square. uint256 roundedDownResult = x / result; if (result >= roundedDownResult) { result = roundedDownResult; } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { MAX_UINT128, MAX_UINT40 } from "../Common.sol"; import { uMAX_SD1x18 } from "../sd1x18/Constants.sol"; import { SD1x18 } from "../sd1x18/ValueType.sol"; import { uMAX_SD59x18 } from "../sd59x18/Constants.sol"; import { SD59x18 } from "../sd59x18/ValueType.sol"; import { uMAX_UD2x18 } from "../ud2x18/Constants.sol"; import { UD2x18 } from "../ud2x18/ValueType.sol"; import { PRBMath_UD60x18_IntoSD1x18_Overflow, PRBMath_UD60x18_IntoUD2x18_Overflow, PRBMath_UD60x18_IntoSD59x18_Overflow, PRBMath_UD60x18_IntoUint128_Overflow, PRBMath_UD60x18_IntoUint40_Overflow } from "./Errors.sol"; import { UD60x18 } from "./ValueType.sol"; /// @notice Casts an UD60x18 number into SD1x18. /// @dev Requirements: /// - x must be less than or equal to `uMAX_SD1x18`. function intoSD1x18(UD60x18 x) pure returns (SD1x18 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > uint256(int256(uMAX_SD1x18))) { revert PRBMath_UD60x18_IntoSD1x18_Overflow(x); } result = SD1x18.wrap(int64(uint64(xUint))); } /// @notice Casts an UD60x18 number into UD2x18. /// @dev Requirements: /// - x must be less than or equal to `uMAX_UD2x18`. function intoUD2x18(UD60x18 x) pure returns (UD2x18 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > uMAX_UD2x18) { revert PRBMath_UD60x18_IntoUD2x18_Overflow(x); } result = UD2x18.wrap(uint64(xUint)); } /// @notice Casts an UD60x18 number into SD59x18. /// @dev Requirements: /// - x must be less than or equal to `uMAX_SD59x18`. function intoSD59x18(UD60x18 x) pure returns (SD59x18 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > uint256(uMAX_SD59x18)) { revert PRBMath_UD60x18_IntoSD59x18_Overflow(x); } result = SD59x18.wrap(int256(xUint)); } /// @notice Casts an UD60x18 number into uint128. /// @dev This is basically a functional alias for the `unwrap` function. function intoUint256(UD60x18 x) pure returns (uint256 result) { result = UD60x18.unwrap(x); } /// @notice Casts an UD60x18 number into uint128. /// @dev Requirements: /// - x must be less than or equal to `MAX_UINT128`. function intoUint128(UD60x18 x) pure returns (uint128 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > MAX_UINT128) { revert PRBMath_UD60x18_IntoUint128_Overflow(x); } result = uint128(xUint); } /// @notice Casts an UD60x18 number into uint40. /// @dev Requirements: /// - x must be less than or equal to `MAX_UINT40`. function intoUint40(UD60x18 x) pure returns (uint40 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > MAX_UINT40) { revert PRBMath_UD60x18_IntoUint40_Overflow(x); } result = uint40(xUint); } /// @notice Alias for the `wrap` function. function ud(uint256 x) pure returns (UD60x18 result) { result = wrap(x); } /// @notice Alias for the `wrap` function. function ud60x18(uint256 x) pure returns (UD60x18 result) { result = wrap(x); } /// @notice Unwraps an UD60x18 number into uint256. function unwrap(UD60x18 x) pure returns (uint256 result) { result = UD60x18.unwrap(x); } /// @notice Wraps an uint256 number into the UD60x18 value type. function wrap(uint256 x) pure returns (UD60x18 result) { result = UD60x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { SD1x18 } from "./ValueType.sol"; /// @dev Euler's number as an SD1x18 number. SD1x18 constant E = SD1x18.wrap(2_718281828459045235); /// @dev The maximum value an SD1x18 number can have. int64 constant uMAX_SD1x18 = 9_223372036854775807; SD1x18 constant MAX_SD1x18 = SD1x18.wrap(uMAX_SD1x18); /// @dev The maximum value an SD1x18 number can have. int64 constant uMIN_SD1x18 = -9_223372036854775808; SD1x18 constant MIN_SD1x18 = SD1x18.wrap(uMIN_SD1x18); /// @dev PI as an SD1x18 number. SD1x18 constant PI = SD1x18.wrap(3_141592653589793238); /// @dev The unit amount that implies how many trailing decimals can be represented. SD1x18 constant UNIT = SD1x18.wrap(1e18); int256 constant uUNIT = 1e18;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import "./Casting.sol" as C; /// @notice The signed 1.18-decimal fixed-point number representation, which can have up to 1 digit and up to 18 decimals. /// The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity type int64. /// This is useful when end users want to use int64 to save gas, e.g. with tight variable packing in contract storage. type SD1x18 is int64; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { C.intoSD59x18, C.intoUD2x18, C.intoUD60x18, C.intoUint256, C.intoUint128, C.intoUint40, C.unwrap } for SD1x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { MAX_UINT40 } from "../Common.sol"; import { SD59x18 } from "../sd59x18/ValueType.sol"; import { UD2x18 } from "../ud2x18/ValueType.sol"; import { UD60x18 } from "../ud60x18/ValueType.sol"; import { PRBMath_SD1x18_ToUD2x18_Underflow, PRBMath_SD1x18_ToUD60x18_Underflow, PRBMath_SD1x18_ToUint128_Underflow, PRBMath_SD1x18_ToUint256_Underflow, PRBMath_SD1x18_ToUint40_Overflow, PRBMath_SD1x18_ToUint40_Underflow } from "./Errors.sol"; import { SD1x18 } from "./ValueType.sol"; /// @notice Casts an SD1x18 number into SD59x18. /// @dev There is no overflow check because the domain of SD1x18 is a subset of SD59x18. function intoSD59x18(SD1x18 x) pure returns (SD59x18 result) { result = SD59x18.wrap(int256(SD1x18.unwrap(x))); } /// @notice Casts an SD1x18 number into UD2x18. /// - x must be positive. function intoUD2x18(SD1x18 x) pure returns (UD2x18 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD1x18_ToUD2x18_Underflow(x); } result = UD2x18.wrap(uint64(xInt)); } /// @notice Casts an SD1x18 number into UD60x18. /// @dev Requirements: /// - x must be positive. function intoUD60x18(SD1x18 x) pure returns (UD60x18 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD1x18_ToUD60x18_Underflow(x); } result = UD60x18.wrap(uint64(xInt)); } /// @notice Casts an SD1x18 number into uint256. /// @dev Requirements: /// - x must be positive. function intoUint256(SD1x18 x) pure returns (uint256 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD1x18_ToUint256_Underflow(x); } result = uint256(uint64(xInt)); } /// @notice Casts an SD1x18 number into uint128. /// @dev Requirements: /// - x must be positive. function intoUint128(SD1x18 x) pure returns (uint128 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD1x18_ToUint128_Underflow(x); } result = uint128(uint64(xInt)); } /// @notice Casts an SD1x18 number into uint40. /// @dev Requirements: /// - x must be positive. /// - x must be less than or equal to `MAX_UINT40`. function intoUint40(SD1x18 x) pure returns (uint40 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD1x18_ToUint40_Underflow(x); } if (xInt > int64(uint64(MAX_UINT40))) { revert PRBMath_SD1x18_ToUint40_Overflow(x); } result = uint40(uint64(xInt)); } /// @notice Alias for the `wrap` function. function sd1x18(int64 x) pure returns (SD1x18 result) { result = wrap(x); } /// @notice Unwraps an SD1x18 number into int64. function unwrap(SD1x18 x) pure returns (int64 result) { result = SD1x18.unwrap(x); } /// @notice Wraps an int64 number into the SD1x18 value type. function wrap(int64 x) pure returns (SD1x18 result) { result = SD1x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import "./Casting.sol" as C; import "./Helpers.sol" as H; import "./Math.sol" as M; /// @notice The signed 59.18-decimal fixed-point number representation, which can have up to 59 digits and up to 18 decimals. /// The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity type int256. type SD59x18 is int256; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { C.intoInt256, C.intoSD1x18, C.intoUD2x18, C.intoUD60x18, C.intoUint256, C.intoUint128, C.intoUint40, C.unwrap } for SD59x18 global; /*////////////////////////////////////////////////////////////////////////// MATHEMATICAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ using { M.abs, M.avg, M.ceil, M.div, M.exp, M.exp2, M.floor, M.frac, M.gm, M.inv, M.log10, M.log2, M.ln, M.mul, M.pow, M.powu, M.sqrt } for SD59x18 global; /*////////////////////////////////////////////////////////////////////////// HELPER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ using { H.add, H.and, H.eq, H.gt, H.gte, H.isZero, H.lshift, H.lt, H.lte, H.mod, H.neq, H.or, H.rshift, H.sub, H.uncheckedAdd, H.uncheckedSub, H.uncheckedUnary, H.xor } for SD59x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { MAX_UINT128, MAX_UINT40 } from "../Common.sol"; import { uMAX_SD1x18, uMIN_SD1x18 } from "../sd1x18/Constants.sol"; import { SD1x18 } from "../sd1x18/ValueType.sol"; import { uMAX_UD2x18 } from "../ud2x18/Constants.sol"; import { UD2x18 } from "../ud2x18/ValueType.sol"; import { UD60x18 } from "../ud60x18/ValueType.sol"; import { PRBMath_SD59x18_IntoSD1x18_Overflow, PRBMath_SD59x18_IntoSD1x18_Underflow, PRBMath_SD59x18_IntoUD2x18_Overflow, PRBMath_SD59x18_IntoUD2x18_Underflow, PRBMath_SD59x18_IntoUD60x18_Underflow, PRBMath_SD59x18_IntoUint128_Overflow, PRBMath_SD59x18_IntoUint128_Underflow, PRBMath_SD59x18_IntoUint256_Underflow, PRBMath_SD59x18_IntoUint40_Overflow, PRBMath_SD59x18_IntoUint40_Underflow } from "./Errors.sol"; import { SD59x18 } from "./ValueType.sol"; /// @notice Casts an SD59x18 number into int256. /// @dev This is basically a functional alias for the `unwrap` function. function intoInt256(SD59x18 x) pure returns (int256 result) { result = SD59x18.unwrap(x); } /// @notice Casts an SD59x18 number into SD1x18. /// @dev Requirements: /// - x must be greater than or equal to `uMIN_SD1x18`. /// - x must be less than or equal to `uMAX_SD1x18`. function intoSD1x18(SD59x18 x) pure returns (SD1x18 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < uMIN_SD1x18) { revert PRBMath_SD59x18_IntoSD1x18_Underflow(x); } if (xInt > uMAX_SD1x18) { revert PRBMath_SD59x18_IntoSD1x18_Overflow(x); } result = SD1x18.wrap(int64(xInt)); } /// @notice Casts an SD59x18 number into UD2x18. /// @dev Requirements: /// - x must be positive. /// - x must be less than or equal to `uMAX_UD2x18`. function intoUD2x18(SD59x18 x) pure returns (UD2x18 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD59x18_IntoUD2x18_Underflow(x); } if (xInt > int256(uint256(uMAX_UD2x18))) { revert PRBMath_SD59x18_IntoUD2x18_Overflow(x); } result = UD2x18.wrap(uint64(uint256(xInt))); } /// @notice Casts an SD59x18 number into UD60x18. /// @dev Requirements: /// - x must be positive. function intoUD60x18(SD59x18 x) pure returns (UD60x18 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD59x18_IntoUD60x18_Underflow(x); } result = UD60x18.wrap(uint256(xInt)); } /// @notice Casts an SD59x18 number into uint256. /// @dev Requirements: /// - x must be positive. function intoUint256(SD59x18 x) pure returns (uint256 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD59x18_IntoUint256_Underflow(x); } result = uint256(xInt); } /// @notice Casts an SD59x18 number into uint128. /// @dev Requirements: /// - x must be positive. /// - x must be less than or equal to `uMAX_UINT128`. function intoUint128(SD59x18 x) pure returns (uint128 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD59x18_IntoUint128_Underflow(x); } if (xInt > int256(uint256(MAX_UINT128))) { revert PRBMath_SD59x18_IntoUint128_Overflow(x); } result = uint128(uint256(xInt)); } /// @notice Casts an SD59x18 number into uint40. /// @dev Requirements: /// - x must be positive. /// - x must be less than or equal to `MAX_UINT40`. function intoUint40(SD59x18 x) pure returns (uint40 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert PRBMath_SD59x18_IntoUint40_Underflow(x); } if (xInt > int256(uint256(MAX_UINT40))) { revert PRBMath_SD59x18_IntoUint40_Overflow(x); } result = uint40(uint256(xInt)); } /// @notice Alias for the `wrap` function. function sd(int256 x) pure returns (SD59x18 result) { result = wrap(x); } /// @notice Alias for the `wrap` function. function sd59x18(int256 x) pure returns (SD59x18 result) { result = wrap(x); } /// @notice Unwraps an SD59x18 number into int256. function unwrap(SD59x18 x) pure returns (int256 result) { result = SD59x18.unwrap(x); } /// @notice Wraps an int256 number into the SD59x18 value type. function wrap(int256 x) pure returns (SD59x18 result) { result = SD59x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { UD2x18 } from "./ValueType.sol"; /// @dev Euler's number as an UD2x18 number. UD2x18 constant E = UD2x18.wrap(2_718281828459045235); /// @dev The maximum value an UD2x18 number can have. uint64 constant uMAX_UD2x18 = 18_446744073709551615; UD2x18 constant MAX_UD2x18 = UD2x18.wrap(uMAX_UD2x18); /// @dev PI as an UD2x18 number. UD2x18 constant PI = UD2x18.wrap(3_141592653589793238); /// @dev The unit amount that implies how many trailing decimals can be represented. uint256 constant uUNIT = 1e18; UD2x18 constant UNIT = UD2x18.wrap(1e18);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import "./Casting.sol" as C; /// @notice The unsigned 2.18-decimal fixed-point number representation, which can have up to 2 digits and up to 18 decimals. /// The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity type uint64. /// This is useful when end users want to use uint64 to save gas, e.g. with tight variable packing in contract storage. type UD2x18 is uint64; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { C.intoSD1x18, C.intoSD59x18, C.intoUD60x18, C.intoUint256, C.intoUint128, C.intoUint40, C.unwrap } for UD2x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { MAX_UINT40 } from "../Common.sol"; import { uMAX_SD1x18 } from "../sd1x18/Constants.sol"; import { SD1x18 } from "../sd1x18/ValueType.sol"; import { SD59x18 } from "../sd59x18/ValueType.sol"; import { UD2x18 } from "../ud2x18/ValueType.sol"; import { UD60x18 } from "../ud60x18/ValueType.sol"; import { PRBMath_UD2x18_IntoSD1x18_Overflow, PRBMath_UD2x18_IntoUint40_Overflow } from "./Errors.sol"; import { UD2x18 } from "./ValueType.sol"; /// @notice Casts an UD2x18 number into SD1x18. /// - x must be less than or equal to `uMAX_SD1x18`. function intoSD1x18(UD2x18 x) pure returns (SD1x18 result) { uint64 xUint = UD2x18.unwrap(x); if (xUint > uint64(uMAX_SD1x18)) { revert PRBMath_UD2x18_IntoSD1x18_Overflow(x); } result = SD1x18.wrap(int64(xUint)); } /// @notice Casts an UD2x18 number into SD59x18. /// @dev There is no overflow check because the domain of UD2x18 is a subset of SD59x18. function intoSD59x18(UD2x18 x) pure returns (SD59x18 result) { result = SD59x18.wrap(int256(uint256(UD2x18.unwrap(x)))); } /// @notice Casts an UD2x18 number into UD60x18. /// @dev There is no overflow check because the domain of UD2x18 is a subset of UD60x18. function intoUD60x18(UD2x18 x) pure returns (UD60x18 result) { result = UD60x18.wrap(UD2x18.unwrap(x)); } /// @notice Casts an UD2x18 number into uint128. /// @dev There is no overflow check because the domain of UD2x18 is a subset of uint128. function intoUint128(UD2x18 x) pure returns (uint128 result) { result = uint128(UD2x18.unwrap(x)); } /// @notice Casts an UD2x18 number into uint256. /// @dev There is no overflow check because the domain of UD2x18 is a subset of uint256. function intoUint256(UD2x18 x) pure returns (uint256 result) { result = uint256(UD2x18.unwrap(x)); } /// @notice Casts an UD2x18 number into uint40. /// @dev Requirements: /// - x must be less than or equal to `MAX_UINT40`. function intoUint40(UD2x18 x) pure returns (uint40 result) { uint64 xUint = UD2x18.unwrap(x); if (xUint > uint64(MAX_UINT40)) { revert PRBMath_UD2x18_IntoUint40_Overflow(x); } result = uint40(xUint); } /// @notice Alias for the `wrap` function. function ud2x18(uint64 x) pure returns (UD2x18 result) { result = wrap(x); } /// @notice Unwrap an UD2x18 number into uint64. function unwrap(UD2x18 x) pure returns (uint64 result) { result = UD2x18.unwrap(x); } /// @notice Wraps an uint64 number into the UD2x18 value type. function wrap(uint64 x) pure returns (UD2x18 result) { result = UD2x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import "./Casting.sol" as C; import "./Helpers.sol" as H; import "./Math.sol" as M; /// @notice The unsigned 60.18-decimal fixed-point number representation, which can have up to 60 digits and up to 18 decimals. /// The values of this are bound by the minimum and the maximum values permitted by the Solidity type uint256. /// @dev The value type is defined here so it can be imported in all other files. type UD60x18 is uint256; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { C.intoSD1x18, C.intoUD2x18, C.intoSD59x18, C.intoUint128, C.intoUint256, C.intoUint40, C.unwrap } for UD60x18 global; /*////////////////////////////////////////////////////////////////////////// MATHEMATICAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// The global "using for" directive makes the functions in this library callable on the UD60x18 type. using { M.avg, M.ceil, M.div, M.exp, M.exp2, M.floor, M.frac, M.gm, M.inv, M.ln, M.log10, M.log2, M.mul, M.pow, M.powu, M.sqrt } for UD60x18 global; /*////////////////////////////////////////////////////////////////////////// HELPER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// The global "using for" directive makes the functions in this library callable on the UD60x18 type. using { H.add, H.and, H.eq, H.gt, H.gte, H.isZero, H.lshift, H.lt, H.lte, H.mod, H.neq, H.or, H.rshift, H.sub, H.uncheckedAdd, H.uncheckedSub, H.xor } for UD60x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { unwrap, wrap } from "./Casting.sol"; import { UD60x18 } from "./ValueType.sol"; /// @notice Implements the checked addition operation (+) in the UD60x18 type. function add(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) + unwrap(y)); } /// @notice Implements the AND (&) bitwise operation in the UD60x18 type. function and(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(unwrap(x) & bits); } /// @notice Implements the equal operation (==) in the UD60x18 type. function eq(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) == unwrap(y); } /// @notice Implements the greater than operation (>) in the UD60x18 type. function gt(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) > unwrap(y); } /// @notice Implements the greater than or equal to operation (>=) in the UD60x18 type. function gte(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) >= unwrap(y); } /// @notice Implements a zero comparison check function in the UD60x18 type. function isZero(UD60x18 x) pure returns (bool result) { // This wouldn't work if x could be negative. result = unwrap(x) == 0; } /// @notice Implements the left shift operation (<<) in the UD60x18 type. function lshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(unwrap(x) << bits); } /// @notice Implements the lower than operation (<) in the UD60x18 type. function lt(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) < unwrap(y); } /// @notice Implements the lower than or equal to operation (<=) in the UD60x18 type. function lte(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) <= unwrap(y); } /// @notice Implements the checked modulo operation (%) in the UD60x18 type. function mod(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) % unwrap(y)); } /// @notice Implements the not equal operation (!=) in the UD60x18 type function neq(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) != unwrap(y); } /// @notice Implements the OR (|) bitwise operation in the UD60x18 type. function or(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) | unwrap(y)); } /// @notice Implements the right shift operation (>>) in the UD60x18 type. function rshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(unwrap(x) >> bits); } /// @notice Implements the checked subtraction operation (-) in the UD60x18 type. function sub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) - unwrap(y)); } /// @notice Implements the unchecked addition operation (+) in the UD60x18 type. function uncheckedAdd(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { unchecked { result = wrap(unwrap(x) + unwrap(y)); } } /// @notice Implements the unchecked subtraction operation (-) in the UD60x18 type. function uncheckedSub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { unchecked { result = wrap(unwrap(x) - unwrap(y)); } } /// @notice Implements the XOR (^) bitwise operation in the UD60x18 type. function xor(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) ^ unwrap(y)); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { UD2x18 } from "./ValueType.sol"; /// @notice Emitted when trying to cast a UD2x18 number that doesn't fit in SD1x18. error PRBMath_UD2x18_IntoSD1x18_Overflow(UD2x18 x); /// @notice Emitted when trying to cast a UD2x18 number that doesn't fit in uint40. error PRBMath_UD2x18_IntoUint40_Overflow(UD2x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { SD59x18 } from "./ValueType.sol"; /// @notice Emitted when taking the absolute value of `MIN_SD59x18`. error PRBMath_SD59x18_Abs_MinSD59x18(); /// @notice Emitted when ceiling a number overflows SD59x18. error PRBMath_SD59x18_Ceil_Overflow(SD59x18 x); /// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18. error PRBMath_SD59x18_Convert_Overflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18. error PRBMath_SD59x18_Convert_Underflow(int256 x); /// @notice Emitted when dividing two numbers and one of them is `MIN_SD59x18`. error PRBMath_SD59x18_Div_InputTooSmall(); /// @notice Emitted when dividing two numbers and one of the intermediary unsigned results overflows SD59x18. error PRBMath_SD59x18_Div_Overflow(SD59x18 x, SD59x18 y); /// @notice Emitted when taking the natural exponent of a base greater than 133.084258667509499441. error PRBMath_SD59x18_Exp_InputTooBig(SD59x18 x); /// @notice Emitted when taking the binary exponent of a base greater than 192. error PRBMath_SD59x18_Exp2_InputTooBig(SD59x18 x); /// @notice Emitted when flooring a number underflows SD59x18. error PRBMath_SD59x18_Floor_Underflow(SD59x18 x); /// @notice Emitted when taking the geometric mean of two numbers and their product is negative. error PRBMath_SD59x18_Gm_NegativeProduct(SD59x18 x, SD59x18 y); /// @notice Emitted when taking the geometric mean of two numbers and multiplying them overflows SD59x18. error PRBMath_SD59x18_Gm_Overflow(SD59x18 x, SD59x18 y); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in SD1x18. error PRBMath_SD59x18_IntoSD1x18_Overflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in SD1x18. error PRBMath_SD59x18_IntoSD1x18_Underflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in UD2x18. error PRBMath_SD59x18_IntoUD2x18_Overflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in UD2x18. error PRBMath_SD59x18_IntoUD2x18_Underflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in UD60x18. error PRBMath_SD59x18_IntoUD60x18_Underflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in uint128. error PRBMath_SD59x18_IntoUint128_Overflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in uint128. error PRBMath_SD59x18_IntoUint128_Underflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in uint256. error PRBMath_SD59x18_IntoUint256_Underflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in uint40. error PRBMath_SD59x18_IntoUint40_Overflow(SD59x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in uint40. error PRBMath_SD59x18_IntoUint40_Underflow(SD59x18 x); /// @notice Emitted when taking the logarithm of a number less than or equal to zero. error PRBMath_SD59x18_Log_InputTooSmall(SD59x18 x); /// @notice Emitted when multiplying two numbers and one of the inputs is `MIN_SD59x18`. error PRBMath_SD59x18_Mul_InputTooSmall(); /// @notice Emitted when multiplying two numbers and the intermediary absolute result overflows SD59x18. error PRBMath_SD59x18_Mul_Overflow(SD59x18 x, SD59x18 y); /// @notice Emitted when raising a number to a power and hte intermediary absolute result overflows SD59x18. error PRBMath_SD59x18_Powu_Overflow(SD59x18 x, uint256 y); /// @notice Emitted when taking the square root of a negative number. error PRBMath_SD59x18_Sqrt_NegativeInput(SD59x18 x); /// @notice Emitted when the calculating the square root overflows SD59x18. error PRBMath_SD59x18_Sqrt_Overflow(SD59x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { unwrap, wrap } from "./Casting.sol"; import { SD59x18 } from "./ValueType.sol"; /// @notice Implements the checked addition operation (+) in the SD59x18 type. function add(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { return wrap(unwrap(x) + unwrap(y)); } /// @notice Implements the AND (&) bitwise operation in the SD59x18 type. function and(SD59x18 x, int256 bits) pure returns (SD59x18 result) { return wrap(unwrap(x) & bits); } /// @notice Implements the equal (=) operation in the SD59x18 type. function eq(SD59x18 x, SD59x18 y) pure returns (bool result) { result = unwrap(x) == unwrap(y); } /// @notice Implements the greater than operation (>) in the SD59x18 type. function gt(SD59x18 x, SD59x18 y) pure returns (bool result) { result = unwrap(x) > unwrap(y); } /// @notice Implements the greater than or equal to operation (>=) in the SD59x18 type. function gte(SD59x18 x, SD59x18 y) pure returns (bool result) { result = unwrap(x) >= unwrap(y); } /// @notice Implements a zero comparison check function in the SD59x18 type. function isZero(SD59x18 x) pure returns (bool result) { result = unwrap(x) == 0; } /// @notice Implements the left shift operation (<<) in the SD59x18 type. function lshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) { result = wrap(unwrap(x) << bits); } /// @notice Implements the lower than operation (<) in the SD59x18 type. function lt(SD59x18 x, SD59x18 y) pure returns (bool result) { result = unwrap(x) < unwrap(y); } /// @notice Implements the lower than or equal to operation (<=) in the SD59x18 type. function lte(SD59x18 x, SD59x18 y) pure returns (bool result) { result = unwrap(x) <= unwrap(y); } /// @notice Implements the unchecked modulo operation (%) in the SD59x18 type. function mod(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { result = wrap(unwrap(x) % unwrap(y)); } /// @notice Implements the not equal operation (!=) in the SD59x18 type. function neq(SD59x18 x, SD59x18 y) pure returns (bool result) { result = unwrap(x) != unwrap(y); } /// @notice Implements the OR (|) bitwise operation in the SD59x18 type. function or(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { result = wrap(unwrap(x) | unwrap(y)); } /// @notice Implements the right shift operation (>>) in the SD59x18 type. function rshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) { result = wrap(unwrap(x) >> bits); } /// @notice Implements the checked subtraction operation (-) in the SD59x18 type. function sub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { result = wrap(unwrap(x) - unwrap(y)); } /// @notice Implements the unchecked addition operation (+) in the SD59x18 type. function uncheckedAdd(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { unchecked { result = wrap(unwrap(x) + unwrap(y)); } } /// @notice Implements the unchecked subtraction operation (-) in the SD59x18 type. function uncheckedSub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { unchecked { result = wrap(unwrap(x) - unwrap(y)); } } /// @notice Implements the unchecked unary minus operation (-) in the SD59x18 type. function uncheckedUnary(SD59x18 x) pure returns (SD59x18 result) { unchecked { result = wrap(-unwrap(x)); } } /// @notice Implements the XOR (^) bitwise operation in the SD59x18 type. function xor(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { result = wrap(unwrap(x) ^ unwrap(y)); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { MAX_UINT128, MAX_UINT40, msb, mulDiv, mulDiv18, prbExp2, prbSqrt } from "../Common.sol"; import { uHALF_UNIT, uLOG2_10, uLOG2_E, uMAX_SD59x18, uMAX_WHOLE_SD59x18, uMIN_SD59x18, uMIN_WHOLE_SD59x18, UNIT, uUNIT, ZERO } from "./Constants.sol"; import { PRBMath_SD59x18_Abs_MinSD59x18, PRBMath_SD59x18_Ceil_Overflow, PRBMath_SD59x18_Div_InputTooSmall, PRBMath_SD59x18_Div_Overflow, PRBMath_SD59x18_Exp_InputTooBig, PRBMath_SD59x18_Exp2_InputTooBig, PRBMath_SD59x18_Floor_Underflow, PRBMath_SD59x18_Gm_Overflow, PRBMath_SD59x18_Gm_NegativeProduct, PRBMath_SD59x18_Log_InputTooSmall, PRBMath_SD59x18_Mul_InputTooSmall, PRBMath_SD59x18_Mul_Overflow, PRBMath_SD59x18_Powu_Overflow, PRBMath_SD59x18_Sqrt_NegativeInput, PRBMath_SD59x18_Sqrt_Overflow } from "./Errors.sol"; import { unwrap, wrap } from "./Helpers.sol"; import { SD59x18 } from "./ValueType.sol"; /// @notice Calculate the absolute value of x. /// /// @dev Requirements: /// - x must be greater than `MIN_SD59x18`. /// /// @param x The SD59x18 number for which to calculate the absolute value. /// @param result The absolute value of x as an SD59x18 number. function abs(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = unwrap(x); if (xInt == uMIN_SD59x18) { revert PRBMath_SD59x18_Abs_MinSD59x18(); } result = xInt < 0 ? wrap(-xInt) : x; } /// @notice Calculates the arithmetic average of x and y, rounding towards zero. /// @param x The first operand as an SD59x18 number. /// @param y The second operand as an SD59x18 number. /// @return result The arithmetic average as an SD59x18 number. function avg(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = unwrap(x); int256 yInt = unwrap(y); unchecked { // This is equivalent to "x / 2 + y / 2" but faster. // This operation can never overflow. int256 sum = (xInt >> 1) + (yInt >> 1); if (sum < 0) { // If at least one of x and y is odd, we add 1 to the result, since shifting negative numbers to the right rounds // down to infinity. The right part is equivalent to "sum + (x % 2 == 1 || y % 2 == 1)" but faster. assembly ("memory-safe") { result := add(sum, and(or(xInt, yInt), 1)) } } else { // We need to add 1 if both x and y are odd to account for the double 0.5 remainder that is truncated after shifting. result = wrap(sum + (xInt & yInt & 1)); } } } /// @notice Yields the smallest whole SD59x18 number greater than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be less than or equal to `MAX_WHOLE_SD59x18`. /// /// @param x The SD59x18 number to ceil. /// @param result The least number greater than or equal to x, as an SD59x18 number. function ceil(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = unwrap(x); if (xInt > uMAX_WHOLE_SD59x18) { revert PRBMath_SD59x18_Ceil_Overflow(x); } int256 remainder = xInt % uUNIT; if (remainder == 0) { result = x; } else { unchecked { // Solidity uses C fmod style, which returns a modulus with the same sign as x. int256 resultInt = xInt - remainder; if (xInt > 0) { resultInt += uUNIT; } result = wrap(resultInt); } } } /// @notice Divides two SD59x18 numbers, returning a new SD59x18 number. Rounds towards zero. /// /// @dev This is a variant of `mulDiv` that works with signed numbers. Works by computing the signs and the absolute values /// separately. /// /// Requirements: /// - All from `Common.mulDiv`. /// - None of the inputs can be `MIN_SD59x18`. /// - The denominator cannot be zero. /// - The result must fit within int256. /// /// Caveats: /// - All from `Common.mulDiv`. /// /// @param x The numerator as an SD59x18 number. /// @param y The denominator as an SD59x18 number. /// @param result The quotient as an SD59x18 number. function div(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = unwrap(x); int256 yInt = unwrap(y); if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) { revert PRBMath_SD59x18_Div_InputTooSmall(); } // Get hold of the absolute values of x and y. uint256 xAbs; uint256 yAbs; unchecked { xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt); yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt); } // Compute the absolute value (x*UNIT)÷y. The resulting value must fit within int256. uint256 resultAbs = mulDiv(xAbs, uint256(uUNIT), yAbs); if (resultAbs > uint256(uMAX_SD59x18)) { revert PRBMath_SD59x18_Div_Overflow(x, y); } // Check if x and y have the same sign. This works thanks to two's complement; the left-most bit is the sign bit. bool sameSign = (xInt ^ yInt) > -1; // If the inputs don't have the same sign, the result should be negative. Otherwise, it should be positive. unchecked { result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs)); } } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the formula: /// /// $$ /// e^x = 2^{x * log_2{e}} /// $$ /// /// Requirements: /// - All from `log2`. /// - x must be less than 133.084258667509499441. /// /// Caveats: /// - All from `exp2`. /// - For any x less than -41.446531673892822322, the result is zero. /// /// @param x The exponent as an SD59x18 number. /// @return result The result as an SD59x18 number. function exp(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = unwrap(x); // Without this check, the value passed to `exp2` would be less than -59.794705707972522261. if (xInt < -41_446531673892822322) { return ZERO; } // Without this check, the value passed to `exp2` would be greater than 192. if (xInt >= 133_084258667509499441) { revert PRBMath_SD59x18_Exp_InputTooBig(x); } unchecked { // Do the fixed-point multiplication inline to save gas. int256 doubleUnitProduct = xInt * uLOG2_E; result = exp2(wrap(doubleUnitProduct / uUNIT)); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev Based on the formula: /// /// $$ /// 2^{-x} = \frac{1}{2^x} /// $$ /// /// See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within `MAX_SD59x18`. /// /// Caveats: /// - For any x less than -59.794705707972522261, the result is zero. /// /// @param x The exponent as an SD59x18 number. /// @return result The result as an SD59x18 number. function exp2(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = unwrap(x); if (xInt < 0) { // 2^59.794705707972522262 is the maximum number whose inverse does not truncate down to zero. if (xInt < -59_794705707972522261) { return ZERO; } unchecked { // Do the fixed-point inversion $1/2^x$ inline to save gas. 1e36 is UNIT * UNIT. result = wrap(1e36 / unwrap(exp2(wrap(-xInt)))); } } else { // 2^192 doesn't fit within the 192.64-bit format used internally in this function. if (xInt >= 192e18) { revert PRBMath_SD59x18_Exp2_InputTooBig(x); } unchecked { // Convert x to the 192.64-bit fixed-point format. uint256 x_192x64 = uint256((xInt << 64) / uUNIT); // It is safe to convert the result to int256 with no checks because the maximum input allowed in this function is 192. result = wrap(int256(prbExp2(x_192x64))); } } } /// @notice Yields the greatest whole SD59x18 number less than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be greater than or equal to `MIN_WHOLE_SD59x18`. /// /// @param x The SD59x18 number to floor. /// @param result The greatest integer less than or equal to x, as an SD59x18 number. function floor(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = unwrap(x); if (xInt < uMIN_WHOLE_SD59x18) { revert PRBMath_SD59x18_Floor_Underflow(x); } int256 remainder = xInt % uUNIT; if (remainder == 0) { result = x; } else { unchecked { // Solidity uses C fmod style, which returns a modulus with the same sign as x. int256 resultInt = xInt - remainder; if (xInt < 0) { resultInt -= uUNIT; } result = wrap(resultInt); } } } /// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right. /// of the radix point for negative numbers. /// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part /// @param x The SD59x18 number to get the fractional part of. /// @param result The fractional part of x as an SD59x18 number. function frac(SD59x18 x) pure returns (SD59x18 result) { result = wrap(unwrap(x) % uUNIT); } /// @notice Calculates the geometric mean of x and y, i.e. sqrt(x * y), rounding down. /// /// @dev Requirements: /// - x * y must fit within `MAX_SD59x18`, lest it overflows. /// - x * y must not be negative, since this library does not handle complex numbers. /// /// @param x The first operand as an SD59x18 number. /// @param y The second operand as an SD59x18 number. /// @return result The result as an SD59x18 number. function gm(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = unwrap(x); int256 yInt = unwrap(y); if (xInt == 0 || yInt == 0) { return ZERO; } unchecked { // Equivalent to "xy / x != y". Checking for overflow this way is faster than letting Solidity do it. int256 xyInt = xInt * yInt; if (xyInt / xInt != yInt) { revert PRBMath_SD59x18_Gm_Overflow(x, y); } // The product must not be negative, since this library does not handle complex numbers. if (xyInt < 0) { revert PRBMath_SD59x18_Gm_NegativeProduct(x, y); } // We don't need to multiply the result by `UNIT` here because the x*y product had picked up a factor of `UNIT` // during multiplication. See the comments within the `prbSqrt` function. uint256 resultUint = prbSqrt(uint256(xyInt)); result = wrap(int256(resultUint)); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The SD59x18 number for which to calculate the inverse. /// @return result The inverse as an SD59x18 number. function inv(SD59x18 x) pure returns (SD59x18 result) { // 1e36 is UNIT * UNIT. result = wrap(1e36 / unwrap(x)); } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the formula: /// /// $$ /// ln{x} = log_2{x} / log_2{e}$$. /// $$ /// /// Requirements: /// - All from `log2`. /// /// Caveats: /// - All from `log2`. /// - This doesn't return exactly 1 for 2.718281828459045235, for that more fine-grained precision is needed. /// /// @param x The SD59x18 number for which to calculate the natural logarithm. /// @return result The natural logarithm as an SD59x18 number. function ln(SD59x18 x) pure returns (SD59x18 result) { // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x) // can return is 195.205294292027477728. result = wrap((unwrap(log2(x)) * uUNIT) / uLOG2_E); } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the formula: /// /// $$ /// log_{10}{x} = log_2{x} / log_2{10} /// $$ /// /// Requirements: /// - All from `log2`. /// /// Caveats: /// - All from `log2`. /// /// @param x The SD59x18 number for which to calculate the common logarithm. /// @return result The common logarithm as an SD59x18 number. function log10(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = unwrap(x); if (xInt < 0) { revert PRBMath_SD59x18_Log_InputTooSmall(x); } // Note that the `mul` in this block is the assembly mul operation, not the SD59x18 `mul`. // prettier-ignore assembly ("memory-safe") { switch x case 1 { result := mul(uUNIT, sub(0, 18)) } case 10 { result := mul(uUNIT, sub(1, 18)) } case 100 { result := mul(uUNIT, sub(2, 18)) } case 1000 { result := mul(uUNIT, sub(3, 18)) } case 10000 { result := mul(uUNIT, sub(4, 18)) } case 100000 { result := mul(uUNIT, sub(5, 18)) } case 1000000 { result := mul(uUNIT, sub(6, 18)) } case 10000000 { result := mul(uUNIT, sub(7, 18)) } case 100000000 { result := mul(uUNIT, sub(8, 18)) } case 1000000000 { result := mul(uUNIT, sub(9, 18)) } case 10000000000 { result := mul(uUNIT, sub(10, 18)) } case 100000000000 { result := mul(uUNIT, sub(11, 18)) } case 1000000000000 { result := mul(uUNIT, sub(12, 18)) } case 10000000000000 { result := mul(uUNIT, sub(13, 18)) } case 100000000000000 { result := mul(uUNIT, sub(14, 18)) } case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) } case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) } case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := uUNIT } case 100000000000000000000 { result := mul(uUNIT, 2) } case 1000000000000000000000 { result := mul(uUNIT, 3) } case 10000000000000000000000 { result := mul(uUNIT, 4) } case 100000000000000000000000 { result := mul(uUNIT, 5) } case 1000000000000000000000000 { result := mul(uUNIT, 6) } case 10000000000000000000000000 { result := mul(uUNIT, 7) } case 100000000000000000000000000 { result := mul(uUNIT, 8) } case 1000000000000000000000000000 { result := mul(uUNIT, 9) } case 10000000000000000000000000000 { result := mul(uUNIT, 10) } case 100000000000000000000000000000 { result := mul(uUNIT, 11) } case 1000000000000000000000000000000 { result := mul(uUNIT, 12) } case 10000000000000000000000000000000 { result := mul(uUNIT, 13) } case 100000000000000000000000000000000 { result := mul(uUNIT, 14) } case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) } case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) } case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) } case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) } case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) } case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) } case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) } case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) } case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) } case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) } case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) } case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) } default { result := uMAX_SD59x18 } } if (unwrap(result) == uMAX_SD59x18) { unchecked { // Do the fixed-point division inline to save gas. result = wrap((unwrap(log2(x)) * uUNIT) / uLOG2_10); } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than zero. /// /// Caveats: /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The SD59x18 number for which to calculate the binary logarithm. /// @return result The binary logarithm as an SD59x18 number. function log2(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = unwrap(x); if (xInt <= 0) { revert PRBMath_SD59x18_Log_InputTooSmall(x); } unchecked { // This works because of: // // $$ // log_2{x} = -log_2{\frac{1}{x}} // $$ int256 sign; if (xInt >= uUNIT) { sign = 1; } else { sign = -1; // Do the fixed-point inversion inline to save gas. The numerator is UNIT * UNIT. xInt = 1e36 / xInt; } // Calculate the integer part of the logarithm and add it to the result and finally calculate $y = x * 2^(-n)$. uint256 n = msb(uint256(xInt / uUNIT)); // This is the integer part of the logarithm as an SD59x18 number. The operation can't overflow // because n is maximum 255, UNIT is 1e18 and sign is either 1 or -1. int256 resultInt = int256(n) * uUNIT; // This is $y = x * 2^{-n}$. int256 y = xInt >> n; // If y is 1, the fractional part is zero. if (y == uUNIT) { return wrap(resultInt * sign); } // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. int256 DOUBLE_UNIT = 2e18; for (int256 delta = uHALF_UNIT; delta > 0; delta >>= 1) { y = (y * y) / uUNIT; // Is $y^2 > 2$ and so in the range [2,4)? if (y >= DOUBLE_UNIT) { // Add the 2^{-m} factor to the logarithm. resultInt = resultInt + delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } resultInt *= sign; result = wrap(resultInt); } } /// @notice Multiplies two SD59x18 numbers together, returning a new SD59x18 number. /// /// @dev This is a variant of `mulDiv` that works with signed numbers and employs constant folding, i.e. the denominator /// is always 1e18. /// /// Requirements: /// - All from `Common.mulDiv18`. /// - None of the inputs can be `MIN_SD59x18`. /// - The result must fit within `MAX_SD59x18`. /// /// Caveats: /// - To understand how this works in detail, see the NatSpec comments in `Common.mulDivSigned`. /// /// @param x The multiplicand as an SD59x18 number. /// @param y The multiplier as an SD59x18 number. /// @return result The product as an SD59x18 number. function mul(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = unwrap(x); int256 yInt = unwrap(y); if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) { revert PRBMath_SD59x18_Mul_InputTooSmall(); } // Get hold of the absolute values of x and y. uint256 xAbs; uint256 yAbs; unchecked { xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt); yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt); } uint256 resultAbs = mulDiv18(xAbs, yAbs); if (resultAbs > uint256(uMAX_SD59x18)) { revert PRBMath_SD59x18_Mul_Overflow(x, y); } // Check if x and y have the same sign. This works thanks to two's complement; the left-most bit is the sign bit. bool sameSign = (xInt ^ yInt) > -1; // If the inputs have the same sign, the result should be negative. Otherwise, it should be positive. unchecked { result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs)); } } /// @notice Raises x to the power of y. /// /// @dev Based on the formula: /// /// $$ /// x^y = 2^{log_2{x} * y} /// $$ /// /// Requirements: /// - All from `exp2`, `log2` and `mul`. /// - x cannot be zero. /// /// Caveats: /// - All from `exp2`, `log2` and `mul`. /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as an SD59x18 number. /// @param y Exponent to raise x to, as an SD59x18 number /// @return result x raised to power y, as an SD59x18 number. function pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = unwrap(x); int256 yInt = unwrap(y); if (xInt == 0) { result = yInt == 0 ? UNIT : ZERO; } else { if (yInt == uUNIT) { result = x; } else { result = exp2(mul(log2(x), y)); } } } /// @notice Raises x (an SD59x18 number) to the power y (unsigned basic integer) using the famous algorithm /// algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - All from `abs` and `Common.mulDiv18`. /// - The result must fit within `MAX_SD59x18`. /// /// Caveats: /// - All from `Common.mulDiv18`. /// - Assumes 0^0 is 1. /// /// @param x The base as an SD59x18 number. /// @param y The exponent as an uint256. /// @return result The result as an SD59x18 number. function powu(SD59x18 x, uint256 y) pure returns (SD59x18 result) { uint256 xAbs = uint256(unwrap(abs(x))); // Calculate the first iteration of the loop in advance. uint256 resultAbs = y & 1 > 0 ? xAbs : uint256(uUNIT); // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. uint256 yAux = y; for (yAux >>= 1; yAux > 0; yAux >>= 1) { xAbs = mulDiv18(xAbs, xAbs); // Equivalent to "y % 2 == 1" but faster. if (yAux & 1 > 0) { resultAbs = mulDiv18(resultAbs, xAbs); } } // The result must fit within `MAX_SD59x18`. if (resultAbs > uint256(uMAX_SD59x18)) { revert PRBMath_SD59x18_Powu_Overflow(x, y); } unchecked { // Is the base negative and the exponent an odd number? int256 resultInt = int256(resultAbs); bool isNegative = unwrap(x) < 0 && y & 1 == 1; if (isNegative) { resultInt = -resultInt; } result = wrap(resultInt); } } /// @notice Calculates the square root of x, rounding down. Only the positive root is returned. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x cannot be negative, since this library does not handle complex numbers. /// - x must be less than `MAX_SD59x18` divided by `UNIT`. /// /// @param x The SD59x18 number for which to calculate the square root. /// @return result The result as an SD59x18 number. function sqrt(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = unwrap(x); if (xInt < 0) { revert PRBMath_SD59x18_Sqrt_NegativeInput(x); } if (xInt > uMAX_SD59x18 / uUNIT) { revert PRBMath_SD59x18_Sqrt_Overflow(x); } unchecked { // Multiply x by `UNIT` to account for the factor of `UNIT` that is picked up when multiplying two SD59x18 // numbers together (in this case, the two numbers are both the square root). uint256 resultUint = prbSqrt(uint256(xInt * uUNIT)); result = wrap(int256(resultUint)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { SD59x18 } from "./ValueType.sol"; /// NOTICE: the "u" prefix stands for "unwrapped". /// @dev Euler's number as an SD59x18 number. SD59x18 constant E = SD59x18.wrap(2_718281828459045235); /// @dev Half the UNIT number. int256 constant uHALF_UNIT = 0.5e18; SD59x18 constant HALF_UNIT = SD59x18.wrap(uHALF_UNIT); /// @dev log2(10) as an SD59x18 number. int256 constant uLOG2_10 = 3_321928094887362347; SD59x18 constant LOG2_10 = SD59x18.wrap(uLOG2_10); /// @dev log2(e) as an SD59x18 number. int256 constant uLOG2_E = 1_442695040888963407; SD59x18 constant LOG2_E = SD59x18.wrap(uLOG2_E); /// @dev The maximum value an SD59x18 number can have. int256 constant uMAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_792003956564819967; SD59x18 constant MAX_SD59x18 = SD59x18.wrap(uMAX_SD59x18); /// @dev The maximum whole value an SD59x18 number can have. int256 constant uMAX_WHOLE_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_000000000000000000; SD59x18 constant MAX_WHOLE_SD59x18 = SD59x18.wrap(uMAX_WHOLE_SD59x18); /// @dev The minimum value an SD59x18 number can have. int256 constant uMIN_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_792003956564819968; SD59x18 constant MIN_SD59x18 = SD59x18.wrap(uMIN_SD59x18); /// @dev The minimum whole value an SD59x18 number can have. int256 constant uMIN_WHOLE_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_000000000000000000; SD59x18 constant MIN_WHOLE_SD59x18 = SD59x18.wrap(uMIN_WHOLE_SD59x18); /// @dev PI as an SD59x18 number. SD59x18 constant PI = SD59x18.wrap(3_141592653589793238); /// @dev The unit amount that implies how many trailing decimals can be represented. int256 constant uUNIT = 1e18; SD59x18 constant UNIT = SD59x18.wrap(1e18); /// @dev Zero as an SD59x18 number. SD59x18 constant ZERO = SD59x18.wrap(0);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { SD1x18 } from "./ValueType.sol"; /// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in UD2x18. error PRBMath_SD1x18_ToUD2x18_Underflow(SD1x18 x); /// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in UD60x18. error PRBMath_SD1x18_ToUD60x18_Underflow(SD1x18 x); /// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in uint128. error PRBMath_SD1x18_ToUint128_Underflow(SD1x18 x); /// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in uint256. error PRBMath_SD1x18_ToUint256_Underflow(SD1x18 x); /// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in uint40. error PRBMath_SD1x18_ToUint40_Overflow(SD1x18 x); /// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in uint40. error PRBMath_SD1x18_ToUint40_Underflow(SD1x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { UD60x18 } from "./ValueType.sol"; /// @notice Emitted when ceiling a number overflows UD60x18. error PRBMath_UD60x18_Ceil_Overflow(UD60x18 x); /// @notice Emitted when converting a basic integer to the fixed-point format overflows UD60x18. error PRBMath_UD60x18_Convert_Overflow(uint256 x); /// @notice Emitted when taking the natural exponent of a base greater than 133.084258667509499441. error PRBMath_UD60x18_Exp_InputTooBig(UD60x18 x); /// @notice Emitted when taking the binary exponent of a base greater than 192. error PRBMath_UD60x18_Exp2_InputTooBig(UD60x18 x); /// @notice Emitted when taking the geometric mean of two numbers and multiplying them overflows UD60x18. error PRBMath_UD60x18_Gm_Overflow(UD60x18 x, UD60x18 y); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in SD1x18. error PRBMath_UD60x18_IntoSD1x18_Overflow(UD60x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in SD59x18. error PRBMath_UD60x18_IntoSD59x18_Overflow(UD60x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in UD2x18. error PRBMath_UD60x18_IntoUD2x18_Overflow(UD60x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in uint128. error PRBMath_UD60x18_IntoUint128_Overflow(UD60x18 x); /// @notice Emitted when trying to cast an UD60x18 number that doesn't fit in uint40. error PRBMath_UD60x18_IntoUint40_Overflow(UD60x18 x); /// @notice Emitted when taking the logarithm of a number less than 1. error PRBMath_UD60x18_Log_InputTooSmall(UD60x18 x); /// @notice Emitted when calculating the square root overflows UD60x18. error PRBMath_UD60x18_Sqrt_Overflow(UD60x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { UD60x18 } from "./ValueType.sol"; /// @dev Euler's number as an UD60x18 number. UD60x18 constant E = UD60x18.wrap(2_718281828459045235); /// @dev Half the UNIT number. uint256 constant uHALF_UNIT = 0.5e18; UD60x18 constant HALF_UNIT = UD60x18.wrap(uHALF_UNIT); /// @dev log2(10) as an UD60x18 number. uint256 constant uLOG2_10 = 3_321928094887362347; UD60x18 constant LOG2_10 = UD60x18.wrap(uLOG2_10); /// @dev log2(e) as an UD60x18 number. uint256 constant uLOG2_E = 1_442695040888963407; UD60x18 constant LOG2_E = UD60x18.wrap(uLOG2_E); /// @dev The maximum value an UD60x18 number can have. uint256 constant uMAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935; UD60x18 constant MAX_UD60x18 = UD60x18.wrap(uMAX_UD60x18); /// @dev The maximum whole value an UD60x18 number can have. uint256 constant uMAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000; UD60x18 constant MAX_WHOLE_UD60x18 = UD60x18.wrap(uMAX_WHOLE_UD60x18); /// @dev PI as an UD60x18 number. UD60x18 constant PI = UD60x18.wrap(3_141592653589793238); /// @dev The unit amount that implies how many trailing decimals can be represented. uint256 constant uUNIT = 1e18; UD60x18 constant UNIT = UD60x18.wrap(uUNIT); /// @dev Zero as an UD60x18 number. UD60x18 constant ZERO = UD60x18.wrap(0);
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, ceil} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBCeil { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(ceil(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, div} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBDiv { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return UD60x18.unwrap(div(UD60x18.wrap(a_), UD60x18.wrap(b_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, exp} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBExp { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(exp(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, exp2} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBExp2 { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(exp2(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, floor} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBFloor { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(floor(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, frac} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBFrac { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(frac(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, gm} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBGm { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return UD60x18.unwrap(gm(UD60x18.wrap(a_), UD60x18.wrap(b_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, inv} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBInv { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(inv(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, ln} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBLn { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(ln(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, log10} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBLog10 { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(log10(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, log2} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBLog2 { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(log2(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, mul} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBMul { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return UD60x18.unwrap(mul(UD60x18.wrap(a_), UD60x18.wrap(b_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, pow} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBPow { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return UD60x18.unwrap(pow(UD60x18.wrap(a_), UD60x18.wrap(b_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, powu} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBPowu { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return UD60x18.unwrap(powu(UD60x18.wrap(a_), b_)); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../../deploy/LibIntegrityCheck.sol"; import "../../../run/LibInterpreterState.sol"; import {UD60x18, sqrt} from "@prb/math/src/ud60x18/Math.sol"; library OpPRBSqrt { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_) internal pure returns (uint256) { return UD60x18.unwrap(sqrt(UD60x18.wrap(a_))); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "rain.math.saturating/SaturatingMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpSaturatingAdd /// @notice Opcode for adding N numbers with saturating addition. library OpSaturatingAdd { using SaturatingMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, SaturatingMath.saturatingAdd, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN( SaturatingMath.saturatingAdd, Operand.unwrap(operand_) ); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "rain.math.saturating/SaturatingMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpSaturatingMul /// @notice Opcode for multiplying N numbers with saturating multiplication. library OpSaturatingMul { using SaturatingMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, SaturatingMath.saturatingMul, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN( SaturatingMath.saturatingMul, Operand.unwrap(operand_) ); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "rain.math.saturating/SaturatingMath.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpSaturatingSub /// @notice Opcode for subtracting N numbers with saturating subtraction. library OpSaturatingSub { using SaturatingMath for uint256; using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, SaturatingMath.saturatingSub, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN( SaturatingMath.saturatingSub, Operand.unwrap(operand_) ); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../../array/LibUint256Array.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpAdd /// @notice Opcode for adding N numbers with error on overflow. library OpAdd { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; /// Addition with implied overflow checks from the Solidity 0.8.x compiler. function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return a_ + b_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpDiv /// @notice Opcode for dividing N numbers. library OpDiv { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return a_ / b_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpExp /// @notice Opcode to exponentiate N numbers. library OpExp { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return a_ ** b_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpMax /// @notice Opcode to stack the maximum of N numbers. library OpMax { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return a_ > b_ ? a_ : b_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpMin /// @notice Opcode to stack the minimum of N numbers. library OpMin { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return a_ < b_ ? a_ : b_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpMod /// @notice Opcode to mod N numbers. library OpMod { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return a_ % b_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpMul /// @notice Opcode for multiplying N numbers. library OpMul { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return a_ * b_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpSub /// @notice Opcode for subtracting N numbers. library OpSub { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 a_, uint256 b_) internal pure returns (uint256) { return a_ - b_; } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFnN( stackTop_, f, Operand.unwrap(operand_) ); } function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFnN(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../orderbook/IOrderBookV1.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpIOrderBookV1VaultBalance /// @notice Opcode for IOrderBookV1 `vaultBalance`. library OpIOrderBookV1VaultBalance { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 orderbook_, uint256 owner_, uint256 token_, uint256 id_ ) internal view returns (uint256) { return uint256( uint160( IOrderBookV1(address(uint160(orderbook_))).vaultBalance( address(uint160(owner_)), address(uint160(token_)), id_ ) ) ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../sale/ISaleV2.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpISaleV2RemainingTokenInventory /// @notice Opcode for ISaleV2 `remainingTokenInventory`. library OpISaleV2RemainingTokenInventory { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 sale_) internal view returns (uint256) { return ISaleV2(address(uint160(sale_))).remainingTokenInventory(); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } /// Stack `remainingTokenInventory`. function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; /// An `ISale` can be in one of 4 possible states and a linear progression is /// expected from an "in flight" status to an immutable definitive outcome. /// - Pending: The sale is deployed onchain but cannot be interacted with yet. /// - Active: The sale can now be bought into and otherwise interacted with. /// - Success: The sale has ended AND reached its minimum raise target. /// - Fail: The sale has ended BUT NOT reached its minimum raise target. /// Once an `ISale` reaches `Active` it MUST NOT return `Pending` ever again. /// Once an `ISale` reaches `Success` or `Fail` it MUST NOT return any other /// status ever again. enum SaleStatus { Pending, Active, Success, Fail } interface ISaleV2 { /// Returns the address of the token being sold in the sale. /// MUST NOT change during the lifecycle of the sale contract. function token() external view returns (address); function remainingTokenInventory() external view returns (uint256); /// Returns the address of the token that sale prices are denominated in. /// MUST NOT change during the lifecycle of the sale contract. function reserve() external view returns (address); /// total reserve taken in to the sale contract via. buys. Does NOT /// include any reserve sent directly to the sale contract outside the /// standard buy/refund loop, e.g. due to a dusting attack. function totalReserveReceived() external view returns (uint256); /// Returns the current `SaleStatus` of the sale. /// Represents a linear progression of the sale through its major lifecycle /// events. function saleStatus() external view returns (SaleStatus); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../sale/ISaleV2.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpISaleV2Reserve /// @notice Opcode for ISaleV2 `reserve`. library OpISaleV2Reserve { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 sale_) internal view returns (uint256) { return uint256(uint160(ISaleV2(address(uint160(sale_))).reserve())); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } /// Stack `reserve`. function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../sale/ISaleV2.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpISaleV2SaleStatus /// @notice Opcode for ISaleV2 `saleStatus`. library OpISaleV2SaleStatus { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 sale_) internal view returns (uint256) { return uint(ISaleV2(address(uint160(sale_))).saleStatus()); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } /// Stack `saleStatus`. function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../sale/ISaleV2.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpISaleV2Token /// @notice Opcode for ISaleV2 `token`. library OpISaleV2Token { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 sale_) internal view returns (uint256) { return uint256(uint160(ISaleV2(address(uint160(sale_))).token())); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } /// Stack `token`. function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../sale/ISaleV2.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpISaleV2TotalReserveReceived /// @notice Opcode for ISaleV2 `totalReserveReceived`. library OpISaleV2TotalReserveReceived { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f(uint256 sale_) internal view returns (uint256) { return ISaleV2(address(uint160(sale_))).totalReserveReceived(); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } /// Stack `totalReserveReceived`. function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../../verify/IVerifyV1.sol"; import "../../../run/LibStackPointer.sol"; import "../../../run/LibInterpreterState.sol"; import "../../../deploy/LibIntegrityCheck.sol"; /// @title OpIVerifyV1AccountStatusAtTime /// @notice Opcode for IVerifyV1 `accountStatusAtTime`. library OpIVerifyV1AccountStatusAtTime { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 contract_, uint256 account_, uint256 timestamp_ ) internal view returns (uint256) { return VerifyStatus.unwrap( IVerifyV1(address(uint160(contract_))).accountStatusAtTime( address(uint160(account_)), timestamp_ ) ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } /// Stack `token`. function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; type VerifyStatus is uint256; interface IVerifyV1 { function accountStatusAtTime( address account, uint256 timestamp ) external view returns (VerifyStatus); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "../../../kv/LibMemoryKV.sol"; /// @title OpGet /// @notice Opcode for reading from storage. library OpGet { using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; using LibIntegrityCheck for IntegrityCheckState; using LibMemoryKV for MemoryKV; using LibMemoryKV for MemoryKVPtr; function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { unchecked { // Pop key // Stack value function(uint256) internal pure returns (uint256) fn_; return integrityCheckState_.applyFn(stackTop_, fn_); } } /// Implements runtime behaviour of the `get` opcode. Attempts to lookup the /// key in the memory key/value store then falls back to the interpreter's /// storage interface as an external call. If the key is not found in either, /// the value will fallback to `0` as per default Solidity/EVM behaviour. /// @param interpreterState_ The interpreter state of the current eval. /// @param stackTop_ Pointer to the current stack top. function run( InterpreterState memory interpreterState_, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { uint256 k_; (stackTop_, k_) = stackTop_.pop(); MemoryKVPtr kvPtr_ = interpreterState_.stateKV.getPtr( MemoryKVKey.wrap(k_) ); uint256 v_ = 0; // Cache MISS, get from external store. if (MemoryKVPtr.unwrap(kvPtr_) == 0) { v_ = interpreterState_.store.get(interpreterState_.namespace, k_); // Push fetched value to memory to make subsequent lookups on the // same key find a cache HIT. interpreterState_.stateKV = interpreterState_.stateKV.setVal( MemoryKVKey.wrap(k_), MemoryKVVal.wrap(v_) ); } // Cache HIT. else { v_ = MemoryKVVal.unwrap(kvPtr_.readPtrVal()); } return stackTop_.push(v_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "../../../kv/LibMemoryKV.sol"; /// @title OpSet /// @notice Opcode for recording k/v state changes to be set in storage. library OpSet { using LibStackPointer for StackPointer; using LibInterpreterState for InterpreterState; using LibIntegrityCheck for IntegrityCheckState; using LibMemoryKV for MemoryKV; function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { unchecked { function(uint256, uint256) internal pure fn_; return integrityCheckState_.applyFn(stackTop_, fn_); } } function run( InterpreterState memory state_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { unchecked { uint256 k_; uint256 v_; (stackTop_, v_) = stackTop_.pop(); (stackTop_, k_) = stackTop_.pop(); state_.stateKV = state_.stateKV.setVal( MemoryKVKey.wrap(k_), MemoryKVVal.wrap(v_) ); return stackTop_; } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../tier/ITierV2.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpITierV2Report /// @notice Exposes `ITierV2.report` as an opcode. library OpITierV2Report { using LibStackPointer for StackPointer; using LibStackPointer for uint256[]; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 tierContract_, uint256 account_, uint256[] memory context_ ) internal view returns (uint256) { return ITierV2(address(uint160(tierContract_))).report( address(uint160(account_)), context_ ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn( stackTop_, f, Operand.unwrap(operand_) ); } // Stack the `report` returned by an `ITierV2` contract. function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer stackTopAfter_) { return stackTop_.applyFn(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; /// @title ITierV2 /// @notice `ITierV2` is a simple interface that contracts can implement to /// provide membership lists for other contracts. /// /// There are many use-cases for a time-preserving conditional membership list. /// /// Some examples include: /// /// - Self-serve whitelist to participate in fundraising /// - Lists of users who can claim airdrops and perks /// - Pooling resources with implied governance/reward tiers /// - POAP style attendance proofs allowing access to future exclusive events /// /// @dev Standard interface to a tiered membership. /// /// A "membership" can represent many things: /// - Exclusive access. /// - Participation in some event or process. /// - KYC completion. /// - Combination of sub-memberships. /// - Etc. /// /// The high level requirements for a contract implementing `ITierV2`: /// - MUST represent held tiers as a `uint`. /// - MUST implement `report`. /// - The report is a `uint256` that SHOULD represent the time each tier has /// been continuously held since encoded as `uint32`. /// - The encoded tiers start at `1`; Tier `0` is implied if no tier has ever /// been held. /// - Tier `0` is NOT encoded in the report, it is simply the fallback value. /// - If a tier is lost the time data is erased for that tier and will be /// set if/when the tier is regained to the new time. /// - If a tier is held but the historical time information is not available /// the report MAY return `0x00000000` for all held tiers. /// - Tiers that are lost or have never been held MUST return `0xFFFFFFFF`. /// - Context can be a list of numbers that MAY pairwise define tiers such as /// minimum thresholds, or MAY simply provide global context such as a /// relevant NFT ID for example. /// - MUST implement `reportTimeForTier` /// - Functions exactly as `report` but only returns a single time for a /// single tier /// - MUST return the same time value `report` would for any given tier and /// context combination. /// /// So the four possible states and report values are: /// - Tier is held and time is known: Timestamp is in the report /// - Tier is held but time is NOT known: `0` is in the report /// - Tier is NOT held: `0xFF..` is in the report /// - Tier is unknown: `0xFF..` is in the report /// /// The reason `context` is specified as a list of values rather than arbitrary /// bytes is to allow clear and efficient compatibility with interpreter stacks. /// Some N values can be taken from an interpreter stack and used directly as a /// context, which would be difficult or impossible to ensure is safe for /// arbitrary bytes. interface ITierV2 { /// Same as report but only returns the time for a single tier. /// Often the implementing contract can calculate a single tier more /// efficiently than all 8 tiers. If the consumer only needs one or a few /// tiers it MAY be much cheaper to request only those tiers individually. /// This DOES NOT apply to all contracts, an obvious example is token /// balance based tiers which always return `ALWAYS` or `NEVER` for all /// tiers so no efficiency is gained. /// The return value is a `uint256` for gas efficiency but the values will /// be bounded by `type(uint32).max` as no single tier can report a value /// higher than this. /// @param account The address to get a report time for. /// @param tier The tier that the address MUST have held CONTINUOUSLY since /// some time. /// @param context Additional data the `ITierV2` contract MAY use to /// calculate the report time. /// @return time The time that the tier has been held continuously since, or /// `type(uint32).max` if the tier has never been held. function reportTimeForTier( address account, uint256 tier, uint256[] calldata context ) external view returns (uint256 time); /// Returns an 8 tier encoded report of 32 bit timestamps for the given /// account. /// /// Same as `ITier` (legacy interface) but with a list of values for /// `context` which allows a single underlying state to present many /// different reports dynamically. /// /// For example: /// - Staking ledgers can calculate different tier thresholds /// - NFTs can give different tiers based on different IDs /// - Snapshot ERC20s can give different reports based on snapshot ID /// /// `context` supercedes `setTier` function and `TierChange` event from /// `ITier` at the interface level. /// @param account The address to get the report for. /// @param context Additional data the `ITierV2` contract MAY use to /// calculate the report. /// @return times All of the times for every tier the `account` has held /// continuously, encoded as 8x `uint32` values within a single `uint256`. function report( address account, uint256[] calldata context ) external view returns (uint256 times); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../tier/ITierV2.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; /// @title OpITierV2Report /// @notice Exposes `ITierV2.reportTimeForTier` as an opcode. library OpITierV2ReportTimeForTier { using LibStackPointer for StackPointer; using LibStackPointer for uint256[]; using LibIntegrityCheck for IntegrityCheckState; function f( uint256 tierContract_, uint256 account_, uint256 tier_, uint256[] memory context_ ) internal view returns (uint256) { return ITierV2(address(uint160(tierContract_))).reportTimeForTier( address(uint160(account_)), tier_, context_ ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn( stackTop_, f, Operand.unwrap(operand_) ); } // Stack the `reportTimeForTier` returned by an `ITierV2` contract. function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, Operand.unwrap(operand_)); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../tier/libraries/TierwiseCombine.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; library OpSaturatingDiff { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn( stackTop_, TierwiseCombine.saturatingSub ); } // Stack the tierwise saturating subtraction of two reports. // If the older report is newer than newer report the result will // be `0`, else a tierwise diff in blocks will be obtained. // The older and newer report are taken from the stack. function run( InterpreterState memory, Operand, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(TierwiseCombine.saturatingSub); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; import {MathUpgradeable as Math} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import "./TierReport.sol"; import "rain.math.saturating/SaturatingMath.sol"; /// @dev Every lte check in `selectLte` must pass. uint256 constant TIERWISE_COMBINE_LOGIC_EVERY = 0; /// @dev Only one lte check in `selectLte` must pass. uint256 constant TIERWISE_COMBINE_LOGIC_ANY = 1; /// @dev Select the minimum block number from passing blocks in `selectLte`. uint256 constant TIERWISE_COMBINE_MODE_MIN = 0; /// @dev Select the maximum block number from passing blocks in `selectLte`. uint256 constant TIERWISE_COMBINE_MODE_MAX = 1; /// @dev Select the first block number that passes in `selectLte`. uint256 constant TIERWISE_COMBINE_MODE_FIRST = 2; library TierwiseCombine { using Math for uint256; using SaturatingMath for uint256; /// Performs a tierwise saturating subtraction of two reports. /// Intepret as "# of blocks older report was held before newer report". /// If older report is in fact newer then `0` will be returned. /// i.e. the diff cannot be negative, older report as simply spent 0 blocks /// existing before newer report, if it is in truth the newer report. /// @param newerReport_ Block to subtract from. /// @param olderReport_ Block to subtract. function saturatingSub( uint256 newerReport_, uint256 olderReport_ ) internal pure returns (uint256) { unchecked { uint256 ret_; for (uint256 tier_ = 1; tier_ <= 8; tier_++) { uint256 newerBlock_ = TierReport.reportTimeForTier( newerReport_, tier_ ); uint256 olderBlock_ = TierReport.reportTimeForTier( olderReport_, tier_ ); uint256 diff_ = newerBlock_.saturatingSub(olderBlock_); ret_ = TierReport.updateTimeAtTier(ret_, tier_ - 1, diff_); } return ret_; } } /// Given a list of reports, selects the best tier in a tierwise fashion. /// The "best" criteria can be configured by `logic_` and `mode_`. /// Logic can be "every" or "any", which means that the reports for a given /// tier must either all or any be less than or equal to the reference /// `blockNumber_`. /// Mode can be "min", "max", "first" which selects between all the block /// numbers for a given tier that meet the lte criteria. /// IMPORTANT: If the output of `selectLte` is used to write to storage /// care must be taken to ensure that "upcoming" tiers relative to the /// `blockNumber_` are not overwritten inappropriately. Typically this /// function should be used as a filter over reads only from an upstream /// source of truth. /// @param reports_ The list of reports to select over. /// @param blockNumber_ The block number that tier blocks must be lte. /// @param logic_ `LOGIC_EVERY` or `LOGIC_ANY`. /// @param mode_ `MODE_MIN`, `MODE_MAX` or `MODE_FIRST`. function selectLte( uint256 logic_, uint256 mode_, uint256 blockNumber_, uint256[] memory reports_ ) internal pure returns (uint256) { unchecked { uint256 ret_; uint256 block_; bool anyLte_; uint256 length_ = reports_.length; for (uint256 tier_ = 1; tier_ <= 8; tier_++) { uint256 accumulator_; // Nothing lte the reference block for this tier yet. anyLte_ = false; // Initialize the accumulator for this tier. if (mode_ == TIERWISE_COMBINE_MODE_MIN) { accumulator_ = TierConstants.NEVER_REPORT; } else { accumulator_ = 0; } // Filter all the blocks at the current tier from all the // reports against the reference tier and each other. for (uint256 i_ = 0; i_ < length_; i_++) { block_ = TierReport.reportTimeForTier(reports_[i_], tier_); if (block_ <= blockNumber_) { // Min and max need to compare current value against // the accumulator. if (mode_ == TIERWISE_COMBINE_MODE_MIN) { accumulator_ = block_.min(accumulator_); } else if (mode_ == TIERWISE_COMBINE_MODE_MAX) { accumulator_ = block_.max(accumulator_); } else if ( mode_ == TIERWISE_COMBINE_MODE_FIRST && !anyLte_ ) { accumulator_ = block_; } anyLte_ = true; } else if (logic_ == TIERWISE_COMBINE_LOGIC_EVERY) { // Can short circuit for an "every" check. accumulator_ = TierConstants.NEVER_REPORT; break; } } if (!anyLte_) { accumulator_ = TierConstants.NEVER_REPORT; } ret_ = TierReport.updateTimeAtTier( ret_, tier_ - 1, accumulator_ ); } return ret_; } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; import {ITierV2} from "../ITierV2.sol"; import "./TierConstants.sol"; /// @title TierReport /// @notice `TierReport` implements several pure functions that can be /// used to interface with reports. /// - `tierAtTimeFromReport`: Returns the highest status achieved relative to /// a block timestamp and report. Statuses gained after that block are ignored. /// - `tierTime`: Returns the timestamp that a given tier has been held /// since according to a report. /// - `truncateTiersAbove`: Resets all the tiers above the reference tier. /// - `updateTimesForTierRange`: Updates a report with a timestamp for every /// tier in a range. /// - `updateReportWithTierAtTime`: Updates a report to a new tier. /// @dev Utilities to consistently read, write and manipulate tiers in reports. /// The low-level bit shifting can be difficult to get right so this /// factors that out. library TierReport { /// Enforce upper limit on tiers so we can do unchecked math. /// @param tier_ The tier to enforce bounds on. modifier maxTier(uint256 tier_) { require(tier_ <= TierConstants.MAX_TIER, "MAX_TIER"); _; } /// Returns the highest tier achieved relative to a block timestamp /// and report. /// /// Note that typically the report will be from the _current_ contract /// state, i.e. `block.timestamp` but not always. Tiers gained after the /// reference time are ignored. /// /// When the `report` comes from a later block than the `timestamp_` this /// means the user must have held the tier continuously from `timestamp_` /// _through_ to the report time. /// I.e. NOT a snapshot. /// /// @param report_ A report as per `ITierV2`. /// @param timestamp_ The timestamp to check the tiers against. /// @return tier_ The highest tier held since `timestamp_` as per `report`. function tierAtTimeFromReport( uint256 report_, uint256 timestamp_ ) internal pure returns (uint256 tier_) { unchecked { for (tier_ = 0; tier_ < 8; tier_++) { if (uint32(uint256(report_ >> (tier_ * 32))) > timestamp_) { break; } } } } /// Returns the timestamp that a given tier has been held since from a /// report. /// /// The report MUST encode "never" as 0xFFFFFFFF. This ensures /// compatibility with `tierAtTimeFromReport`. /// /// @param report_ The report to read a timestamp from. /// @param tier_ The Tier to read the timestamp for. /// @return The timestamp the tier has been held since. function reportTimeForTier( uint256 report_, uint256 tier_ ) internal pure maxTier(tier_) returns (uint256) { unchecked { // ZERO is a special case. Everyone has always been at least ZERO, // since block 0. if (tier_ == 0) { return 0; } uint256 offset_ = (tier_ - 1) * 32; return uint256(uint32(uint256(report_ >> offset_))); } } /// Resets all the tiers above the reference tier to 0xFFFFFFFF. /// /// @param report_ Report to truncate with high bit 1s. /// @param tier_ Tier to truncate above (exclusive). /// @return Truncated report. function truncateTiersAbove( uint256 report_, uint256 tier_ ) internal pure maxTier(tier_) returns (uint256) { unchecked { uint256 offset_ = tier_ * 32; uint256 mask_ = (TierConstants.NEVER_REPORT >> offset_) << offset_; return report_ | mask_; } } /// Updates a report with a timestamp for a given tier. /// More gas efficient than `updateTimesForTierRange` if only a single /// tier is being modified. /// The tier at/above the given tier is updated. E.g. tier `0` will update /// the time for tier `1`. /// @param report_ Report to use as the baseline for the updated report. /// @param tier_ The tier level to update. /// @param timestamp_ The new block number for `tier_`. /// @return The newly updated `report_`. function updateTimeAtTier( uint256 report_, uint256 tier_, uint256 timestamp_ ) internal pure maxTier(tier_) returns (uint256) { unchecked { uint256 offset_ = tier_ * 32; return (report_ & ~uint256(uint256(TierConstants.NEVER_TIME) << offset_)) | uint256(timestamp_ << offset_); } } /// Updates a report with a block number for every tier in a range. /// /// Does nothing if the end status is equal or less than the start tier. /// @param report_ The report to update. /// @param startTier_ The tier at the start of the range (exclusive). /// @param endTier_ The tier at the end of the range (inclusive). /// @param timestamp_ The timestamp to set for every tier in the range. /// @return The updated report. function updateTimesForTierRange( uint256 report_, uint256 startTier_, uint256 endTier_, uint256 timestamp_ ) internal pure maxTier(endTier_) returns (uint256) { unchecked { uint256 offset_; for (uint256 i_ = startTier_; i_ < endTier_; i_++) { offset_ = i_ * 32; report_ = (report_ & ~uint256( uint256(TierConstants.NEVER_TIME) << offset_ )) | uint256(timestamp_ << offset_); } return report_; } } /// Updates a report to a new status. /// /// Internally dispatches to `truncateTiersAbove` and /// `updateBlocksForTierRange`. /// The dispatch is based on whether the new tier is above or below the /// current tier. /// The `startTier_` MUST match the result of `tierAtBlockFromReport`. /// It is expected the caller will know the current tier when /// calling this function and need to do other things in the calling scope /// with it. /// /// @param report_ The report to update. /// @param startTier_ The tier to start updating relative to. Data above /// this tier WILL BE LOST so probably should be the current tier. /// @param endTier_ The new highest tier held, at the given timestamp_. /// @param timestamp_ The timestamp_ to update the highest tier to, and /// intermediate tiers from `startTier_`. /// @return The updated report. function updateReportWithTierAtTime( uint256 report_, uint256 startTier_, uint256 endTier_, uint256 timestamp_ ) internal pure returns (uint256) { return endTier_ < startTier_ ? truncateTiersAbove(report_, endTier_) : updateTimesForTierRange( report_, startTier_, endTier_, timestamp_ ); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; /// @title TierConstants /// @notice Constants for use with tier logic. library TierConstants { /// NEVER is 0xFF.. as it is infinitely in the future. /// NEVER for an entire report. uint256 internal constant NEVER_REPORT = type(uint256).max; /// NEVER for a single tier time. uint32 internal constant NEVER_TIME = type(uint32).max; /// Always is 0 as negative timestamps are not possible/supported onchain. /// Tiers can't predate the chain but they can predate an `ITierV2` /// contract. uint256 internal constant ALWAYS = 0; /// Account has never held a tier. uint256 internal constant TIER_ZERO = 0; /// Magic number for tier one. uint256 internal constant TIER_ONE = 1; /// Magic number for tier two. uint256 internal constant TIER_TWO = 2; /// Magic number for tier three. uint256 internal constant TIER_THREE = 3; /// Magic number for tier four. uint256 internal constant TIER_FOUR = 4; /// Magic number for tier five. uint256 internal constant TIER_FIVE = 5; /// Magic number for tier six. uint256 internal constant TIER_SIX = 6; /// Magic number for tier seven. uint256 internal constant TIER_SEVEN = 7; /// Magic number for tier eight. uint256 internal constant TIER_EIGHT = 8; /// Maximum tier is `TIER_EIGHT`. uint256 internal constant MAX_TIER = TIER_EIGHT; }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../tier/libraries/TierwiseCombine.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; import "sol.lib.binmaskflag/Binary.sol"; /// Zero inputs to select lte is NOT supported. error ZeroInputs(); /// @title OpSelectLte /// @notice Exposes `TierwiseCombine.selectLte` as an opcode. library OpSelectLte { using LibStackPointer for StackPointer; using LibStackPointer for uint256[]; using LibIntegrityCheck for IntegrityCheckState; function integrity( IntegrityCheckState memory integrityCheckState_, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { unchecked { uint256 inputs_ = Operand.unwrap(operand_) & MASK_8BIT; if (inputs_ == 0) { revert ZeroInputs(); } return integrityCheckState_.push( integrityCheckState_.pop(stackTop_, inputs_) ); } } // Stacks the result of a `selectLte` combinator. // All `selectLte` share the same stack and argument handling. // Takes the `logic_` and `mode_` from the `operand_` high bits. // `logic_` is the highest bit. // `mode_` is the 2 highest bits after `logic_`. // The other bits specify how many values to take from the stack // as reports to compare against each other and the block number. function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal pure returns (StackPointer) { unchecked { uint256 inputs_ = Operand.unwrap(operand_) & MASK_8BIT; uint256 mode_ = (Operand.unwrap(operand_) >> 8) & MASK_2BIT; uint256 logic_ = Operand.unwrap(operand_) >> 10; (uint256 time_, uint256[] memory reports_) = stackTop_.list( inputs_ ); return reports_.asStackPointer().push( TierwiseCombine.selectLte(logic_, mode_, time_, reports_) ); } } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.15; import "../../../tier/libraries/TierReport.sol"; import "../../run/LibStackPointer.sol"; import "../../run/LibInterpreterState.sol"; import "../../deploy/LibIntegrityCheck.sol"; library OpUpdateTimesForTierRange { using LibStackPointer for StackPointer; using LibIntegrityCheck for IntegrityCheckState; function f( Operand operand_, uint256 report_, uint256 timestamp_ ) internal pure returns (uint256) { return TierReport.updateTimesForTierRange( report_, // start tier. // 4 low bits. Operand.unwrap(operand_) & 0x0f, // end tier. // 4 high bits. (Operand.unwrap(operand_) >> 4) & 0x0f, timestamp_ ); } function integrity( IntegrityCheckState memory integrityCheckState_, Operand, StackPointer stackTop_ ) internal pure returns (StackPointer) { return integrityCheckState_.applyFn(stackTop_, f); } // Stacks a report with updated times over tier range. // The start and end tier are taken from the low and high bits of // the `operand_` respectively. // The report to update and timestamp to update to are both // taken from the stack. function run( InterpreterState memory, Operand operand_, StackPointer stackTop_ ) internal view returns (StackPointer) { return stackTop_.applyFn(f, operand_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.0; import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {SafeERC20Upgradeable as SafeERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import {MathUpgradeable as Math} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import "../ierc3156/IERC3156FlashBorrower.sol"; import "../ierc3156/IERC3156FlashLender.sol"; /// Thrown when `flashLoan` token is zero address. error ZeroToken(); /// Thrown when `flashLoadn` receiver is zero address. error ZeroReceiver(); /// Thrown when the `onFlashLoan` callback returns anything other than /// ON_FLASH_LOAN_CALLBACK_SUCCESS. /// @param result The value that was returned by `onFlashLoan`. error FlashLenderCallbackFailed(bytes32 result); /// Thrown when more than one debt is attempted simultaneously. /// @param receiver The receiver of the active debt. /// @param token The token of the active debt. /// @param amount The amount of the active debt. error ActiveDebt(address receiver, address token, uint256 amount); /// @dev The ERC3156 spec mandates this hash be returned by `onFlashLoan`. bytes32 constant ON_FLASH_LOAN_CALLBACK_SUCCESS = keccak256( "ERC3156FlashBorrower.onFlashLoan" ); /// @dev Flash fee is always 0 for orderbook as there's no entity to take /// revenue for `Orderbook` and its more important anyway that flashloans happen /// to connect external liquidity to live orders via arbitrage. uint256 constant FLASH_FEE = 0; /// @title OrderBookFlashLender /// @notice Implements `IERC3156FlashLender` for `OrderBook`. Based on the /// reference implementation by Alberto Cuesta Cañada found at /// https://eips.ethereum.org/EIPS/eip-3156 /// Several features found in the reference implementation are simplified or /// hardcoded for `Orderbook`. contract OrderBookFlashLender is IERC3156FlashLender { using SafeERC20 for IERC20; using Math for uint256; IERC3156FlashBorrower private _receiver = IERC3156FlashBorrower(address(0)); address private _token = address(0); uint256 private _amount = 0; function _isActiveDebt() internal view returns (bool) { return (address(_receiver) != address(0) || _token != address(0) || _amount != 0); } function _checkActiveDebt() internal view { if (_isActiveDebt()) { revert ActiveDebt(address(_receiver), _token, _amount); } } /// Whenever `Orderbook` sends tokens to any address it MUST first attempt /// to decrease any outstanding flash loans for that address. Consider the /// case that Alice deposits 100 TKN and she is the only depositor of TKN /// then flash borrows 100 TKN. If she attempts to withdraw 100 TKN during /// her `onFlashLoan` callback then `Orderbook`: /// /// - has 0 TKN balance to process the withdrawal /// - MUST process the withdrawal as Alice has the right to withdraw her /// balance at any time /// - Has the 100 TKN debt active under Alice /// /// In this case `Orderbook` can simply forgive Alice's 100 TKN debt instead /// of actually transferring any tokens. The withdrawal can decrease her /// vault balance by 100 TKN decoupled from needing to know whether a /// tranfer or forgiveness happened. /// /// The same logic applies to withdrawals as sending tokens during /// `takeOrders` as the reason for sending tokens is irrelevant, all that /// matters is that `Orderbook` prioritises debt repayments over external /// transfers. /// /// If there is an active debt that only partially eclipses the withdrawal /// then the debt will be fully repaid and the remainder transferred as a /// real token transfer. /// /// Note that Alice can still contrive a situation that causes `Orderbook` /// to attempt to send tokens that it does not have. If Alice can write a /// smart contract to trigger withdrawals she can flash loan 100% of the /// TKN supply in `Orderbook` and trigger her contract to attempt a /// withdrawal. For any normal ERC20 token this will fail and revert as the /// `Orderbook` cannot send tokens it does not have under any circumstances, /// but the scenario is worth being aware of for more exotic token /// behaviours that may not be supported. /// /// @param token_ The token being sent or for the debt being paid. /// @param receiver_ The receiver of the token or holder of the debt. /// @param sendAmount_ The amount to send or repay. function _decreaseFlashDebtThenSendToken( address token_, address receiver_, uint256 sendAmount_ ) internal { // If this token transfer matches the active debt then prioritise // reducing debt over sending tokens. if (token_ == _token && receiver_ == address(_receiver)) { uint256 debtReduction_ = sendAmount_.min(_amount); sendAmount_ -= debtReduction_; // Even if this completely zeros the amount the debt is considered // active until the `flashLoan` also clears the token and recipient. _amount -= debtReduction_; } if (sendAmount_ > 0) { IERC20(token_).safeTransfer(receiver_, sendAmount_); } } /// @inheritdoc IERC3156FlashLender function flashLoan( IERC3156FlashBorrower receiver_, address token_, uint256 amount_, bytes calldata data_ ) external override returns (bool) { // This prevents reentrancy, loans can be taken sequentially within a // transaction but not simultanously. _checkActiveDebt(); // Set the active debt before transferring tokens to prevent reeentrancy. // The active debt is set beyond the scope of `flashLoan` to facilitate // early repayment via. `_decreaseFlashDebtThenSendToken`. { if (token_ == address(0)) { revert ZeroToken(); } if (address(receiver_) == address(0)) { revert ZeroReceiver(); } _token = token_; _receiver = receiver_; _amount = amount_; if (amount_ > 0) { IERC20(token_).safeTransfer(address(receiver_), amount_); } } bytes32 result_ = receiver_.onFlashLoan( // initiator msg.sender, // token token_, // amount amount_, // fee 0, // data data_ ); if (result_ != ON_FLASH_LOAN_CALLBACK_SUCCESS) { revert FlashLenderCallbackFailed(result_); } // Pull tokens before releasing the active debt to prevent a new loan // from being taken reentrantly during the repayment of the current loan. { // Sync local `amount_` with global `_amount` in case an early // repayment was made during the loan term via. // `_decreaseFlashDebtThenSendToken`. amount_ = _amount; if (amount_ > 0) { IERC20(_token).safeTransferFrom( address(_receiver), address(this), amount_ ); _amount = 0; } // Both of these are required to fully clear the active debt and // allow new debts. _receiver = IERC3156FlashBorrower(address(0)); _token = address(0); } // Guard against some bad code path that allowed an active debt to remain // at this point. Should be impossible. _checkActiveDebt(); return true; } /// @inheritdoc IERC3156FlashLender function flashFee( address, uint256 ) external pure override returns (uint256) { return FLASH_FEE; } /// There's no limit to the size of a flash loan from `Orderbook` other than /// the current tokens deposited in `Orderbook`. If there is an active debt /// then loans are disabled so the max becomes `0` until after repayment. /// @inheritdoc IERC3156FlashLender function maxFlashLoan( address token_ ) external view override returns (uint256) { return _isActiveDebt() ? 0 : IERC20(token_).balanceOf(address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/draft-IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; function safeTransfer( IERC20Upgradeable token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20Upgradeable token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20Upgradeable token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "./IInterpreterV1.sol"; /// @title LibEncodedDispatch /// @notice Establishes and implements a convention for encoding an interpreter /// dispatch. Handles encoding of several things required for efficient dispatch. library LibEncodedDispatch { /// Builds an `EncodedDispatch` from its constituent parts. /// @param expression_ The onchain address of the expression to run. /// @param sourceIndex_ The index of the source to run within the expression /// as an entrypoint. /// @param maxOutputs_ The maximum outputs the caller can meaningfully use. /// If the interpreter returns a larger stack than this it is merely wasting /// gas across the external call boundary. /// @return The encoded dispatch. function encode( address expression_, SourceIndex sourceIndex_, uint256 maxOutputs_ ) internal pure returns (EncodedDispatch) { return EncodedDispatch.wrap( (uint256(uint160(expression_)) << 32) | (SourceIndex.unwrap(sourceIndex_) << 16) | maxOutputs_ ); } /// Decodes an `EncodedDispatch` to its constituent parts. /// @param dispatch_ The `EncodedDispatch` to decode. /// @return The expression, source index, and max outputs as per `encode`. function decode( EncodedDispatch dispatch_ ) internal pure returns (address, SourceIndex, uint256) { return ( address(uint160(EncodedDispatch.unwrap(dispatch_) >> 32)), SourceIndex.wrap((EncodedDispatch.unwrap(dispatch_) >> 16) & 0xFF), EncodedDispatch.unwrap(dispatch_) & 0xFF ); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../../array/LibUint256Array.sol"; import {SignatureCheckerUpgradeable as SignatureChecker} from "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol"; import {ECDSAUpgradeable as ECDSA} from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; import "./IInterpreterCallerV1.sol"; /// Thrown when the ith signature from a list of signed contexts is invalid. error InvalidSignature(uint256 i); /// @title LibContext /// @notice Conventions for working with context as a calling contract. All of /// this functionality is OPTIONAL but probably useful for the majority of use /// cases. By building and authenticating onchain, caller provided and signed /// contexts all in a standard way the overall usability of context is greatly /// improved for expression authors and readers. Any calling contract that can /// match the context expectations of an existing expression is one large step /// closer to compatibility and portability, inheriting network effects of what /// has already been authored elsewhere. library LibContext { using LibUint256Array for uint256[]; /// The base context is the `msg.sender` and address of the calling contract. /// As the interpreter itself is called via an external interface and may be /// statically calling itself, it MAY NOT have any ability to inspect either /// of these values. Even if this were not the case the calling contract /// cannot assume the existence of some opcode(s) in the interpreter that /// inspect the caller, so providing these two values as context is /// sufficient to decouple the calling contract from the interpreter. It is /// STRONGLY RECOMMENDED that even if the calling contract has "no context" /// that it still provides this base to every `eval`. /// /// Calling contracts DO NOT need to call this directly. It is built and /// merged automatically into the standard context built by `build`. /// /// @return The `msg.sender` and address of the calling contract using this /// library, as a context-compatible array. function base() internal view returns (uint256[] memory) { return LibUint256Array.arrayFrom( uint(uint160(msg.sender)), uint(uint160(address(this))) ); } /// Standard hashing process over a list of signed contexts. Situationally /// useful if the calling contract wants to record that it has seen a set of /// signed data then later compare it against some input (e.g. to ensure that /// many calls of some function all share the same input values). Note that /// unlike the internals of `build`, this hashes over the signer and the /// signature, to ensure that some data cannot be re-signed and used under /// a different provenance later. /// @param signedContexts_ The list of signed contexts to hash over. /// @return The hash of the signed contexts. function hash( SignedContext[] memory signedContexts_ ) internal pure returns (bytes32) { // Note the use of abi.encode rather than abi.encodePacked here to guard // against potential issues due to multiple different inputs colliding // on a common encoded output. return keccak256(abi.encode(signedContexts_)); } /// Builds a standard 2-dimensional context array from base, calling and /// signed contexts. Note that "columns" of a context array refer to each /// `uint256[]` and each item within a `uint256[]` is a "row". /// /// @param baseContext_ Anything the calling contract can provide without /// input from the `msg.sender`. More strictly the `msg.sender` MUST NOT be /// able to directly modify any of these values, although the values MAY be /// derived from user activity broadly, such as current vault balances after /// a series of deposits and withdrawals. The default base context from /// `LibContext.base()` DOES NOT need to be provided by the caller, this /// matrix MAY be empty and will be simply merged into the final context. The /// base context matrix MUST contain a consistent number of columns from the /// calling contract so that the expression can always predict how many /// columns there will be when it runs. /// @param callingContext_ Calling context is provided by the `msg.sender` /// and so should be treated as self-signed data. As an attestation/proof of /// some external event or state it is highly suspect, but as an indicator /// of the intent of `msg.sender` it may be treated as gospel. Calling /// context MAY be empty but a zero length column will still be reserved in /// the final built context. This ensures that expressions can always /// predict how many columns there will be when they run. /// @param signedContexts_ Signed contexts are provided by the `msg.sender` /// but signed by a third party. The expression (author) defines _who_ may /// sign and the calling contract authenticates the signature over the /// signed data. Technically `build` handles all the authentication inline /// for the calling contract so if some context builds it can be treated as /// authentic. The builder WILL REVERT if any of the signatures are invalid. /// Note two things about the structure of the final built context re: signed /// contexts: /// - The first column is a list of the signers in order of what they signed /// - The `msg.sender` can provide an arbitrary number of signed contexts so /// expressions DO NOT know exactly how many columns there are. /// The expression is responsible for defining e.g. a domain separator in a /// position that would force signed context to be provided in the "correct" /// order, rather than relying on the `msg.sender` to honestly present data /// in any particular structure/order. function build( uint256[][] memory baseContext_, uint256[] memory callingContext_, SignedContext[] memory signedContexts_ ) internal view returns (uint256[][] memory) { unchecked { uint256[] memory signers_ = new uint256[](signedContexts_.length); // - LibContext.base() + whatever we are provided. // - calling context always even if empty // - signed contexts + signers if they exist else nothing. uint256 contextLength_ = 1 + baseContext_.length + 1 + (signedContexts_.length > 0 ? signedContexts_.length + 1 : 0); uint256[][] memory context_ = new uint256[][](contextLength_); uint256 offset_ = 0; context_[offset_] = LibContext.base(); for (uint256 i_ = 0; i_ < baseContext_.length; i_++) { offset_++; context_[offset_] = baseContext_[i_]; } // Calling context is added unconditionally so that a 0 length array // is simply an empty column. We don't want callers to be able to // manipulate the overall structure of context columns that the // expression indexes into. offset_++; context_[offset_] = callingContext_; if (signedContexts_.length > 0) { offset_++; context_[offset_] = signers_; for (uint256 i_ = 0; i_ < signedContexts_.length; i_++) { if ( !SignatureChecker.isValidSignatureNow( signedContexts_[i_].signer, ECDSA.toEthSignedMessageHash( // Unlike `LibContext.hash` we can only hash over // the context as it's impossible for a signature // to sign itself. // Note the use of encodePacked here over a // single array, not including the length. This // would be a security issue if multiple dynamic // length values were hashed over together as // then many possible inputs could collide with // a single encoded output. keccak256( abi.encodePacked( signedContexts_[i_].context ) ) ), signedContexts_[i_].signature ) ) { revert InvalidSignature(i_); } signers_[i_] = uint256(uint160(signedContexts_[i_].signer)); offset_++; context_[offset_] = signedContexts_[i_].context; } } return context_; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/SignatureChecker.sol) pragma solidity ^0.8.0; import "./ECDSAUpgradeable.sol"; import "../AddressUpgradeable.sol"; import "../../interfaces/IERC1271Upgradeable.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like * Argent and Gnosis Safe. * * _Available since v4.1._ */ library SignatureCheckerUpgradeable { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidSignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (address recovered, ECDSAUpgradeable.RecoverError error) = ECDSAUpgradeable.tryRecover(hash, signature); if (error == ECDSAUpgradeable.RecoverError.NoError && recovered == signer) { return true; } (bool success, bytes memory result) = signer.staticcall( abi.encodeWithSelector(IERC1271Upgradeable.isValidSignature.selector, hash, signature) ); return (success && result.length == 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271Upgradeable.isValidSignature.selector)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../StringsUpgradeable.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. * * _Available since v4.1._ */ interface IERC1271Upgradeable { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "sol.metadata/IMetaV1.sol"; import "sol.metadata/LibMeta.sol"; import "./LibDeployerDiscoverable.sol"; struct DeployerDiscoverableMetaV1ConstructionConfig { address deployer; bytes meta; } /// @title DeployerDiscoverableMetaV1 /// @notice Checks metadata against a known hash, emits it then touches the /// deployer (deploy an empty expression). This allows indexers to discover the /// metadata of the `DeployerDiscoverableMetaV1` contract by indexing the /// deployer. In this way the deployer acts as a pseudo-registry by virtue of it /// being a natural hub for interactions. abstract contract DeployerDiscoverableMetaV1 is IMetaV1 { constructor( bytes32 metaHash_, DeployerDiscoverableMetaV1ConstructionConfig memory config_ ) { LibMeta.checkMetaHashed(metaHash_, config_.meta); emit MetaV1(msg.sender, uint256(uint160(address(this))), config_.meta); LibDeployerDiscoverable.touchDeployer(config_.deployer); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.18; /// Thrown when hashed metadata does NOT match the expected hash. /// @param expectedHash The hash expected by the `IMetaV1` contract. /// @param actualHash The hash of the metadata seen by the `IMetaV1` contract. error UnexpectedMetaHash(bytes32 expectedHash, bytes32 actualHash); /// Thrown when some bytes are expected to be rain meta and are not. /// @param unmeta the bytes that are not meta. error NotRainMetaV1(bytes unmeta); /// @dev Randomly generated magic number with first bytes oned out. /// https://github.com/rainprotocol/specs/blob/main/metadata-v1.md uint64 constant META_MAGIC_NUMBER_V1 = 0xff0a89c674ee7874; /// @title IMetaV1 interface IMetaV1 { /// An onchain wrapper to carry arbitrary Rain metadata. Assigns the sender /// to the metadata so that tooling can easily drop/ignore data from unknown /// sources. As metadata is about something, the subject MUST be provided. /// @param sender The msg.sender. /// @param subject The entity that the metadata is about. MAY be the address /// of the emitting contract (as `uint256`) OR anything else. The /// interpretation of the subject is context specific, so will often be a /// hash of some data/thing that this metadata is about. /// @param meta Rain metadata V1 compliant metadata bytes. /// https://github.com/rainprotocol/specs/blob/main/metadata-v1.md event MetaV1(address sender, uint256 subject, bytes meta); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.18; import "./IMetaV1.sol"; /// @title LibMeta /// @notice Need a place to put data that can be handled offchain like ABIs that /// IS NOT etherscan. library LibMeta { /// Returns true if the metadata bytes are prefixed by the Rain meta magic /// number. DOES NOT attempt to validate the body of the metadata as offchain /// tooling will be required for this. /// @param meta_ The data that may be rain metadata. /// @return True if `meta_` is metadata, false otherwise. function isRainMetaV1(bytes memory meta_) internal pure returns (bool) { if (meta_.length < 8) return false; uint256 mask_ = type(uint64).max; uint256 magicNumber_ = META_MAGIC_NUMBER_V1; assembly ("memory-safe") { magicNumber_ := and(mload(add(meta_, 8)), mask_) } return magicNumber_ == META_MAGIC_NUMBER_V1; } /// Reverts if the provided `meta_` is NOT metadata according to /// `isRainMetaV1`. /// @param meta_ The metadata bytes to check. function checkMetaUnhashed(bytes memory meta_) internal pure { if (!isRainMetaV1(meta_)) { revert NotRainMetaV1(meta_); } } /// Reverts if the provided `meta_` is NOT metadata according to /// `isRainMetaV1` OR it does not match the expected hash of its data. /// @param meta_ The metadata to check. function checkMetaHashed(bytes32 expectedHash_, bytes memory meta_) internal pure { bytes32 actualHash_ = keccak256(meta_); if (expectedHash_ != actualHash_) { revert UnexpectedMetaHash(expectedHash_, actualHash_); } checkMetaUnhashed(meta_); } }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.18; /// Thrown when hashed metadata does NOT match the expected hash. /// @param expectedHash The hash expected by the `IMetaV1` contract. /// @param actualHash The hash of the metadata seen by the `IMetaV1` contract. error UnexpectedMetaHash(bytes32 expectedHash, bytes32 actualHash); /// Thrown when some bytes are expected to be rain meta and are not. /// @param unmeta the bytes that are not meta. error NotRainMetaV1(bytes unmeta); /// @dev Randomly generated magic number with first bytes oned out. /// https://github.com/rainprotocol/specs/blob/main/metadata-v1.md uint64 constant META_MAGIC_NUMBER_V1 = 0xff0a89c674ee7874; /// @title IMetaV1 interface IMetaV1 { /// An onchain wrapper to carry arbitrary Rain metadata. Assigns the sender /// to the metadata so that tooling can easily drop/ignore data from unknown /// sources. As metadata is about something, the subject MUST be provided. /// @param sender The msg.sender. /// @param subject The entity that the metadata is about. MAY be the address /// of the emitting contract (as `uint256`) OR anything else. The /// interpretation of the subject is context specific, so will often be a /// hash of some data/thing that this metadata is about. /// @param meta Rain metadata V1 compliant metadata bytes. /// https://github.com/rainprotocol/specs/blob/main/metadata-v1.md event MetaV1(address sender, uint256 subject, bytes meta); }
// SPDX-License-Identifier: CAL pragma solidity ^0.8.17; import "./IExpressionDeployerV1.sol"; library LibDeployerDiscoverable { /// Hack so that some deployer will emit an event with the sender as the /// caller of `touchDeployer`. This MAY be needed by indexers such as /// subgraph that can only index events from the first moment they are aware /// of some contract. The deployer MUST be registered in ERC1820 registry /// before it is touched, THEN the caller meta MUST be emitted after the /// deployer is touched. This allows indexers such as subgraph to index the /// deployer, then see the caller, then see the caller's meta emitted in the /// same transaction. /// This is NOT required if ANY other expression is deployed in the same /// transaction as the caller meta, there only needs to be one expression on /// ANY deployer known to ERC1820. function touchDeployer(address deployer_) internal { IExpressionDeployerV1(deployer_).deployExpression( new bytes[](0), new uint256[](0), new uint256[](0) ); } }
// SPDX-License-Identifier: CAL pragma solidity =0.8.18; import "../interpreter/store/IInterpreterStoreV1.sol"; import "./IOrderBookV1.sol"; import "../math/LibFixedPointMath.sol"; import {MathUpgradeable as Math} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; /// All information resulting from an order calculation that allows for vault IO /// to be calculated and applied, then the handle IO entrypoint to be dispatched. /// @param outputMax The UNSCALED maximum output calculated by the order /// expression. WILL BE RESCALED ACCORDING TO TOKEN DECIMALS to an 18 fixed /// point decimal number for the purpose of calculating actual vault movements. /// The output max is CAPPED AT THE OUTPUT VAULT BALANCE OF THE ORDER OWNER. /// The order is guaranteed that the total output of this single clearance cannot /// exceed this (subject to rescaling). It is up to the order expression to track /// values over time if the output max is to impose a global limit across many /// transactions and counterparties. /// @param IORatio The UNSCALED order ratio as input/output from the perspective /// of the order. As each counterparty's input is the other's output, the IORatio /// calculated by each order is inverse of its counterparty. IORatio is SCALED /// ACCORDING TO TOKEN DECIMALS to allow 18 decimal fixed point math over the /// vault balances. I.e. `1e18` returned from the expression is ALWAYS "one" as /// ECONOMIC EQUIVALENCE between two tokens, but this will be rescaled according /// to the decimals of the token. For example, if DAI and USDT have a ratio of /// `1e18` then in reality `1e12` DAI will move in the vault for every `1` USDT /// that moves, because DAI has `1e18` decimals per $1 peg and USDT has `1e6` /// decimals per $1 peg. THE ORDER DEFINES THE DECIMALS for each token, NOT the /// token itself, because the token MAY NOT report its decimals as per it being /// optional in the ERC20 specification. /// @param context The entire 2D context array, initialized from the context /// passed into the order calculations and then populated with the order /// calculations and vault IO before being passed back to handle IO entrypoint. /// @param namespace The `StateNamespace` to be passed to the store for calculate /// IO state changes. /// @param kvs KVs returned from calculate order entrypoint to pass to the store /// before calling handle IO entrypoint. struct OrderIOCalculation { uint256 outputMax; //solhint-disable-next-line var-name-mixedcase uint256 IORatio; uint256[][] context; StateNamespace namespace; uint256[] kvs; } library LibOrderBook { using LibFixedPointMath for uint256; using Math for uint256; /// Calculates the clear state change given both order calculations for order /// alice and order bob. The input of each is their output multiplied by /// their IO ratio and the output of each is the smaller of their maximum /// output and the counterparty IO * max output. /// @param aliceOrderIOCalculation_ Order calculation A. /// @param bobOrderIOCalculation_ Order calculation B. /// @return The clear state change with absolute inputs and outputs for A and /// B. function _clearStateChange( OrderIOCalculation memory aliceOrderIOCalculation_, OrderIOCalculation memory bobOrderIOCalculation_ ) internal pure returns (ClearStateChange memory) { ClearStateChange memory clearStateChange_; { clearStateChange_.aliceOutput = aliceOrderIOCalculation_ .outputMax .min( // B's input is A's output. // A cannot output more than their max. // B wants input of their IO ratio * their output. // Always round IO calculations up. bobOrderIOCalculation_.outputMax.fixedPointMul( bobOrderIOCalculation_.IORatio, Math.Rounding.Up ) ); clearStateChange_.bobOutput = bobOrderIOCalculation_.outputMax.min( // A's input is B's output. // B cannot output more than their max. // A wants input of their IO ratio * their output. // Always round IO calculations up. aliceOrderIOCalculation_.outputMax.fixedPointMul( aliceOrderIOCalculation_.IORatio, Math.Rounding.Up ) ); // A's input is A's output * their IO ratio. // Always round IO calculations up. clearStateChange_.aliceInput = clearStateChange_ .aliceOutput .fixedPointMul( aliceOrderIOCalculation_.IORatio, Math.Rounding.Up ); // B's input is B's output * their IO ratio. // Always round IO calculations up. clearStateChange_.bobInput = clearStateChange_ .bobOutput .fixedPointMul( bobOrderIOCalculation_.IORatio, Math.Rounding.Up ); } return clearStateChange_; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol) pragma solidity ^0.8.0; import "./AddressUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ abstract contract MulticallUpgradeable is Initializable { function __Multicall_init() internal onlyInitializing { } function __Multicall_init_unchained() internal onlyInitializing { } /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = _functionDelegateCall(address(this), data[i]); } return results; } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
{ "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":[{"components":[{"internalType":"address","name":"deployer","type":"address"},{"internalType":"bytes","name":"meta","type":"bytes"}],"internalType":"struct DeployerDiscoverableMetaV1ConstructionConfig","name":"config_","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ActiveDebt","type":"error"},{"inputs":[{"internalType":"bytes32","name":"result","type":"bytes32"}],"name":"FlashLenderCallbackFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"name":"InvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"minimumInput","type":"uint256"},{"internalType":"uint256","name":"input","type":"uint256"}],"name":"MinimumInput","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"NotOrderOwner","type":"error"},{"inputs":[{"internalType":"bytes","name":"unmeta","type":"bytes"}],"name":"NotRainMetaV1","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"SameOwner","type":"error"},{"inputs":[{"internalType":"address","name":"aliceToken","type":"address"},{"internalType":"address","name":"bobToken","type":"address"}],"name":"TokenMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expectedHash","type":"bytes32"},{"internalType":"bytes32","name":"actualHash","type":"bytes32"}],"name":"UnexpectedMetaHash","type":"error"},{"inputs":[],"name":"ZeroReceiver","type":"error"},{"inputs":[],"name":"ZeroToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"contract IExpressionDeployerV1","name":"expressionDeployer","type":"address"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"indexed":false,"internalType":"struct Order","name":"order","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"orderHash","type":"uint256"}],"name":"AddOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"uint256","name":"aliceOutput","type":"uint256"},{"internalType":"uint256","name":"bobOutput","type":"uint256"},{"internalType":"uint256","name":"aliceInput","type":"uint256"},{"internalType":"uint256","name":"bobInput","type":"uint256"}],"indexed":false,"internalType":"struct ClearStateChange","name":"clearStateChange","type":"tuple"}],"name":"AfterClear","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"indexed":false,"internalType":"struct Order","name":"alice","type":"tuple"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"indexed":false,"internalType":"struct Order","name":"bob","type":"tuple"},{"components":[{"internalType":"uint256","name":"aliceInputIOIndex","type":"uint256"},{"internalType":"uint256","name":"aliceOutputIOIndex","type":"uint256"},{"internalType":"uint256","name":"bobInputIOIndex","type":"uint256"},{"internalType":"uint256","name":"bobOutputIOIndex","type":"uint256"},{"internalType":"uint256","name":"aliceBountyVaultId","type":"uint256"},{"internalType":"uint256","name":"bobBountyVaultId","type":"uint256"}],"indexed":false,"internalType":"struct ClearConfig","name":"clearConfig","type":"tuple"}],"name":"Clear","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256[][]","name":"context","type":"uint256[][]"}],"name":"Context","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct DepositConfig","name":"config","type":"tuple"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"subject","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"meta","type":"bytes"}],"name":"MetaV1","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"orderHash","type":"uint256"}],"name":"OrderExceedsMaxRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"orderHash","type":"uint256"}],"name":"OrderNotFound","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"orderHash","type":"uint256"}],"name":"OrderZeroAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"indexed":false,"internalType":"struct Order","name":"order","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"orderHash","type":"uint256"}],"name":"RemoveOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"components":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"internalType":"struct Order","name":"order","type":"tuple"},{"internalType":"uint256","name":"inputIOIndex","type":"uint256"},{"internalType":"uint256","name":"outputIOIndex","type":"uint256"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"context","type":"uint256[]"}],"internalType":"struct SignedContext[]","name":"signedContext","type":"tuple[]"}],"indexed":false,"internalType":"struct TakeOrderConfig","name":"config","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"input","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"output","type":"uint256"}],"name":"TakeOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct WithdrawConfig","name":"config","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"},{"components":[{"internalType":"contract IExpressionDeployerV1","name":"deployer","type":"address"},{"internalType":"bytes[]","name":"sources","type":"bytes[]"},{"internalType":"uint256[]","name":"constants","type":"uint256[]"}],"internalType":"struct EvaluableConfig","name":"evaluableConfig","type":"tuple"},{"internalType":"bytes","name":"meta","type":"bytes"}],"internalType":"struct OrderConfig","name":"config_","type":"tuple"}],"name":"addOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"internalType":"struct Order","name":"alice_","type":"tuple"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"internalType":"struct Order","name":"bob_","type":"tuple"},{"components":[{"internalType":"uint256","name":"aliceInputIOIndex","type":"uint256"},{"internalType":"uint256","name":"aliceOutputIOIndex","type":"uint256"},{"internalType":"uint256","name":"bobInputIOIndex","type":"uint256"},{"internalType":"uint256","name":"bobOutputIOIndex","type":"uint256"},{"internalType":"uint256","name":"aliceBountyVaultId","type":"uint256"},{"internalType":"uint256","name":"bobBountyVaultId","type":"uint256"}],"internalType":"struct ClearConfig","name":"clearConfig_","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"context","type":"uint256[]"}],"internalType":"struct SignedContext[]","name":"aliceSignedContext_","type":"tuple[]"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"context","type":"uint256[]"}],"internalType":"struct SignedContext[]","name":"bobSignedContext_","type":"tuple[]"}],"name":"clear","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct DepositConfig","name":"config_","type":"tuple"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract IERC3156FlashBorrower","name":"receiver_","type":"address"},{"internalType":"address","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"flashLoan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"maxFlashLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"internalType":"struct Order","name":"order_","type":"tuple"}],"name":"removeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"output","type":"address"},{"internalType":"address","name":"input","type":"address"},{"internalType":"uint256","name":"minimumInput","type":"uint256"},{"internalType":"uint256","name":"maximumInput","type":"uint256"},{"internalType":"uint256","name":"maximumIORatio","type":"uint256"},{"components":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"handleIO","type":"bool"},{"components":[{"internalType":"contract IInterpreterV1","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV1","name":"store","type":"address"},{"internalType":"address","name":"expression","type":"address"}],"internalType":"struct Evaluable","name":"evaluable","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validInputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"vaultId","type":"uint256"}],"internalType":"struct IO[]","name":"validOutputs","type":"tuple[]"}],"internalType":"struct Order","name":"order","type":"tuple"},{"internalType":"uint256","name":"inputIOIndex","type":"uint256"},{"internalType":"uint256","name":"outputIOIndex","type":"uint256"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"context","type":"uint256[]"}],"internalType":"struct SignedContext[]","name":"signedContext","type":"tuple[]"}],"internalType":"struct TakeOrderConfig[]","name":"orders","type":"tuple[]"}],"internalType":"struct TakeOrdersConfig","name":"takeOrders_","type":"tuple"}],"name":"takeOrders","outputs":[{"internalType":"uint256","name":"totalInput_","type":"uint256"},{"internalType":"uint256","name":"totalOutput_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"vaultBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct WithdrawConfig","name":"config_","type":"tuple"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080604052606580546001600160a01b031990811690915560668054909116905560006067553480156200003257600080fd5b5060405162005a5938038062005a5983398101604081905262000055916200057f565b7f46fe110bf52ba709a3d80747fa101a615fc46eb9ff0fadd4a46d1def682f974f60001b81620000958282602001516200023360201b620018511760201c565b60208101516040517fbea766d03fa1efd3f81cc8634d08320bc62bb0ed9234ac59bbaafa5893fb6b1391620000ce91339130916200068d565b60405180910390a1620000f081600001516200027660201b620018a91760201c565b5050600054610100900460ff1615808015620001135750600054600160ff909116105b8062000143575062000130306200033a60201b6200198b1760201c565b15801562000143575060005460ff166001145b620001ac5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015620001d0576000805461ff0019166101001790555b620001da62000349565b620001e4620003b1565b80156200022b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050620007ff565b80516020820120828114620002665760405163074fe10f60e41b81526004810184905260248101829052604401620001a3565b62000271826200040d565b505050565b604080516000808252602082019092526001600160a01b03831691635511cb679190620002b4565b60608152602001906001900390816200029e5790505b5060408051600080825260208201908152818301928390526001600160e01b031960e086901b16909252620002ee929160448201620006fc565b6060604051808303816000875af11580156200030e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200033491906200078f565b50505050565b6001600160a01b03163b151590565b600054610100900460ff16620003a55760405162461bcd60e51b815260206004820152602b602482015260008051602062005a3983398151915260448201526a6e697469616c697a696e6760a81b6064820152608401620001a3565b620003af6200043d565b565b600054610100900460ff16620003af5760405162461bcd60e51b815260206004820152602b602482015260008051602062005a3983398151915260448201526a6e697469616c697a696e6760a81b6064820152608401620001a3565b62000418816200049f565b6200043a5780604051630c89984b60e31b8152600401620001a39190620007e3565b50565b600054610100900460ff16620004995760405162461bcd60e51b815260206004820152602b602482015260008051602062005a3983398151915260448201526a6e697469616c697a696e6760a81b6064820152608401620001a3565b60018055565b6000600882511015620004b457506000919050565b50600801516001600160401b031667ff0a89c674ee78741490565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156200050a576200050a620004cf565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200053b576200053b620004cf565b604052919050565b6001600160a01b03811681146200043a57600080fd5b60005b83811015620005765781810151838201526020016200055c565b50506000910152565b600060208083850312156200059357600080fd5b82516001600160401b0380821115620005ab57600080fd5b9084019060408287031215620005c057600080fd5b620005ca620004e5565b8251620005d78162000543565b81528284015182811115620005eb57600080fd5b80840193505086601f8401126200060157600080fd5b825182811115620006165762000616620004cf565b6200062a601f8201601f1916860162000510565b925080835287858286010111156200064157600080fd5b620006528186850187870162000559565b5092830152509392505050565b600081518084526200067981602086016020860162000559565b601f01601f19169290920160200192915050565b60018060a01b0384168152826020820152606060408201526000620006b660608301846200065f565b95945050505050565b600081518084526020808501945080840160005b83811015620006f157815187529582019590820190600101620006d3565b509495945050505050565b6000606082016060835280865180835260808501915060808160051b8601019250602080890160005b838110156200075757607f19888703018552620007448683516200065f565b9550938201939082019060010162000725565b5050858403818701525050506200076f8186620006bf565b90508281036040840152620007858185620006bf565b9695505050505050565b600080600060608486031215620007a557600080fd5b8351620007b28162000543565b6020850151909350620007c58162000543565b6040850151909250620007d88162000543565b809150509250925092565b602081526000620007f860208301846200065f565b9392505050565b61522a806200080f6000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c8063ac9650d811610081578063d9d98ce41161005b578063d9d98ce4146101cb578063e23746a3146101de578063e6b62636146101f157600080fd5b8063ac9650d814610152578063b5afc09314610172578063d97b2e481461019a57600080fd5b8063613255ab116100b2578063613255ab1461010b578063702766781461012c578063883746d11461013f57600080fd5b80634f266187146100ce5780635cffe9de146100e3575b600080fd5b6100e16100dc36600461397d565b610204565b005b6100f66100f13660046139bb565b610351565b60405190151581526020015b60405180910390f35b61011e610119366004613a5a565b610600565b604051908152602001610102565b6100e161013a366004613a77565b6106aa565b6100e161014d366004613f51565b610a3d565b610165610160366004614013565b610ffd565b604051610102919061414b565b61018561018036600461415e565b6110f2565b60408051928352602083019190915201610102565b61011e6101a8366004614193565b606960209081526000938452604080852082529284528284209052825290205481565b61011e6101d93660046141d4565b6106a1565b6100e16101ec366004614200565b611656565b6100e16101ff36600461397d565b61176a565b61020c6119a7565b336000908152606960209081526040822090829061022c90850185613a5a565b73ffffffffffffffffffffffffffffffffffffffff168152602080820192909252604090810160009081208584013582529092528082205492506102739084013583611a1a565b905061027f818361426a565b3360009081526069602090815260408220919061029e90870187613a5a565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085602001358152602001908152602001600020819055507f2538ccc7ad2a119a36f2e65c1e2fc908beef800cd59b5d6680db24de18e7847a338483604051610324939291906142b5565b60405180910390a161034361033c6020850185613a5a565b3383611a32565b505061034e60018055565b50565b600061035b611ae0565b73ffffffffffffffffffffffffffffffffffffffff85166103a8576040517fad1991f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff86166103f5576040517f6ba9ecd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6066805473ffffffffffffffffffffffffffffffffffffffff8088167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556065805492891692909116919091179055606784905583156104765761047673ffffffffffffffffffffffffffffffffffffffff86168786611b51565b6040517f23e30c8b00000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8816906323e30c8b906104d59033908a908a9087908b908b90600401614336565b6020604051808303816000875af11580156104f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610518919061437c565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9811461057b576040517f5b62c548000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b606754945084156105b7576065546066546105b19173ffffffffffffffffffffffffffffffffffffffff91821691163088611c25565b60006067555b606580547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169091556066805490911690556105f3611ae0565b5060019695505050505050565b600061060a611c83565b6106a1576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069c919061437c565b6106a4565b60005b92915050565b6106b26119a7565b600080806106c36040850185614395565b6106d1906020810190613a5a565b73ffffffffffffffffffffffffffffffffffffffff16635511cb676106f96040870187614395565b6107079060208101906143d3565b6107146040890189614395565b6107229060408101906143d3565b61072e60026000611cd4565b6040518663ffffffff1660e01b815260040161074e9594939291906144c1565b6060604051808303816000875af115801561076d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079191906145b7565b92509250925060006040518060a001604052803373ffffffffffffffffffffffffffffffffffffffff16815260200160008780604001906107d29190614395565b6107e09060208101906143d3565b60018181106107f1576107f1614604565b90506020028101906108039190614633565b919091118252506040805160608101825273ffffffffffffffffffffffffffffffffffffffff8089168252878116602083810191909152908716828401528301520161084f8780614698565b808060200260200160405190810160405280939291908181526020016000905b8282101561089b5761088c606083028601368190038101906146ff565b8152602001906001019061086f565b505050505081526020018680602001906108b59190614698565b808060200260200160405190810160405280939291908181526020016000905b82821015610901576108f2606083028601368190038101906146ff565b815260200190600101906108d5565b50505050508152509050600061091682611d08565b60008181526068602052604090819020600190559091507f73e46afa6205785bdaa1daaf8b6ccc71715ec06b3b4264f5a00fde98671c2fc690339061095d90890189614395565b61096b906020810190613a5a565b848460405161097d94939291906147fd565b60405180910390a160006109946060880188614633565b90501115610a2f576109e66109ac6060880188614633565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d5792505050565b7fbea766d03fa1efd3f81cc8634d08320bc62bb0ed9234ac59bbaafa5893fb6b133382610a1660608a018a614633565b604051610a269493929190614847565b60405180910390a15b505050505061034e60018055565b610a456119a7565b8351855173ffffffffffffffffffffffffffffffffffffffff918216911603610ab55784516040517f227e4ce900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610572565b8360600151836040013581518110610acf57610acf614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff168560800151846020013581518110610b0b57610b0b614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614610bd0578460800151836020013581518110610b4c57610b4c614604565b6020026020010151600001518460600151846040013581518110610b7257610b72614604565b6020908102919091010151516040517ff902523f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401610572565b606085015180518435908110610be857610be8614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff168460800151846060013581518110610c2457610c24614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614610c8957606085015180518435908110610c6357610c63614604565b6020026020010151600001518460800151846060013581518110610b7257610b72614604565b600060686000610c9888611d08565b81526020019081526020016000205403610d17577fe721f6888210c87666d3888f93b4139a86ab7757999ce54e268cba700d642a3b338660000151610cdc88611d08565b6040805173ffffffffffffffffffffffffffffffffffffffff94851681529390921660208401529082015260600160405180910390a1610fed565b600060686000610d2687611d08565b81526020019081526020016000205403610d6a577fe721f6888210c87666d3888f93b4139a86ab7757999ce54e268cba700d642a3b338560000151610cdc87611d08565b7fd153812deb929a6e4378f6f8cf61d010470840bf2e736f43fb2275803958bfa233868686604051610d9f949392919061487d565b60405180910390a16000610dc28685600001358660200135886000015186611d98565b90506000610ddf86866040013587606001358a6000015188611d98565b90506000610ded838361248b565b9050610e03888260400151836000015186612560565b610e17878260600151836020015185612560565b60608101518151600091610e2a9161426a565b9050600082604001518360200151610e42919061426a565b90508115610ee857336000908152606960209081526040822060808d01518051869492938d0135908110610e7857610e78614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a6080013581526020019081526020016000206000828254610ee29190614907565b90915550505b8015610f8c5733600090815260696020526040812060808b015180518493919060608d0135908110610f1c57610f1c614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a60a0013581526020019081526020016000206000828254610f869190614907565b90915550505b5050604080513381528251602080830191909152830151818301529082015160608083019190915282015160808201527f3f20e55919cca701abb2a40ab72542b25ea7eed63a50f979dd2cd3231e5f488d9060a00160405180910390a15050505b610ff660018055565b5050505050565b60608167ffffffffffffffff81111561101857611018613ab2565b60405190808252806020026020018201604052801561104b57816020015b60608152602001906001900390816110365790505b50905060005b828110156110eb576110bb3085858481811061106f5761106f614604565b90506020028101906110819190614633565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a0892505050565b8282815181106110cd576110cd614604565b602002602001018190525080806110e39061491a565b915050611051565b5092915050565b6000806110fd6119a7565b6000611164604080516101208101825260006080820181815260a08301829052835160608082018652838252602080830185905282870185905260c086019290925260e0850181905261010085018190529184528301829052928201528181019190915290565b6040805160a08101825260008082526020808301829052835160608082018652838252918101839052808501929092529282015281810182905260808101829052908601355b6111b760a08801886143d3565b9050841080156111c75750600081115b1561159e576111d960a08801886143d3565b858181106111e9576111e9614604565b90506020028101906111fb9190614952565b61120490614986565b80519093509150600061121683611d08565b6000818152606860205260409020549091506112895782516040805133815273ffffffffffffffffffffffffffffffffffffffff909216602083015281018290527fe721f6888210c87666d3888f93b4139a86ab7757999ce54e268cba700d642a3b9060600160405180910390a1611592565b6112966020890189613a5a565b73ffffffffffffffffffffffffffffffffffffffff1683606001518560200151815181106112c6576112c6614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff161461137357826060015184602001518151811061130757611307614604565b6020908102919091018101515190611321908a018a613a5a565b6040517ff902523f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401610572565b6113836040890160208a01613a5a565b73ffffffffffffffffffffffffffffffffffffffff1683608001518560400151815181106113b3576113b3614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16146114135782608001518460400151815181106113f4576113f4614604565b6020026020010151600001518860200160208101906113219190613a5a565b600061142e8486602001518760400151338960600151611d98565b905088608001358160200151111561149e5783516040805133815273ffffffffffffffffffffffffffffffffffffffff909216602083015281018390527f460c258f27efac20e56c4607a28003d235168e76997ffb7542637d26d45ea6d8906060015b60405180910390a1611590565b80516000036114fc5783516040805133815273ffffffffffffffffffffffffffffffffffffffff909216602083015281018390527f3ba461a0ffd1b6782d4817ae7be605cfb1bbb4fa503c0dd613b8e50f1dcafacd90606001611491565b805160009061150c908590611a1a565b9050600061152a8360200151600184612b479092919063ffffffff16565b9050611536828661426a565b9450611542818a614907565b985061155086828486612560565b7fa9f5933dc364b27dc6896a7e5a24de764ecf13b3969dcb5ac5a71d97db8aa8ee338884846040516115859493929190614a20565b60405180910390a150505b505b506001909301926111aa565b6115ac81606089013561426a565b955086604001358610156115f957604080517f45094d8800000000000000000000000000000000000000000000000000000000815290880135600482015260248101879052604401610572565b61162a33308761160c60208c018c613a5a565b73ffffffffffffffffffffffffffffffffffffffff16929190611c25565b61164461163d6040890160208a01613a5a565b3388611a32565b5050505061165160018055565b915091565b61165e6119a7565b61166b6020820182613a5a565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146116fd57336116ab6020830183613a5a565b6040517f4702b91400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401610572565b600061171061170b83614b50565b611d08565b60008181526068602052604080822091909155519091507fe2dd87ac53228b6f23feabcc7301fe64145f23cc3c3ed75e6cd07341ae7f22829061175890339085908590614c2c565b60405180910390a15061034e60018055565b6117726119a7565b7fadc7bd964a04a8a02261d33d2d09c6a7d9f539bc5eab77008e85fc6661ef123133826040516117a3929190614d31565b60405180910390a16117c23330604084013561160c6020860186613a5a565b336000908152606960209081526040808320908401359290916117e790850185613a5a565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008360200135815260200190815260200160002060008282546118459190614907565b90915550506001805550565b8051602082012082811461189b576040517f74fe10f00000000000000000000000000000000000000000000000000000000081526004810184905260248101829052604401610572565b6118a482611d57565b505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff831691635511cb6791906118f2565b60608152602001906001900390816118dd5790505b5060408051600080825260208201908152818301928390527fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16909252611942929160448201614d5b565b6060604051808303816000875af1158015611961573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198591906145b7565b50505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b600260015403611a13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610572565b6002600155565b6000818310611a295781611a2b565b825b9392505050565b60665473ffffffffffffffffffffffffffffffffffffffff8481169116148015611a76575060655473ffffffffffffffffffffffffffffffffffffffff8381169116145b15611ab9576000611a9260675483611a1a90919063ffffffff16565b9050611a9e818361426a565b91508060676000828254611ab2919061426a565b9091555050505b80156118a4576118a473ffffffffffffffffffffffffffffffffffffffff84168383611b51565b611ae8611c83565b15611b4f576065546066546067546040517f60817cfa00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401610572565b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526118a49084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b65565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526119859085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611ba3565b60655460009073ffffffffffffffffffffffffffffffffffffffff16151580611cc3575060665473ffffffffffffffffffffffffffffffffffffffff1615155b80611ccf575060675415155b905090565b6040805160028082526060808301845292600092919060208301908036833750505060208101949094525050604082015290565b600081604051602001611d1b9190614d94565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012092915050565b611d6081612c71565b61034e57806040517f644cc2580000000000000000000000000000000000000000000000000000000081526004016105729190614da7565b611dca6040518060a0016040528060008152602001600081526020016060815260200160008152602001606081525090565b6000611dd587611d08565b60408051600480825260a08201909252919250606091600091816020015b6060815260200190600190039081611df3579050509050611e45838a6000015173ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16612ca1565b816001800381518110611e5a57611e5a614604565b6020026020010181905250611fc289606001518981518110611e7e57611e7e614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff168a606001518a81518110611eb657611eb6614604565b60200260200101516020015160ff168b606001518b81518110611edb57611edb614604565b602002602001015160400151606960008e6000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008e606001518e81518110611f4257611f42614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008e606001518e81518110611fa057611fa0614604565b6020026020010151604001518152602001908152602001600020546000612cde565b81600160030381518110611fd857611fd8614604565b602002602001018190525061211e89608001518881518110611ffc57611ffc614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff168a60800151898151811061203457612034614604565b60200260200101516020015160ff168b608001518a8151811061205957612059614604565b602002602001015160400151606960008e6000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008e608001518d815181106120c0576120c0614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008e608001518d81518110611fa057611fa0614604565b8160016004038151811061213457612134614604565b602090810291909101015261217581600060405190808252806020026020018201604052801561216e578160200160208202803683370190505b5087612d29565b9150506000886000015173ffffffffffffffffffffffffffffffffffffffff1690506000808a604001516000015173ffffffffffffffffffffffffffffffffffffffff16636715f8258c6040015160200151856121d98f6040015160400151613093565b886040518563ffffffff1660e01b81526004016121f99493929190614e02565b600060405180830381865afa158015612216573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261225c9190810190614e98565b9150915060008260028451038151811061227857612278614604565b6020026020010151905060008360018551038151811061229a5761229a614604565b602002602001015190506122de8d608001518c815181106122bd576122bd614604565b60200260200101516020015160ff166000846130bc9092919063ffffffff16565b91506123408d608001518c815181106122f9576122f9614604565b60200260200101516020015160ff168e606001518e8151811061231e5761231e614604565b60200260200101516020015160ff1660018461312b909392919063ffffffff16565b9050612428606960008f6000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008f608001518e815181106123a0576123a0614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008f608001518e815181106123fe576123fe614604565b60200260200101516040015181526020019081526020016000205483611a1a90919063ffffffff16565b91506124348282611cd4565b8660028151811061244757612447614604565b60200260200101819052506040518060a001604052808381526020018281526020018781526020018681526020018481525097505050505050505095945050505050565b6124b66040518060800160405280600081526020016000815260200160008152602001600081525090565b6124e16040518060800160405280600081526020016000815260200160008152602001600081525090565b60208301518351612500916124f891906001612b47565b855190611a1a565b8152602084015184516125219161251991906001612b47565b845190611a1a565b602080830191909152840151815161253a916001612b47565b604082015260208084015190820151612554916001612b47565b60608201529392505050565b82816040015160038151811061257857612578614604565b602002602001015160048151811061259257612592614604565b6020026020010181815250508181604001516004815181106125b6576125b6614604565b60200260200101516004815181106125d0576125d0614604565b602090810291909101015282156126dd57835173ffffffffffffffffffffffffffffffffffffffff1660009081526069602052604080822090830151805186939190600390811061262357612623614604565b602002602001015160008151811061263d5761263d614604565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836040015160038151811061269857612698614604565b60200260200101516002815181106126b2576126b2614604565b6020026020010151815260200190815260200160002060008282546126d79190614907565b90915550505b81156127df57835173ffffffffffffffffffffffffffffffffffffffff1660009081526069602052604080822090830151805185939190600490811061272557612725614604565b602002602001015160008151811061273f5761273f614604565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836040015160048151811061279a5761279a614604565b60200260200101516002815181106127b4576127b4614604565b6020026020010151815260200190815260200160002060008282546127d9919061426a565b90915550505b7f17a5c0f3785132a57703932032f6863e7920434150aa1dc940e567b440fdce1f338260400151604051612814929190614efc565b60405180910390a1608081015151156128a55783604001516020015173ffffffffffffffffffffffffffffffffffffffff1663946aadc6826060015183608001516040518363ffffffff1660e01b8152600401612872929190614f2b565b600060405180830381600087803b15801561288c57600080fd5b505af11580156128a0573d6000803e3d6000fd5b505050505b83602001511561198557600084604001516000015173ffffffffffffffffffffffffffffffffffffffff16636715f82586604001516020015184606001516128f4896040015160400151613149565b86604001516040518563ffffffff1660e01b81526004016129189493929190614e02565b600060405180830381865afa158015612935573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261297b9190810190614e98565b915050600081511115610ff65784604001516020015173ffffffffffffffffffffffffffffffffffffffff1663946aadc68360600151836040518363ffffffff1660e01b81526004016129cf929190614f2b565b600060405180830381600087803b1580156129e957600080fd5b505af11580156129fd573d6000803e3d6000fd5b505050505050505050565b606073ffffffffffffffffffffffffffffffffffffffff83163b612aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610572565b6000808473ffffffffffffffffffffffffffffffffffffffff1684604051612ad69190614f44565b600060405180830381855af49150503d8060008114612b11576040519150601f19603f3d011682016040523d82523d6000602084013e612b16565b606091505b5091509150612b3e82826040518060600160405280602781526020016151ce60279139613174565b95945050505050565b6000612b5d8484670de0b6b3a76400008561318d565b949350505050565b6000612bc7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166131e89092919063ffffffff16565b8051909150156118a45780806020019051810190612be59190614f56565b6118a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610572565b6000600882511015612c8557506000919050565b506008015167ffffffffffffffff1667ff0a89c674ee78741490565b6040805160038082526080820190925260609160009190602082018480368337505050602081019590955250506040830191909152606082015290565b60408051600580825260c08201909252606091600091906020820160a0803683375050506020810197909752505060408501939093526060840191909152608083015260a082015290565b60606000825167ffffffffffffffff811115612d4757612d47613ab2565b604051908082528060200260200182016040528015612d70578160200160208202803683370190505b509050600080845111612d84576000612d8a565b83516001015b865101600201905060008167ffffffffffffffff811115612dad57612dad613ab2565b604051908082528060200260200182016040528015612de057816020015b6060815260200190600190039081612dcb5790505b5090506000612ded6131f7565b828281518110612dff57612dff614604565b602002602001018190525060005b8851811015612e5d578180600101925050888181518110612e3057612e30614604565b6020026020010151838381518110612e4a57612e4a614604565b6020908102919091010152600101612e0d565b50808060010191505086828281518110612e7957612e79614604565b602090810291909101015285511561308857808060010191505083828281518110612ea657612ea6614604565b602002602001018190525060005b865181101561308657612fb0878281518110612ed257612ed2614604565b602002602001015160000151612f8d898481518110612ef357612ef3614604565b602002602001015160400151604051602001612f0f9190614f73565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b898481518110612f9f57612f9f614604565b602002602001015160200151613203565b612fe9576040517f52bf984800000000000000000000000000000000000000000000000000000000815260048101829052602401610572565b868181518110612ffb57612ffb614604565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1685828151811061302f5761302f614604565b602002602001018181525050818060010192505086818151811061305557613055614604565b60200260200101516040015183838151811061307357613073614604565b6020908102919091010152600101612eb4565b505b509695505050505050565b6000602082901b77ffffffffffffffffffffffffffffffffffffffff00000000166002176106a4565b600080601284036130d05784915050611a2b565b83601211156130f2578360120390506130ea8582856133d0565b915050611a2b565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee83016130ea61312482600a6150c9565b8690613425565b6000612b3e8561314361313e87876150d5565b61347f565b84613518565b600062010000602083901b77ffffffffffffffffffffffffffffffffffffffff0000000016176106a4565b60608315613183575081611a2b565b611a2b8383613567565b60008061319b8686866135ab565b905060018360028111156131b1576131b16150f5565b1480156131ce5750600084806131c9576131c9615124565b868809115b15612b3e576131de600182614907565b9695505050505050565b6060612b5d8484600085613678565b6060611ccf3330611cd4565b60008060006132128585613791565b9092509050600081600481111561322b5761322b6150f5565b14801561326357508573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1561327357600192505050611a2b565b6000808773ffffffffffffffffffffffffffffffffffffffff16631626ba7e60e01b88886040516024016132a8929190615153565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516133319190614f44565b600060405180830381855afa9150503d806000811461336c576040519150601f19603f3d011682016040523d82523d6000602084013e613371565b606091505b5091509150818015613384575080516020145b80156133c4575080517f1626ba7e00000000000000000000000000000000000000000000000000000000906133c2908301602090810190840161437c565b145b98975050505050505050565b6000806133de84600a6150c9565b905060006133ec828761516c565b90506001846002811115613402576134026150f5565b1480156131ce575061341482826151a7565b8614612b3e576131de600182614907565b600082600003613437575060006106a4565b8282028284828161344a5761344a615124565b04036134565780612b5d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff949350505050565b80600081900b8114613513576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f20626974730000000000000000000000000000000000000000000000000000006064820152608401610572565b919050565b60008260000b60000361352c575082611a2b565b60008360000b13156135545761354d61354684600a6151be565b8590613425565b9050611a2b565b60ff6000849003166130ea8582856133d0565b8151156135775781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105729190614da7565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003613603578382816135f9576135f9615124565b0492505050611a2b565b80841161360f57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60608247101561370a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610572565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516137339190614f44565b60006040518083038185875af1925050503d8060008114613770576040519150601f19603f3d011682016040523d82523d6000602084013e613775565b606091505b5091509150613786878383876137d6565b979650505050505050565b60008082516041036137c75760208301516040840151606085015160001a6137bb87828585613876565b945094505050506137cf565b506000905060025b9250929050565b6060831561386c5782516000036138655773ffffffffffffffffffffffffffffffffffffffff85163b613865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610572565b5081612b5d565b612b5d8383613567565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138ad575060009050600361395c565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613901573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139555760006001925092505061395c565b9150600090505b94509492505050565b60006060828403121561397757600080fd5b50919050565b60006060828403121561398f57600080fd5b611a2b8383613965565b73ffffffffffffffffffffffffffffffffffffffff8116811461034e57600080fd5b6000806000806000608086880312156139d357600080fd5b85356139de81613999565b945060208601356139ee81613999565b935060408601359250606086013567ffffffffffffffff80821115613a1257600080fd5b818801915088601f830112613a2657600080fd5b813581811115613a3557600080fd5b896020828501011115613a4757600080fd5b9699959850939650602001949392505050565b600060208284031215613a6c57600080fd5b8135611a2b81613999565b600060208284031215613a8957600080fd5b813567ffffffffffffffff811115613aa057600080fd5b820160808185031215611a2b57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715613b0457613b04613ab2565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b5157613b51613ab2565b604052919050565b801515811461034e57600080fd5b803561351381613b59565b600060608284031215613b8457600080fd5b613b8c613ae1565b90508135613b9981613999565b81526020820135613ba981613999565b60208201526040820135613bbc81613999565b604082015292915050565b600067ffffffffffffffff821115613be157613be1613ab2565b5060051b60200190565b803560ff8116811461351357600080fd5b600060608284031215613c0e57600080fd5b613c16613ae1565b90508135613c2381613999565b8152613c3160208301613beb565b60208201526040820135604082015292915050565b600082601f830112613c5757600080fd5b81356020613c6c613c6783613bc7565b613b0a565b82815260609283028501820192828201919087851115613c8b57600080fd5b8387015b85811015613cae57613ca18982613bfc565b8452928401928101613c8f565b5090979650505050505050565b600060e08284031215613ccd57600080fd5b60405160a0810167ffffffffffffffff8282108183111715613cf157613cf1613ab2565b8160405282935084359150613d0582613999565b818352613d1460208601613b67565b6020840152613d268660408701613b72565b604084015260a0850135915080821115613d3f57600080fd5b613d4b86838701613c46565b606084015260c0850135915080821115613d6457600080fd5b50613d7185828601613c46565b6080830152505092915050565b600060c0828403121561397757600080fd5b600082601f830112613da157600080fd5b81356020613db1613c6783613bc7565b82815260059290921b84018101918181019086841115613dd057600080fd5b8286015b848110156130885780358352918301918301613dd4565b600082601f830112613dfc57600080fd5b81356020613e0c613c6783613bc7565b82815260059290921b84018101918181019086841115613e2b57600080fd5b8286015b8481101561308857803567ffffffffffffffff80821115613e505760008081fd5b818901915060607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08181858e03011215613e8a5760008081fd5b613e92613ae1565b88850135613e9f81613999565b815260408581013585811115613eb55760008081fd5b8601603f81018f13613ec75760008081fd5b8a81013586811115613edb57613edb613ab2565b613eeb8c86601f84011601613b0a565b94508085528f83828401011115613f025760008081fd5b808383018d87013760009150818c828701015250838b84015284870135945085851115613f2d578081fd5b50613f3c8e8b86890101613d90565b90820152875250505092840192508301613e2f565b60008060008060006101408688031215613f6a57600080fd5b853567ffffffffffffffff80821115613f8257600080fd5b613f8e89838a01613cbb565b96506020880135915080821115613fa457600080fd5b613fb089838a01613cbb565b9550613fbf8960408a01613d7e565b9450610100880135915080821115613fd657600080fd5b613fe289838a01613deb565b9350610120880135915080821115613ff957600080fd5b5061400688828901613deb565b9150509295509295909350565b6000806020838503121561402657600080fd5b823567ffffffffffffffff8082111561403e57600080fd5b818501915085601f83011261405257600080fd5b81358181111561406157600080fd5b8660208260051b850101111561407657600080fd5b60209290920196919550909350505050565b60005b838110156140a357818101518382015260200161408b565b50506000910152565b600081518084526140c4816020860160208601614088565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b8581101561413e57828403895261412c8483516140ac565b98850198935090840190600101614114565b5091979650505050505050565b602081526000611a2b60208301846140f6565b60006020828403121561417057600080fd5b813567ffffffffffffffff81111561418757600080fd5b612b5d84828501613d7e565b6000806000606084860312156141a857600080fd5b83356141b381613999565b925060208401356141c381613999565b929592945050506040919091013590565b600080604083850312156141e757600080fd5b82356141f281613999565b946020939093013593505050565b60006020828403121561421257600080fd5b813567ffffffffffffffff81111561422957600080fd5b820160e08185031215611a2b57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156106a4576106a461423b565b803561428881613999565b73ffffffffffffffffffffffffffffffffffffffff16825260208181013590830152604090810135910152565b73ffffffffffffffffffffffffffffffffffffffff8416815260a081016142df602083018561427d565b826080830152949350505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a060808301526133c460a0830184866142ed565b60006020828403121561438e57600080fd5b5051919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181126143c957600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261440857600080fd5b83018035915067ffffffffffffffff82111561442357600080fd5b6020019150600581901b36038213156137cf57600080fd5b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561446d57600080fd5b8260051b80836020870137939093016020019392505050565b600081518084526020808501945080840160005b838110156144b65781518752958201959082019060010161449a565b509495945050505050565b6060808252810185905260006080600587901b8301810190830188835b8981101561458d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086850301835281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18c360301811261453f57600080fd5b8b01602081810191359067ffffffffffffffff82111561455e57600080fd5b81360383131561456d57600080fd5b6145788783856142ed565b965094850194939093019250506001016144de565b50505082810360208401526145a381868861443b565b905082810360408401526133c48185614486565b6000806000606084860312156145cc57600080fd5b83516145d781613999565b60208501519093506145e881613999565b60408501519092506145f981613999565b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261466857600080fd5b83018035915067ffffffffffffffff82111561468357600080fd5b6020019150368190038213156137cf57600080fd5b6000