Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 10266641 | 129 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Orchestrator
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {LibBitmap} from "solady/utils/LibBitmap.sol";
import {LibERC7579} from "solady/accounts/LibERC7579.sol";
import {LibEIP7702} from "solady/accounts/LibEIP7702.sol";
import {EfficientHashLib} from "solady/utils/EfficientHashLib.sol";
import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
import {EIP712} from "solady/utils/EIP712.sol";
import {LibBit} from "solady/utils/LibBit.sol";
import {LibBytes} from "solady/utils/LibBytes.sol";
import {LibStorage} from "solady/utils/LibStorage.sol";
import {CallContextChecker} from "solady/utils/CallContextChecker.sol";
import {FixedPointMathLib as Math} from "solady/utils/FixedPointMathLib.sol";
import {TokenTransferLib} from "./libraries/TokenTransferLib.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {IIthacaAccount} from "./interfaces/IIthacaAccount.sol";
import {IOrchestrator} from "./interfaces/IOrchestrator.sol";
import {ICommon} from "./interfaces/ICommon.sol";
import {IFunder} from "./interfaces/IFunder.sol";
import {ISettler} from "./interfaces/ISettler.sol";
import {MerkleProofLib} from "solady/utils/MerkleProofLib.sol";
/// @title Orchestrator
/// @notice Enables atomic verification, gas compensation and execution across eoas.
/// @dev
/// The Orchestrator allows relayers to submit payloads on one or more eoas,
/// and get compensated for the gas spent in an atomic transaction.
/// It serves the following purposes:
/// - Facilitate fair gas compensation to the relayer.
/// This means capping the amount of gas consumed,
/// such that it will not exceed the signed gas stipend,
/// and ensuring the relayer gets compensated even if the call to the eoa reverts.
/// This also means minimizing the risk of griefing the relayer, in areas where
/// we cannot absolutely guarantee compensation for gas spent.
/// - Ensures that the eoa can safely compensate the relayer.
/// This means ensuring that the eoa cannot be drained.
/// This means ensuring that the compensation is capped by the signed max amount.
/// Tokens can only be deducted from an eoa once per signed nonce.
/// - Minimize chance of censorship.
/// This means once an Intent is signed, it is infeasible to
/// alter or rearrange it to force it to fail.
contract Orchestrator is IOrchestrator, EIP712, CallContextChecker, ReentrancyGuardTransient {
using LibERC7579 for bytes32[];
using EfficientHashLib for bytes32[];
using LibBitmap for LibBitmap.Bitmap;
////////////////////////////////////////////////////////////////////////
// Errors
////////////////////////////////////////////////////////////////////////
/// @dev Unable to perform the payment.
error PaymentError();
/// @dev Unable to verify the user op. The user op may be invalid.
error VerificationError();
/// @dev Unable to perform the call.
error CallError();
/// @dev Unable to perform the verification and the call.
error VerifiedCallError();
/// @dev Out of gas to perform the call operation.
error InsufficientGas();
/// @dev The order has already been filled.
error OrderAlreadyFilled();
/// @dev The simulate execute run has failed. Try passing in more gas to the simulation.
error SimulateExecuteFailed();
/// @dev A PreCall's EOA must be the same as its parent Intent's.
error InvalidPreCallEOA();
/// @dev The PreCall cannot be verified to be correct.
error PreCallVerificationError();
/// @dev Error calling the sub Intents `executionData`.
error PreCallError();
/// @dev The EOA's account implementation is not supported.
error UnsupportedAccountImplementation();
/// @dev The simulation has passed.
error SimulationPassed(uint256 gUsed);
/// @dev The state override has not happened.
error StateOverrideError();
/// @dev The intent has expired.
error IntentExpired();
////////////////////////////////////////////////////////////////////////
// Events
////////////////////////////////////////////////////////////////////////
/// @dev Emitted when an Intent (including PreCalls) is executed.
/// This event is emitted in the `execute` function.
/// - `incremented` denotes that `nonce`'s sequence has been incremented to invalidate `nonce`,
/// - `err` denotes the resultant error selector.
/// If `incremented` is true and `err` is non-zero, the Intent was successful.
/// For PreCalls where the nonce is skipped, this event will NOT be emitted..
event IntentExecuted(address indexed eoa, uint256 indexed nonce, bool incremented, bytes4 err);
////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////
/// @dev For EIP712 signature digest calculation for the `execute` function.
bytes32 public constant INTENT_TYPEHASH = keccak256(
"Intent(bool multichain,address eoa,Call[] calls,uint256 nonce,address payer,address paymentToken,uint256 paymentMaxAmount,uint256 combinedGas,bytes[] encodedPreCalls,bytes[] encodedFundTransfers,address settler,uint256 expiry)Call(address to,uint256 value,bytes data)"
);
/// @dev For EIP712 signature digest calculation for SignedCalls
bytes32 public constant SIGNED_CALL_TYPEHASH = keccak256(
"SignedCall(bool multichain,address eoa,Call[] calls,uint256 nonce)Call(address to,uint256 value,bytes data)"
);
/// @dev For EIP712 signature digest calculation for the `execute` function.
bytes32 public constant CALL_TYPEHASH = keccak256("Call(address to,uint256 value,bytes data)");
bytes32 public constant DOMAIN_TYPEHASH = _DOMAIN_TYPEHASH;
/// @dev Nonce prefix to signal that the payload is to be signed with EIP712 without the chain ID.
/// This constant is a pun for "chain ID 0".
uint16 public constant MULTICHAIN_NONCE_PREFIX = 0xc1d0;
/// @dev For ensuring that the remaining gas is sufficient for a self-call with
/// overhead for cleaning up after the self-call. This also has an added benefit
/// of preventing the censorship vector of calling `execute` in a very deep call-stack.
/// With the 63/64 rule, and an initial gas of 30M, we can approximately make
/// around 339 recursive calls before the amount of gas passed in drops below 100k.
/// The EVM has a maximum call depth of 1024.
uint256 internal constant _INNER_GAS_OVERHEAD = 100000;
/// @dev The amount of expected gas for refunds.
/// Should be enough for a cold zero to non-zero SSTORE + a warm SSTORE + a few SLOADs.
uint256 internal constant _REFUND_GAS = 50000;
/// @dev Flag for normal execution mode.
uint256 internal constant _NORMAL_MODE_FLAG = 0;
/// @dev Flag for simulation mode.
uint256 internal constant _SIMULATION_MODE_FLAG = 1;
////////////////////////////////////////////////////////////////////////
// Main
////////////////////////////////////////////////////////////////////////
/// @dev Allows anyone to sweep tokens from the orchestrator.
/// If `token` is `address(0)`, withdraws the native gas token.
function withdrawTokens(address token, address recipient, uint256 amount) public virtual {
TokenTransferLib.safeTransfer(token, recipient, amount);
}
/// @dev DEPRECATION WARNING: This function will be deprecated in the future.
/// Allows pre calls to be executed individually, for counterfactual signatures.
function executePreCalls(address parentEOA, SignedCall[] calldata preCalls) public virtual {
for (uint256 j; j < preCalls.length; ++j) {
SignedCall calldata p = preCalls[j];
address eoa = Math.coalesce(p.eoa, parentEOA);
uint256 nonce = p.nonce;
(bool isValid, bytes32 keyHash) = _verify(_computeDigest(p), eoa, p.signature);
if (!isValid) revert PreCallVerificationError();
_checkAndIncrementNonce(eoa, nonce);
// This part is same as `selfCallPayVerifyCall537021665`. We simply inline to save gas.
bytes memory data = LibERC7579.reencodeBatchAsExecuteCalldata(
hex"01000000000078210001", // ERC7821 batch execution mode.
p.executionData,
abi.encode(keyHash) // `opData`.
);
assembly ("memory-safe") {
mstore(0x00, 0) // Zeroize the return slot.
if iszero(call(gas(), eoa, 0, add(0x20, data), mload(data), 0x00, 0x20)) {
if iszero(mload(0x00)) { mstore(0x00, shl(224, 0x2228d5db)) } // `PreCallError()`.
revert(0x00, 0x20) // Revert the `err` (NOT return).
}
}
// Event so that indexers can know that the nonce is used.
// Reaching here means there's no error in the PreCall.
emit IntentExecuted(eoa, p.nonce, true, 0); // `incremented = true`, `err = 0`.
}
}
/// @dev Executes a single encoded intent.
/// `encodedIntent` is given by `abi.encode(intent)`, where `intent` is a struct of type `Intent`.
/// If sufficient gas is provided, returns an error selector that is non-zero
/// if there is an error during the payment, verification, and call execution.
function execute(bytes calldata encodedIntent)
public
payable
virtual
nonReentrant
returns (bytes4 err)
{
(, err) = _execute(encodedIntent, 0, _NORMAL_MODE_FLAG);
}
/// @dev Executes the array of encoded intents.
/// Each element in `encodedIntents` is given by `abi.encode(intent)`,
/// where `intent` is a struct of type `Intent`.
function execute(bytes[] calldata encodedIntents)
public
payable
virtual
nonReentrant
returns (bytes4[] memory errs)
{
// This allocation and loop was initially in assembly, but I've normified it for now.
errs = new bytes4[](encodedIntents.length);
for (uint256 i; i < encodedIntents.length; ++i) {
// We reluctantly use regular Solidity to access `encodedIntents[i]`.
// This generates an unnecessary check for `i < encodedIntents.length`, but helps
// generate all the implicit calldata bound checks on `encodedIntents[i]`.
(, errs[i]) = _execute(encodedIntents[i], 0, _NORMAL_MODE_FLAG);
}
}
/// @dev Minimal function, to allow hooking into the _execute function with the simulation flags set to true.
/// When flags is set to true, all errors are bubbled up. Also signature verification always returns true.
/// But the codepaths for signature verification are still hit, for correct gas measurement.
/// @dev If `isStateOverride` is false, then this function will always revert. If the simulation is successful, then it reverts with `SimulationPassed` error.
/// If `isStateOverride` is true, then this function will not revert if the simulation is successful.
/// But the balance of tx.origin has to be greater than or equal to type(uint192).max, to prove that a state override has been made offchain,
/// and this is not an onchain call. This mode has been added so that receipt logs can be generated for `eth_simulateV1`
/// @return gasUsed The amount of gas used by the execution. (Only returned if `isStateOverride` is true)
function simulateExecute(
bool isStateOverride,
uint256 combinedGasOverride,
bytes calldata encodedIntent
) external payable returns (uint256) {
// If Simulation Fails, then it will revert here.
(uint256 gUsed, bytes4 err) =
_execute(encodedIntent, combinedGasOverride, _SIMULATION_MODE_FLAG);
if (err != 0) {
assembly ("memory-safe") {
mstore(0x00, err)
revert(0x00, 0x20)
}
}
if (isStateOverride) {
if (tx.origin.balance >= type(uint192).max) {
return gUsed;
} else {
revert StateOverrideError();
}
} else {
// If Simulation Passes, then it will revert here.
revert SimulationPassed(gUsed);
}
}
/// @dev Extracts the Intent from the calldata bytes, with minimal checks.
function _extractIntent(bytes calldata encodedIntent)
internal
view
virtual
returns (Intent calldata i)
{
// This function does NOT allocate memory to avoid quadratic memory expansion costs.
// Otherwise, it will be unfair to the Intents at the back of the batch.
// `dynamicStructInCalldata` internally performs out-of-bounds checks.
bytes calldata intentCalldata = LibBytes.dynamicStructInCalldata(encodedIntent, 0x00);
assembly ("memory-safe") {
i := intentCalldata.offset
}
// These checks are included for more safety: Swiss Cheese Model.
// Ensures that all the dynamic children in `encodedIntent` are contained.
LibBytes.checkInCalldata(i.executionData, intentCalldata);
LibBytes.checkInCalldata(i.encodedPreCalls, intentCalldata);
LibBytes.checkInCalldata(i.encodedFundTransfers, intentCalldata);
LibBytes.checkInCalldata(i.funderSignature, intentCalldata);
LibBytes.checkInCalldata(i.settlerContext, intentCalldata);
LibBytes.checkInCalldata(i.signature, intentCalldata);
LibBytes.checkInCalldata(i.paymentSignature, intentCalldata);
}
/// @dev Extracts the PreCall from the calldata bytes, with minimal checks.
function _extractPreCall(bytes calldata encodedPreCall)
internal
virtual
returns (SignedCall calldata p)
{
assembly ("memory-safe") {
// We can skip the offset checks here, since precalls are only accessed within the verify self-call.
// By that time, we already know that the intent struct is well formed.
let t := calldataload(encodedPreCall.offset)
p := add(t, encodedPreCall.offset)
}
}
/// @dev Executes a single encoded intent.
/// @dev If flags is non-zero, then all errors are bubbled up.
/// Currently there can only be 2 modes - simulation mode, and execution mode.
/// But we use a uint256 for efficient stack operations, and more flexiblity in the future.
/// Note: We keep the flags in the stack/memory (TSTORE doesn't work) to make sure they are reset in each new call context,
/// to provide protection against attacks which could spoof the execute function to believe it is in simulation mode.
function _execute(bytes calldata encodedIntent, uint256 combinedGasOverride, uint256 flags)
internal
virtual
returns (uint256 gUsed, bytes4 err)
{
Intent calldata i = _extractIntent(encodedIntent);
uint256 g = Math.coalesce(uint96(combinedGasOverride), i.combinedGas);
uint256 gStart = gasleft();
if (i.paymentAmount > i.paymentMaxAmount) {
err = PaymentError.selector;
if (flags == _SIMULATION_MODE_FLAG) {
revert PaymentError();
}
}
unchecked {
// Check if there's sufficient gas left for the gas-limited self calls
// via the 63/64 rule. This is for gas estimation. If the total amount of gas
// for the whole transaction is insufficient, revert.
if (((gasleft() * 63) >> 6) < Math.saturatingAdd(g, _INNER_GAS_OVERHEAD)) {
if (flags != _SIMULATION_MODE_FLAG) {
revert InsufficientGas();
}
}
}
if (i.supportedAccountImplementation != address(0)) {
if (accountImplementationOf(i.eoa) != i.supportedAccountImplementation) {
err = UnsupportedAccountImplementation.selector;
if (flags == _SIMULATION_MODE_FLAG) {
revert UnsupportedAccountImplementation();
}
}
}
address payer = Math.coalesce(i.payer, i.eoa);
// Early skip the entire pay-verify-call workflow if the payer lacks tokens,
// so that less gas is wasted when the Intent fails.
// For multi chain mode, we skip this check, as the funding happens inside the self call.
if (!i.isMultichain && LibBit.and(i.paymentAmount != 0, err == 0)) {
if (TokenTransferLib.balanceOf(i.paymentToken, payer) < i.paymentAmount) {
err = PaymentError.selector;
if (flags == _SIMULATION_MODE_FLAG) {
revert PaymentError();
}
}
}
bool selfCallSuccess;
// We'll use assembly for frequently used call related stuff to save massive memory gas.
assembly ("memory-safe") {
let m := mload(0x40) // Grab the free memory pointer.
if iszero(err) {
// Copy the encoded user op to the memory to be ready to pass to the self call.
calldatacopy(add(m, 0x40), encodedIntent.offset, encodedIntent.length)
mstore(m, 0x00000000) // `selfCallPayVerifyCall537021665()`.
// The word after the function selector contains the simulation flags.
mstore(add(m, 0x20), flags)
mstore(0x00, 0) // Zeroize the return slot.
// To prevent griefing, we need to do a non-reverting gas-limited self call.
// If the self call is successful, we know that the payment has been made,
// and the sequence for `nonce` has been incremented.
// For more information, see `selfCallPayVerifyCall537021665()`.
selfCallSuccess :=
call(g, address(), 0, add(m, 0x1c), add(encodedIntent.length, 0x24), 0x00, 0x20)
err := mload(0x00) // The self call will do another self call to execute.
if iszero(selfCallSuccess) {
// If it is a simulation, we simply revert with the full error.
if eq(flags, _SIMULATION_MODE_FLAG) {
returndatacopy(mload(0x40), 0x00, returndatasize())
revert(mload(0x40), returndatasize())
}
// If we don't get an error selector, then we set this one.
if iszero(err) { err := shl(224, 0xad4db224) } // `VerifiedCallError()`.
}
}
}
emit IntentExecuted(i.eoa, i.nonce, selfCallSuccess, err);
if (selfCallSuccess) {
gUsed = Math.rawSub(gStart, gasleft());
}
}
/// @dev This function is only intended for self-call.
/// The name is mined to give a function selector of `0x00000000`, which makes it
/// more efficient to call by placing it at the leftmost part of the function dispatch tree.
///
/// We perform a gas-limited self-call to this function via `_execute(bytes,uint256)`
/// with assembly for the following reasons:
/// - Allow recovery from out-of-gas errors.
/// When a transaction is actually mined, an `executionData` payload that takes 100k gas
/// to execute during simulation might require 1M gas to actually execute
/// (e.g. a sale contract that auto-distributes tokens at the very last sale).
/// If we do simply let this consume all gas, then the relayer's compensation
/// which is determined to be sufficient during simulation might not be actually sufficient.
/// We can only know how much gas a payload costs by actually executing it, but once it
/// has been executed, the gas burned cannot be returned and will be debited from the relayer.
/// - Avoid the overheads of `abi.encode`, `abi.decode`, and memory allocation.
/// Doing `(bool success, bytes memory result) = address(this).call(abi.encodeCall(...))`
/// incurs unnecessary ABI encoding, decoding, and memory allocation.
/// Quadratic memory expansion costs will make Intents in later parts of a batch
/// unfairly punished, while making gas estimates unreliable.
/// - For even more efficiency, we directly rip the Intent from the calldata instead
/// of making it as an argument to this function.
///
/// This function reverts if the PREP initialization or the Intent validation fails.
/// This is to prevent incorrect compensation (the Intent's signature defines what is correct).
function selfCallPayVerifyCall537021665() public payable {
require(msg.sender == address(this));
Intent calldata i;
uint256 flags;
assembly ("memory-safe") {
i := add(0x24, calldataload(0x24))
flags := calldataload(0x04)
}
// Check if intent has expired (only if expiry is set)
// If expiry timestamp is set to 0, then expiry is considered to be infinite.
if (i.expiry != 0 && block.timestamp > i.expiry) {
revert IntentExpired();
}
address eoa = i.eoa;
uint256 nonce = i.nonce;
bytes32 digest = _computeDigest(i);
_fund(eoa, i.funder, digest, i.encodedFundTransfers, i.funderSignature);
// The chicken and egg problem:
// A off-chain simulation of a successful Intent may not guarantee on-chain success.
// The state may change in the window between simulation and actual on-chain execution.
// If on-chain execution fails, gas that has already been burned cannot be returned
// and will be debited from the relayer.
// Yet, we still need to minimally check that the Intent has a valid signature to draw
// compensation. If we draw compensation first and then realize that the signature is
// invalid, we will need to refund the compensation, which is more inefficient than
// simply ensuring validity of the signature before drawing compensation.
// The best we can do is to minimize the chance that an Intent success in off-chain
// simulation can somehow result in an uncompensated on-chain failure.
// This is why ERC4337 has all those weird storage and opcode restrictions for
// simulation, and suggests banning users that intentionally grief the simulation.
// Handle the sub Intents after initialize (if any), and before the `_verify`.
if (i.encodedPreCalls.length != 0) _handlePreCalls(eoa, flags, i.encodedPreCalls);
// If `_verify` is invalid, just revert.
// The verification gas is determined by `executionData` and the account logic.
// Off-chain simulation of `_verify` should suffice, provided that the eoa's
// account is not changed, and the `keyHash` is not revoked
// in the window between off-chain simulation and on-chain execution.
bool isValid;
bytes32 keyHash;
if (i.isMultichain) {
// For multi chain intents, we have to verify using merkle sigs.
(isValid, keyHash) = _verifyMerkleSig(digest, eoa, i.signature);
// If this is an output intent, then send the digest as the settlementId
// on all input chains.
if (i.encodedFundTransfers.length > 0) {
// Output intent
ISettler(i.settler).send(digest, i.settlerContext);
}
} else {
(isValid, keyHash) = _verify(digest, eoa, i.signature);
}
if (flags == _SIMULATION_MODE_FLAG) {
isValid = true;
}
if (!isValid) revert VerificationError();
_checkAndIncrementNonce(eoa, nonce);
// Payment
// If `_pay` fails, just revert.
// Off-chain simulation of `_pay` should suffice,
// provided that the token balance does not decrease in the window between
// off-chain simulation and on-chain execution.
if (i.paymentAmount != 0) _pay(keyHash, digest, i);
// This re-encodes the ERC7579 `executionData` with the optional `opData`.
// We expect that the account supports ERC7821
// (an extension of ERC7579 tailored for 7702 accounts).
bytes memory data = LibERC7579.reencodeBatchAsExecuteCalldata(
hex"01000000000078210001", // ERC7821 batch execution mode.
i.executionData,
abi.encode(keyHash) // `opData`.
);
assembly ("memory-safe") {
mstore(0x00, 0) // Zeroize the return slot.
if iszero(call(gas(), eoa, 0, add(0x20, data), mload(data), 0x00, 0x20)) {
if eq(flags, _SIMULATION_MODE_FLAG) {
returndatacopy(mload(0x40), 0x00, returndatasize())
revert(mload(0x40), returndatasize())
}
if iszero(mload(0x00)) { mstore(0x00, shl(224, 0x6c9d47e8)) } // `CallError()`.
return(0x00, 0x20)
}
}
}
/// @dev Loops over the `encodedPreCalls` and does the following for each:
/// - If the `eoa == address(0)`, it will be coalesced to `parentEOA`.
/// - Check if `eoa == parentEOA`.
/// - Validate the signature.
/// - Check and increment the nonce.
/// - Call the Account with `executionData`, using the ERC7821 batch-execution mode.
/// If the call fails, revert.
/// - Emit an {IntentExecuted} event.
function _handlePreCalls(address parentEOA, uint256 flags, bytes[] calldata encodedPreCalls)
internal
virtual
{
for (uint256 j; j < encodedPreCalls.length; ++j) {
SignedCall calldata p = _extractPreCall(encodedPreCalls[j]);
address eoa = Math.coalesce(p.eoa, parentEOA);
uint256 nonce = p.nonce;
if (eoa != parentEOA) revert InvalidPreCallEOA();
(bool isValid, bytes32 keyHash) = _verify(_computeDigest(p), eoa, p.signature);
if (flags == _SIMULATION_MODE_FLAG) {
isValid = true;
}
if (!isValid) revert PreCallVerificationError();
_checkAndIncrementNonce(eoa, nonce);
// This part is same as `selfCallPayVerifyCall537021665`. We simply inline to save gas.
bytes memory data = LibERC7579.reencodeBatchAsExecuteCalldata(
hex"01000000000078210001", // ERC7821 batch execution mode.
p.executionData,
abi.encode(keyHash) // `opData`.
);
assembly ("memory-safe") {
mstore(0x00, 0) // Zeroize the return slot.
if iszero(call(gas(), eoa, 0, add(0x20, data), mload(data), 0x00, 0x20)) {
// If this is a simulation via `simulateFailed`, bubble up the whole revert.
if eq(flags, _SIMULATION_MODE_FLAG) {
returndatacopy(mload(0x40), 0x00, returndatasize())
revert(mload(0x40), returndatasize())
}
if iszero(mload(0x00)) { mstore(0x00, shl(224, 0x2228d5db)) } // `PreCallError()`.
revert(0x00, 0x20) // Revert the `err` (NOT return).
}
}
// Event so that indexers can know that the nonce is used.
// Reaching here means there's no error in the PreCall.
emit IntentExecuted(eoa, p.nonce, true, 0); // `incremented = true`, `err = 0`.
}
}
////////////////////////////////////////////////////////////////////////
// Account Implementation
////////////////////////////////////////////////////////////////////////
/// @dev Returns the implementation of the EOA.
/// If the EOA's account's is not valid EIP7702Proxy (via bytecode check), returns `address(0)`.
/// This function is provided as a public helper for easier integration.
function accountImplementationOf(address eoa) public view virtual returns (address result) {
(, result) = LibEIP7702.delegationAndImplementationOf(eoa);
}
////////////////////////////////////////////////////////////////////////
// Multi Chain Functions
////////////////////////////////////////////////////////////////////////
/// @dev Verifies the merkle sig for the multi chain intents.
/// - Note: Each leaf of the merkle tree should be a standard intent digest, computed with chainId.
/// - Leaf intents do NOT need to have the multichain nonce prefix.
/// - The signature for multi chain intents using merkle verification is encoded as:
/// - bytes signature = abi.encode(bytes32[] memory proof, bytes32 root, bytes memory rootSig)
function _verifyMerkleSig(bytes32 digest, address eoa, bytes memory signature)
internal
view
returns (bool isValid, bytes32 keyHash)
{
(bytes32[] memory proof, bytes32 root, bytes memory rootSig) =
abi.decode(signature, (bytes32[], bytes32, bytes));
if (MerkleProofLib.verify(proof, root, digest)) {
(isValid, keyHash) = IIthacaAccount(eoa).unwrapAndValidateSignature(root, rootSig);
return (isValid, keyHash);
}
return (false, bytes32(0));
}
/// @dev Funds the eoa with with the encoded fund transfers, before executing the intent.
/// - For ERC20 tokens, the funder needs to approve the orchestrator to pull funds.
/// - For native assets like ETH, the funder needs to transfer the funds to the orchestrator
/// before calling execute.
/// - The funder address should implement the IFunder interface.
function _fund(
address eoa,
address funder,
bytes32 digest,
bytes[] memory encodedFundTransfers,
bytes memory funderSignature
) internal virtual {
// Note: The fund function is mostly only used in the multi chain mode.
// For single chain intents the encodedFundTransfers field would be empty.
if (encodedFundTransfers.length == 0) {
return;
}
Transfer[] memory transfers = new Transfer[](encodedFundTransfers.length);
for (uint256 i; i < encodedFundTransfers.length; ++i) {
transfers[i] = abi.decode(encodedFundTransfers[i], (Transfer));
}
IFunder(funder).fund(digest, transfers, funderSignature);
uint256 j;
if (transfers[0].token == address(0)) {
SafeTransferLib.safeTransferETH(eoa, transfers[0].amount);
j++;
}
for (j; j < transfers.length; ++j) {
SafeTransferLib.safeTransferFrom(transfers[j].token, funder, eoa, transfers[j].amount);
}
}
////////////////////////////////////////////////////////////////////////
// Internal Helpers
////////////////////////////////////////////////////////////////////////
/// @dev Makes the `eoa` perform a payment to the `paymentRecipient` directly.
/// This reverts if the payment is insufficient or fails. Otherwise returns nothing.
function _pay(bytes32 keyHash, bytes32 digest, Intent calldata i) internal virtual {
uint256 paymentAmount = i.paymentAmount;
uint256 requiredBalanceAfter = Math.saturatingAdd(
TokenTransferLib.balanceOf(i.paymentToken, i.paymentRecipient), paymentAmount
);
address payer = Math.coalesce(i.payer, i.eoa);
// Call the pay function on the account contract
// Equivalent Solidity code:
// IIthacaAccount(payer).pay(paymentAmount, keyHash, digest, abi.encode(i));
// Gas Savings:
// Saves ~2k gas for normal use cases, by avoiding abi.encode and solidity external call overhead
assembly ("memory-safe") {
let m := mload(0x40) // Load the free memory pointer
mstore(m, 0xf81d87a7) // `pay(uint256,bytes32,bytes32,bytes)`
mstore(add(m, 0x20), paymentAmount) // Add payment amount as first param
mstore(add(m, 0x40), keyHash) // Add keyHash as second param
mstore(add(m, 0x60), digest) // Add digest as third param
mstore(add(m, 0x80), 0x80) // Add offset of encoded Intent as third param
let encodedSize := sub(calldatasize(), i)
mstore(add(m, 0xa0), add(encodedSize, 0x20)) // Store length of encoded Intent at offset.
mstore(add(m, 0xc0), 0x20) // Offset at which the Intent struct starts in encoded Intent.
// Copy the intent data to memory
calldatacopy(add(m, 0xe0), i, encodedSize)
// We revert here, so that if the payment fails, the execution is also reverted.
// The revert for payment is caught inside the selfCallPayVerify function.
if iszero(
call(
gas(), // gas
payer, // address
0, // value
add(m, 0x1c), // input memory offset
add(0xc4, encodedSize), // input size
0x00, // output memory offset
0x20 // output size
)
) { revert(0x00, 0x20) }
}
if (TokenTransferLib.balanceOf(i.paymentToken, i.paymentRecipient) < requiredBalanceAfter) {
revert PaymentError();
}
}
/// @dev Calls `unwrapAndValidateSignature` on the `eoa`.
function _verify(bytes32 digest, address eoa, bytes calldata sig)
internal
view
virtual
returns (bool isValid, bytes32 keyHash)
{
// While it is technically safe for the digest to be computed on the account,
// we do it on the Orchestrator for efficiency and maintainability. Validating the
// a single bytes32 digest avoids having to pass in the entire Intent. Additionally,
// the account does not need to know anything about the Intent structure.
assembly ("memory-safe") {
let m := mload(0x40)
mstore(m, 0x0cef73b4) // `unwrapAndValidateSignature(bytes32,bytes)`.
mstore(add(m, 0x20), digest)
mstore(add(m, 0x40), 0x40)
mstore(add(m, 0x60), sig.length)
calldatacopy(add(m, 0x80), sig.offset, sig.length)
isValid := staticcall(gas(), eoa, add(m, 0x1c), add(sig.length, 0x64), 0x00, 0x40)
isValid := and(eq(mload(0x00), 1), and(gt(returndatasize(), 0x3f), isValid))
keyHash := mload(0x20)
}
}
/// @dev calls `checkAndIncrementNonce` on the eoa.
function _checkAndIncrementNonce(address eoa, uint256 nonce) internal virtual {
assembly ("memory-safe") {
mstore(0x00, 0x9e49fbf1) // `checkAndIncrementNonce(uint256)`.
mstore(0x20, nonce)
if iszero(call(gas(), eoa, 0, 0x1c, 0x24, 0x00, 0x00)) {
mstore(0x00, 0x756688fe) // `InvalidNonce()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Computes the EIP712 digest for the PreCall.
function _computeDigest(SignedCall calldata p) internal view virtual returns (bytes32) {
bool isMultichain = p.nonce >> 240 == MULTICHAIN_NONCE_PREFIX;
// To avoid stack-too-deep. Faster than a regular Solidity array anyways.
bytes32[] memory f = EfficientHashLib.malloc(5);
f.set(0, SIGNED_CALL_TYPEHASH);
f.set(1, LibBit.toUint(isMultichain));
f.set(2, uint160(p.eoa));
f.set(3, _executionDataHash(p.executionData));
f.set(4, p.nonce);
return isMultichain ? _hashTypedDataSansChainId(f.hash()) : _hashTypedData(f.hash());
}
/// @dev Computes the EIP712 digest for the Intent.
/// If the the nonce starts with `MULTICHAIN_NONCE_PREFIX`,
/// the digest will be computed without the chain ID.
/// Otherwise, the digest will be computed with the chain ID.
function _computeDigest(Intent calldata i) internal view virtual returns (bytes32) {
bool isMultichain = i.nonce >> 240 == MULTICHAIN_NONCE_PREFIX;
// To avoid stack-too-deep. Faster than a regular Solidity array anyways.
bytes32[] memory f = EfficientHashLib.malloc(13);
f.set(0, INTENT_TYPEHASH);
f.set(1, LibBit.toUint(isMultichain));
f.set(2, uint160(i.eoa));
f.set(3, _executionDataHash(i.executionData));
f.set(4, i.nonce);
f.set(5, uint160(i.payer));
f.set(6, uint160(i.paymentToken));
f.set(7, i.paymentMaxAmount);
f.set(8, i.combinedGas);
f.set(9, _encodedArrHash(i.encodedPreCalls));
f.set(10, _encodedArrHash(i.encodedFundTransfers));
f.set(11, uint160(i.settler));
f.set(12, i.expiry);
return isMultichain ? _hashTypedDataSansChainId(f.hash()) : _hashTypedData(f.hash());
}
/// @dev Helper function to return the hash of the `execuctionData`.
function _executionDataHash(bytes calldata executionData)
internal
view
virtual
returns (bytes32)
{
bytes32[] calldata pointers = LibERC7579.decodeBatch(executionData);
bytes32[] memory a = EfficientHashLib.malloc(pointers.length);
unchecked {
for (uint256 i; i != pointers.length; ++i) {
(address target, uint256 value, bytes calldata data) = pointers.getExecution(i);
a.set(
i,
EfficientHashLib.hash(
CALL_TYPEHASH,
bytes32(uint256(uint160(target))),
bytes32(value),
EfficientHashLib.hashCalldata(data)
)
);
}
}
return a.hash();
}
/// @dev Helper function to return the hash of the `encodedPreCalls`.
function _encodedArrHash(bytes[] calldata encodedArr) internal view virtual returns (bytes32) {
bytes32[] memory a = EfficientHashLib.malloc(encodedArr.length);
for (uint256 i; i < encodedArr.length; ++i) {
a.set(i, EfficientHashLib.hashCalldata(encodedArr[i]));
}
return a.hash();
}
receive() external payable virtual {}
////////////////////////////////////////////////////////////////////////
// EIP712
////////////////////////////////////////////////////////////////////////
/// @dev For EIP712.
function _domainNameAndVersion()
internal
view
virtual
override
returns (string memory name, string memory version)
{
name = "Orchestrator";
version = "0.5.3";
}
////////////////////////////////////////////////////////////////////////
// Other Overrides
////////////////////////////////////////////////////////////////////////
/// @dev There won't be chains that have 7702 and without TSTORE.
function _useTransientReentrancyGuardOnlyOnMainnet()
internal
view
virtual
override
returns (bool)
{
return false;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {LibBit} from "./LibBit.sol";
/// @notice Library for storage of packed unsigned booleans.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol)
library LibBitmap {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when a bitmap scan does not find a result.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A bitmap in storage.
struct Bitmap {
mapping(uint256 => uint256) map;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the boolean value of the bit at `index` in `bitmap`.
function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) {
// It is better to set `isSet` to either 0 or 1, than zero vs non-zero.
// Both cost the same amount of gas, but the former allows the returned value
// to be reused without cleaning the upper bits.
uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1;
/// @solidity memory-safe-assembly
assembly {
isSet := b
}
}
/// @dev Updates the bit at `index` in `bitmap` to true.
function set(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] |= (1 << (index & 0xff));
}
/// @dev Updates the bit at `index` in `bitmap` to false.
function unset(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] &= ~(1 << (index & 0xff));
}
/// @dev Flips the bit at `index` in `bitmap`.
/// Returns the boolean result of the flipped bit.
function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot := keccak256(0x00, 0x40)
let shift := and(index, 0xff)
let storageValue := xor(sload(storageSlot), shl(shift, 1))
// It makes sense to return the `newIsSet`,
// as it allow us to skip an additional warm `sload`,
// and it costs minimal gas (about 15),
// which may be optimized away if the returned value is unused.
newIsSet := and(1, shr(shift, storageValue))
sstore(storageSlot, storageValue)
}
}
/// @dev Updates the bit at `index` in `bitmap` to `shouldSet`.
function setTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot := keccak256(0x00, 0x40)
let storageValue := sload(storageSlot)
let shift := and(index, 0xff)
sstore(
storageSlot,
// Unsets the bit at `shift` via `and`, then sets its new value via `or`.
or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))
)
}
}
/// @dev Consecutively sets `amount` of bits starting from the bit at `start`.
function setBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let max := not(0)
let shift := and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
if iszero(lt(add(shift, amount), 257)) {
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, max)))
let bucket := add(mload(0x00), 1)
let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
amount := and(add(amount, shift), 0xff)
shift := 0
for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), max)
}
mstore(0x00, bucket)
}
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max))))
}
}
/// @dev Consecutively unsets `amount` of bits starting from the bit at `start`.
function unsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let shift := and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
if iszero(lt(add(shift, amount), 257)) {
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0)))))
let bucket := add(mload(0x00), 1)
let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
amount := and(add(amount, shift), 0xff)
shift := 0
for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), 0)
}
mstore(0x00, bucket)
}
let storageSlot := keccak256(0x00, 0x40)
sstore(
storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))
)
}
}
/// @dev Returns number of set bits within a range by
/// scanning `amount` of bits starting from the bit at `start`.
function popCount(Bitmap storage bitmap, uint256 start, uint256 amount)
internal
view
returns (uint256 count)
{
unchecked {
uint256 bucket = start >> 8;
uint256 shift = start & 0xff;
if (!(amount + shift < 257)) {
count = LibBit.popCount(bitmap.map[bucket] >> shift);
uint256 bucketEnd = bucket + ((amount + shift) >> 8);
amount = (amount + shift) & 0xff;
shift = 0;
for (++bucket; bucket != bucketEnd; ++bucket) {
count += LibBit.popCount(bitmap.map[bucket]);
}
}
count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount));
}
}
/// @dev Returns the index of the most significant set bit in `[0..upTo]`.
/// If no set bit is found, returns `NOT_FOUND`.
function findLastSet(Bitmap storage bitmap, uint256 upTo)
internal
view
returns (uint256 setBitIndex)
{
setBitIndex = NOT_FOUND;
uint256 bucket = upTo >> 8;
uint256 bits;
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, bucket)
mstore(0x20, bitmap.slot)
let offset := and(0xff, not(upTo)) // `256 - (255 & upTo) - 1`.
bits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40))))
if iszero(or(bits, iszero(bucket))) {
for {} 1 {} {
bucket := add(bucket, setBitIndex) // `sub(bucket, 1)`.
mstore(0x00, bucket)
bits := sload(keccak256(0x00, 0x40))
if or(bits, iszero(bucket)) { break }
}
}
}
if (bits != 0) {
setBitIndex = (bucket << 8) | LibBit.fls(bits);
/// @solidity memory-safe-assembly
assembly {
setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, upTo)))
}
}
}
/// @dev Returns the index of the least significant unset bit in `[begin..upTo]`.
/// If no unset bit is found, returns `NOT_FOUND`.
function findFirstUnset(Bitmap storage bitmap, uint256 begin, uint256 upTo)
internal
view
returns (uint256 unsetBitIndex)
{
unsetBitIndex = NOT_FOUND;
uint256 bucket = begin >> 8;
uint256 negBits;
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, bucket)
mstore(0x20, bitmap.slot)
let offset := and(0xff, begin)
negBits := shl(offset, shr(offset, not(sload(keccak256(0x00, 0x40)))))
if iszero(negBits) {
let lastBucket := shr(8, upTo)
for {} 1 {} {
bucket := add(bucket, 1)
mstore(0x00, bucket)
negBits := not(sload(keccak256(0x00, 0x40)))
if or(negBits, gt(bucket, lastBucket)) { break }
}
if gt(bucket, lastBucket) {
negBits := shl(and(0xff, not(upTo)), shr(and(0xff, not(upTo)), negBits))
}
}
}
if (negBits != 0) {
uint256 r = (bucket << 8) | LibBit.ffs(negBits);
/// @solidity memory-safe-assembly
assembly {
unsetBitIndex := or(r, sub(0, or(gt(r, upTo), lt(r, begin))))
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for handling ERC7579 mode and execution data.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/accounts/LibERC7579.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/main/contracts/account/utils/draft-ERC7579Utils.sol)
library LibERC7579 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Cannot decode `executionData`.
error DecodingError();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A single execution.
bytes1 internal constant CALLTYPE_SINGLE = 0x00;
/// @dev A batch of executions.
bytes1 internal constant CALLTYPE_BATCH = 0x01;
/// @dev A single `staticcall` execution.
bytes1 internal constant CALLTYPE_STATICCALL = 0xfe;
/// @dev A `delegatecall` execution.
bytes1 internal constant CALLTYPE_DELEGATECALL = 0xff;
/// @dev Default execution type that reverts on failure.
bytes1 internal constant EXECTYPE_DEFAULT = 0x00;
/// @dev Execution type that does not revert on failure.
bytes1 internal constant EXECTYPE_TRY = 0x01;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Encodes the fields into a mode.
function encodeMode(bytes1 callType, bytes1 execType, bytes4 selector, bytes22 payload)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
result := or(shl(8, byte(0, callType)), byte(0, execType))
result := or(shr(224, selector), shl(64, result))
result := or(shr(80, payload), shl(176, result))
}
}
/// @dev Returns the call type of the mode.
function getCallType(bytes32 mode) internal pure returns (bytes1) {
return bytes1(mode);
}
/// @dev Returns the call type of the mode.
function getExecType(bytes32 mode) internal pure returns (bytes1) {
return mode[1];
}
/// @dev Returns the selector of the mode.
function getSelector(bytes32 mode) internal pure returns (bytes4) {
return bytes4(bytes32(uint256(mode) << 48));
}
/// @dev Returns the payload stored in the mode.
function getPayload(bytes32 mode) internal pure returns (bytes22) {
return bytes22(bytes32(uint256(mode) << 80));
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EXECUTION DATA OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Decodes a single call execution.
/// Reverts if `executionData` is not correctly encoded.
function decodeSingle(bytes calldata executionData)
internal
pure
returns (address target, uint256 value, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
if iszero(gt(executionData.length, 0x33)) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
target := shr(96, calldataload(executionData.offset))
value := calldataload(add(executionData.offset, 0x14))
data.offset := add(executionData.offset, 0x34)
data.length := sub(executionData.length, 0x34)
}
}
/// @dev Decodes a single call execution without bounds checks.
function decodeSingleUnchecked(bytes calldata executionData)
internal
pure
returns (address target, uint256 value, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
target := shr(96, calldataload(executionData.offset))
value := calldataload(add(executionData.offset, 0x14))
data.offset := add(executionData.offset, 0x34)
data.length := sub(executionData.length, 0x34)
}
}
/// @dev Decodes a single delegate execution.
/// Reverts if `executionData` is not correctly encoded.
function decodeDelegate(bytes calldata executionData)
internal
pure
returns (address target, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
if iszero(gt(executionData.length, 0x13)) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
target := shr(96, calldataload(executionData.offset))
data.offset := add(executionData.offset, 0x14)
data.length := sub(executionData.length, 0x14)
}
}
/// @dev Decodes a single delegate execution without bounds checks.
function decodeDelegateUnchecked(bytes calldata executionData)
internal
pure
returns (address target, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
target := shr(96, calldataload(executionData.offset))
data.offset := add(executionData.offset, 0x14)
data.length := sub(executionData.length, 0x14)
}
}
/// @dev Decodes a batch.
/// Reverts if `executionData` is not correctly encoded.
function decodeBatch(bytes calldata executionData)
internal
pure
returns (bytes32[] calldata pointers)
{
/// @solidity memory-safe-assembly
assembly {
let u := calldataload(executionData.offset)
let s := add(executionData.offset, u)
let e := sub(add(executionData.offset, executionData.length), 0x20)
pointers.offset := add(s, 0x20)
pointers.length := calldataload(s)
if or(shr(64, u), gt(add(s, shl(5, pointers.length)), e)) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
if pointers.length {
// Perform bounds checks on the decoded `pointers`.
// Loop runs out-of-gas if `pointers.length` is big enough to cause overflows.
for { let i := pointers.length } 1 {} {
i := sub(i, 1)
let p := calldataload(add(pointers.offset, shl(5, i)))
let c := add(pointers.offset, p)
let q := calldataload(add(c, 0x40))
let o := add(c, q)
// forgefmt: disable-next-item
if or(shr(64, or(calldataload(o), or(p, q))),
or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
if iszero(i) { break }
}
}
}
}
/// @dev Decodes a batch without bounds checks.
/// This function can be used in `execute`, if the validation phase has already
/// decoded the `executionData` with checks via `decodeBatch`.
function decodeBatchUnchecked(bytes calldata executionData)
internal
pure
returns (bytes32[] calldata pointers)
{
/// @solidity memory-safe-assembly
assembly {
let o := add(executionData.offset, calldataload(executionData.offset))
pointers.offset := add(o, 0x20)
pointers.length := calldataload(o)
}
}
/// @dev Decodes a batch and optional `opData`.
/// Reverts if `executionData` is not correctly encoded.
function decodeBatchAndOpData(bytes calldata executionData)
internal
pure
returns (bytes32[] calldata pointers, bytes calldata opData)
{
opData = emptyCalldataBytes();
pointers = decodeBatch(executionData);
if (hasOpData(executionData)) {
/// @solidity memory-safe-assembly
assembly {
let e := sub(add(executionData.offset, executionData.length), 0x20)
let p := calldataload(add(0x20, executionData.offset))
let q := add(executionData.offset, p)
opData.offset := add(q, 0x20)
opData.length := calldataload(q)
if or(shr(64, or(opData.length, p)), gt(add(q, opData.length), e)) {
mstore(0x00, 0xba597e7e) // `DecodingError()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Decodes a batch without bounds checks.
/// This function can be used in `execute`, if the validation phase has already
/// decoded the `executionData` with checks via `decodeBatchAndOpData`.
function decodeBatchAndOpDataUnchecked(bytes calldata executionData)
internal
pure
returns (bytes32[] calldata pointers, bytes calldata opData)
{
opData = emptyCalldataBytes();
pointers = decodeBatchUnchecked(executionData);
if (hasOpData(executionData)) {
/// @solidity memory-safe-assembly
assembly {
let q := add(executionData.offset, calldataload(add(0x20, executionData.offset)))
opData.offset := add(q, 0x20)
opData.length := calldataload(q)
}
}
}
/// @dev Returns whether the `executionData` has optional `opData`.
function hasOpData(bytes calldata executionData) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result :=
iszero(or(lt(executionData.length, 0x40), lt(calldataload(executionData.offset), 0x40)))
}
}
/// @dev Returns the `i`th execution at `pointers`, without bounds checks.
/// The bounds check is excluded as this function is intended to be called in a bounded loop.
function getExecution(bytes32[] calldata pointers, uint256 i)
internal
pure
returns (address target, uint256 value, bytes calldata data)
{
/// @solidity memory-safe-assembly
assembly {
let c := add(pointers.offset, calldataload(add(pointers.offset, shl(5, i))))
target := calldataload(c)
value := calldataload(add(c, 0x20))
let o := add(c, calldataload(add(c, 0x40)))
data.offset := add(o, 0x20)
data.length := calldataload(o)
}
}
/// @dev Reencodes `executionData` such that it has `opData` added to it.
/// Like `abi.encode(abi.decode(executionData, (Call[])), opData)`.
/// Useful for forwarding `executionData` with extra `opData`.
/// This function does not perform any check on the validity of `executionData`.
function reencodeBatch(bytes calldata executionData, bytes memory opData)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := add(0x64, mload(0x40)) // Give some space for `reencodeBatchAsExecuteCalldata`.
let s := calldataload(executionData.offset) // Offset of `calls`.
let n := sub(executionData.length, s) // Byte length of `calls`.
mstore(add(result, 0x20), 0x40) // Store the new offset of `calls`.
calldatacopy(add(result, 0x60), add(executionData.offset, s), n)
mstore(add(result, 0x40), add(0x40, n)) // Store the new offset of `opData`.
let o := add(add(result, 0x60), n) // Start offset of `opData` destination in memory.
let d := sub(opData, o) // Offset difference between `opData` source and `o`.
let end := add(mload(opData), add(0x20, o)) // End of `opData` destination in memory.
for {} 1 {} {
mstore(o, mload(add(o, d)))
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(result, sub(o, add(result, 0x20))) // Store the length of `result`.
calldatacopy(end, calldatasize(), 0x40) // Zeroize the bytes after `end`.
mstore(0x40, add(0x20, o)) // Allocate memory.
}
}
/// @dev `abi.encodeWithSignature("execute(bytes32,bytes)", mode, reencodeBatch(executionData, opData))`.
function reencodeBatchAsExecuteCalldata(
bytes32 mode,
bytes calldata executionData,
bytes memory opData
) internal pure returns (bytes memory result) {
result = reencodeBatch(executionData, opData);
/// @solidity memory-safe-assembly
assembly {
let n := mload(result)
result := sub(result, 0x64)
mstore(add(result, 0x44), 0x40) // Offset of `executionData`.
mstore(add(result, 0x24), mode)
mstore(add(result, 0x04), 0xe9ae5c53) // `execute(bytes32,bytes)`.
mstore(result, add(0x64, n))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Helper function to return empty calldata bytes.
function emptyCalldataBytes() internal pure returns (bytes calldata result) {
/// @solidity memory-safe-assembly
assembly {
result.offset := 0
result.length := 0
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @notice Library for EIP7702 operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/accounts/LibEIP7702.sol)
library LibEIP7702 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Failed to deploy the EIP7702Proxy.
error DeploymentFailed();
/// @dev The proxy query has failed.
error ProxyQueryFailed();
/// @dev Failed to change the proxy admin.
error ChangeProxyAdminFailed();
/// @dev Failed to upgrade the proxy.
error UpgradeProxyFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ERC-1967 storage slot for the implementation in the proxy.
/// `uint256(keccak256("eip1967.proxy.implementation")) - 1`.
bytes32 internal constant ERC1967_IMPLEMENTATION_SLOT =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/// @dev The transient storage slot for requesting the proxy to initialize the implementation.
/// `uint256(keccak256("eip7702.proxy.delegation.initialization.request")) - 1`.
/// While we would love to use a smaller constant, this slot is used in both the proxy
/// and the delegation, so we shall just use bytes32 in case we want to standardize this.
bytes32 internal constant EIP7702_PROXY_DELEGATION_INITIALIZATION_REQUEST_SLOT =
0x94e11c6e41e7fb92cb8bb65e13fdfbd4eba8b831292a1a220f7915c78c7c078f;
/// @dev The creation code for the EIP7702Proxy.
/// This is generated from `EIP7702Proxy.sol` with exact compilation settings.
bytes internal constant EIP7702_PROXY_CREATION_CODE =
hex"60c06040819052306080526102d63881900390819083398101604081905261002691610096565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8290557fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103819055811515110260a0526100c7565b80516001600160a01b0381168114610091575f5ffd5b919050565b5f5f604083850312156100a7575f5ffd5b6100b08361007b565b91506100be6020840161007b565b90509250929050565b60805160a0516101f06100e65f395f602701525f600601526101f05ff3fe60016040527f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc361960601c30841861010a576001361161008657815481165f5260205ff35b5f3560e01c80635c60da1b036100a157825482165f5260205ff35b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61038163f851a440036100d65780545f5260205ff35b80543303610106578382630900f01014028183638f2839701402178015610104576004358416815560206040f35b505b5f5ffd5b815481163660010361013b5780610133575082806101335760205f5f5f885afa15610106573d5ff35b805f5260205ff35b365f5f37806101a7575082806101a7576020365f5f885afa5f5f365f36515af416610168573d5f5f3e3d5ffd5b7f94e11c6e41e7fb92cb8bb65e13fdfbd4eba8b831292a1a220f7915c78c7c078f805c1561019e57365184548419161784555f815d5b503d5f5f3e3d5ff35b5f5f365f845af461019e573d5f5f3e3d5ffdfea2646970667358221220e8b1a2a38594baf32c154aa7dd7743c9cd741d4f386b5ab588a5dcd613c3a00e64736f6c634300081c0033";
/// @dev The keccak256 of runtime code for `EIP7702Proxy.sol` with exact compilation settings,
/// with immutables zeroized and without the CBOR metadata.
bytes32 internal constant EIP7702_PROXY_MINIMAL_CODE_HASH =
0xf8710866f390ac7c12640457f9cb9663657ac8168b7d4ce6418a982932b3043e;
/// @dev The length of the runtime code for `EIP7702Proxy.sol` with exact compilation settings,
/// with immutables zeroized and without the CBOR metadata.
uint256 internal constant EIP7702_PROXY_MINIMAL_CODE_LENGTH = 0x1ba;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* AUTHORITY AND PROXY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the delegation of the account.
/// If the account is not an EIP7702 authority, returns `address(0)`.
function delegationOf(address account) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
extcodecopy(account, 0x00, 0x00, 0x20)
// Note: Checking that it starts with hex"ef01" is the most general and futureproof.
// 7702 bytecode is `abi.encodePacked(hex"ef01", uint8(version), address(delegation))`.
result := mul(shr(96, mload(0x03)), eq(0xef01, shr(240, mload(0x00))))
}
}
/// @dev Returns the delegation and the implementation of the account.
/// If the account delegation is not a valid EIP7702Proxy, returns `address(0)`.
function delegationAndImplementationOf(address account)
internal
view
returns (address delegation, address implementation)
{
delegation = delegationOf(account);
if (isEIP7702Proxy(delegation)) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0)
if iszero(staticcall(gas(), account, 0x00, 0x01, 0x00, 0x20)) { revert(0x00, 0x00) }
implementation := mload(0x00)
}
}
}
/// @dev Returns the implementation of `target`.
/// If `target` is neither an EIP7702Proxy nor an EOA delegated to an EIP7702Proxy, returns `address(0)`.
function implementationOf(address target) internal view returns (address result) {
if (!isEIP7702Proxy(target)) if (!isEIP7702Proxy(delegationOf(target))) return address(0);
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0)
if iszero(staticcall(gas(), target, 0x00, 0x01, 0x00, 0x20)) { revert(0x00, 0x00) }
result := mload(0x00)
}
}
/// @dev Returns if `target` is an valid EIP7702Proxy based on a bytecode hash check.
function isEIP7702Proxy(address target) internal view returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
// Copy the runtime bytecode without the CBOR metadata.
extcodecopy(target, m, 0x00, EIP7702_PROXY_MINIMAL_CODE_LENGTH)
// Zeroize the immutables.
mstore(add(m, 0x06), 0) // The first `7f<immutable_word>`.
mstore(add(m, 0x27), 0) // The second `7f<immutable_word>`.
let h := keccak256(m, EIP7702_PROXY_MINIMAL_CODE_LENGTH)
result := eq(EIP7702_PROXY_MINIMAL_CODE_HASH, h)
}
}
/// @dev Returns the initialization code for the EIP7702Proxy.
function proxyInitCode(address initialImplementation, address initialAdmin)
internal
pure
returns (bytes memory)
{
return abi.encodePacked(
EIP7702_PROXY_CREATION_CODE,
uint256(uint160(initialImplementation)),
uint256(uint160(initialAdmin))
);
}
/// @dev Deploys an EIP7702Proxy.
function deployProxy(address initialImplementation, address initialAdmin)
internal
returns (address instance)
{
bytes memory initCode = proxyInitCode(initialImplementation, initialAdmin);
/// @solidity memory-safe-assembly
assembly {
instance := create(0, add(initCode, 0x20), mload(initCode))
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Deploys an EIP7702Proxy to a deterministic address with `salt`.
function deployProxyDeterministic(
address initialImplementation,
address initialAdmin,
bytes32 salt
) internal returns (address instance) {
bytes memory initCode = proxyInitCode(initialImplementation, initialAdmin);
/// @solidity memory-safe-assembly
assembly {
instance := create2(0, add(initCode, 0x20), mload(initCode), salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns the admin of the proxy.
/// Assumes that the proxy is a proper EIP7702Proxy, if it exists.
function proxyAdmin(address proxy) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0xf851a440) // `admin()`.
let t := staticcall(gas(), proxy, 0x1c, 0x04, 0x00, 0x20)
if iszero(and(gt(returndatasize(), 0x1f), t)) {
mstore(0x00, 0x26ec9b6a) // `ProxyQueryFailed()`.
revert(0x1c, 0x04)
}
result := mload(0x00)
}
}
/// @dev Changes the admin on the proxy. The caller must be the admin.
/// Assumes that the proxy is a proper EIP7702Proxy, if it exists.
function changeProxyAdmin(address proxy, address newAdmin) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x8f283970) // `changeAdmin(address)`.
mstore(0x20, newAdmin) // The implementation will clean the upper 96 bits.
if iszero(and(eq(mload(0x00), 1), call(gas(), proxy, 0, 0x1c, 0x24, 0x00, 0x20))) {
mstore(0x00, 0xc502e37e) // `ChangeProxyAdminFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Changes the implementation on the proxy. The caller must be the admin.
/// Assumes that the proxy is a proper EIP7702Proxy, if it exists.
function upgradeProxy(address proxy, address newImplementation) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x0900f010) // `upgrade(address)`.
mstore(0x20, newImplementation) // The implementation will clean the upper 96 bits.
if iszero(and(eq(mload(0x00), 1), call(gas(), proxy, 0, 0x1c, 0x24, 0x00, 0x20))) {
mstore(0x00, 0xc6edd882) // `UpgradeProxyFailed()`.
revert(0x1c, 0x04)
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* UUPS OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Upgrades the implementation.
/// The new implementation will NOT be active until the next UserOp or transaction.
/// To "auto-upgrade" to the latest implementation on the proxy, pass in `address(0)` to reset
/// the implementation slot. This causes the proxy to use the latest default implementation,
/// which may be optionally reinitialized via `requestProxyDelegationInitialization()`.
/// This function is intended to be used on the authority of an EIP7702Proxy delegation.
/// The most intended usage pattern is to wrap this in an access-gated admin function.
function upgradeProxyDelegation(address newImplementation) internal {
/// @solidity memory-safe-assembly
assembly {
let s := ERC1967_IMPLEMENTATION_SLOT
// Preserve the upper 96 bits when updating in case they are used for some stuff.
mstore(0x00, sload(s))
mstore(0x0c, shl(96, newImplementation))
sstore(s, mload(0x00))
}
}
/// @dev Requests the implementation to be initialized to the latest implementation on the proxy.
/// This function is intended to be used on the authority of an EIP7702Proxy delegation.
/// The most intended usage pattern is to place it at the end of an `execute` function.
function requestProxyDelegationInitialization() internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, sload(ERC1967_IMPLEMENTATION_SLOT))) {
// Use a dedicated transient storage slot for better Swiss-cheese-model safety.
tstore(EIP7702_PROXY_DELEGATION_INITIALIZATION_REQUEST_SLOT, address())
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for efficiently performing keccak256 hashes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EfficientHashLib.sol)
/// @dev To avoid stack-too-deep, you can use:
/// ```
/// bytes32[] memory buffer = EfficientHashLib.malloc(10);
/// EfficientHashLib.set(buffer, 0, value0);
/// ..
/// EfficientHashLib.set(buffer, 9, value9);
/// bytes32 finalHash = EfficientHashLib.hash(buffer);
/// ```
library EfficientHashLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MALLOC-LESS HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `keccak256(abi.encode(v0))`.
function hash(bytes32 v0) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
result := keccak256(0x00, 0x20)
}
}
/// @dev Returns `keccak256(abi.encode(v0))`.
function hash(uint256 v0) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
result := keccak256(0x00, 0x20)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1))`.
function hash(bytes32 v0, bytes32 v1) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
mstore(0x20, v1)
result := keccak256(0x00, 0x40)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1))`.
function hash(uint256 v0, uint256 v1) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
mstore(0x20, v1)
result := keccak256(0x00, 0x40)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
result := keccak256(m, 0x60)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
function hash(uint256 v0, uint256 v1, uint256 v2) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
result := keccak256(m, 0x60)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
result := keccak256(m, 0x80)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
result := keccak256(m, 0x80)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
result := keccak256(m, 0xa0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
result := keccak256(m, 0xa0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4, bytes32 v5)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
result := keccak256(m, 0xc0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4, uint256 v5)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
result := keccak256(m, 0xc0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
result := keccak256(m, 0xe0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
result := keccak256(m, 0xe0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
result := keccak256(m, 0x100)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
result := keccak256(m, 0x100)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
result := keccak256(m, 0x120)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
result := keccak256(m, 0x120)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
result := keccak256(m, 0x140)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
result := keccak256(m, 0x140)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
result := keccak256(m, 0x160)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
result := keccak256(m, 0x160)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
result := keccak256(m, 0x180)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
result := keccak256(m, 0x180)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11,
bytes32 v12
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
result := keccak256(m, 0x1a0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11,
uint256 v12
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
result := keccak256(m, 0x1a0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11,
bytes32 v12,
bytes32 v13
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
mstore(add(m, 0x1a0), v13)
result := keccak256(m, 0x1c0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11,
uint256 v12,
uint256 v13
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
mstore(add(m, 0x1a0), v13)
result := keccak256(m, 0x1c0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES32 BUFFER HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `keccak256(abi.encode(buffer[0], .., buffer[buffer.length - 1]))`.
function hash(bytes32[] memory buffer) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := keccak256(add(buffer, 0x20), shl(5, mload(buffer)))
}
}
/// @dev Sets `buffer[i]` to `value`, without a bounds check.
/// Returns the `buffer` for function chaining.
function set(bytes32[] memory buffer, uint256 i, bytes32 value)
internal
pure
returns (bytes32[] memory)
{
/// @solidity memory-safe-assembly
assembly {
mstore(add(buffer, shl(5, add(1, i))), value)
}
return buffer;
}
/// @dev Sets `buffer[i]` to `value`, without a bounds check.
/// Returns the `buffer` for function chaining.
function set(bytes32[] memory buffer, uint256 i, uint256 value)
internal
pure
returns (bytes32[] memory)
{
/// @solidity memory-safe-assembly
assembly {
mstore(add(buffer, shl(5, add(1, i))), value)
}
return buffer;
}
/// @dev Returns `new bytes32[](n)`, without zeroing out the memory.
function malloc(uint256 n) internal pure returns (bytes32[] memory buffer) {
/// @solidity memory-safe-assembly
assembly {
buffer := mload(0x40)
mstore(buffer, n)
mstore(0x40, add(shl(5, add(1, n)), buffer))
}
}
/// @dev Frees memory that has been allocated for `buffer`.
/// No-op if `buffer.length` is zero, or if new memory has been allocated after `buffer`.
function free(bytes32[] memory buffer) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(buffer)
mstore(shl(6, lt(iszero(n), eq(add(shl(5, add(1, n)), buffer), mload(0x40)))), buffer)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EQUALITY CHECKS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `a == abi.decode(b, (bytes32))`.
function eq(bytes32 a, bytes memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := and(eq(0x20, mload(b)), eq(a, mload(add(b, 0x20))))
}
}
/// @dev Returns `abi.decode(a, (bytes32)) == a`.
function eq(bytes memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := and(eq(0x20, mload(a)), eq(b, mload(add(a, 0x20))))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE SLICE HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function hash(bytes memory b, uint256 start, uint256 end)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
end := xor(end, mul(xor(end, n), lt(n, end)))
start := xor(start, mul(xor(start, n), lt(n, start)))
result := keccak256(add(add(b, 0x20), start), mul(gt(end, start), sub(end, start)))
}
}
/// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
function hash(bytes memory b, uint256 start) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
start := xor(start, mul(xor(start, n), lt(n, start)))
result := keccak256(add(add(b, 0x20), start), mul(gt(n, start), sub(n, start)))
}
}
/// @dev Returns the keccak256 of the bytes.
function hash(bytes memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := keccak256(add(b, 0x20), mload(b))
}
}
/// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function hashCalldata(bytes calldata b, uint256 start, uint256 end)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(end, start), sub(end, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := keccak256(mload(0x40), n)
}
}
/// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
function hashCalldata(bytes calldata b, uint256 start) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(b.length, start), sub(b.length, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := keccak256(mload(0x40), n)
}
}
/// @dev Returns the keccak256 of the bytes.
function hashCalldata(bytes calldata b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
calldatacopy(mload(0x40), b.offset, b.length)
result := keccak256(mload(0x40), b.length)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SHA2-256 HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `sha256(abi.encode(b))`. Yes, it's more efficient.
function sha2(bytes32 b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, b)
result := mload(staticcall(gas(), 2, 0x00, 0x20, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function sha2(bytes memory b, uint256 start, uint256 end)
internal
view
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
end := xor(end, mul(xor(end, n), lt(n, end)))
start := xor(start, mul(xor(start, n), lt(n, start)))
// forgefmt: disable-next-item
result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
mul(gt(end, start), sub(end, start)), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
function sha2(bytes memory b, uint256 start) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
start := xor(start, mul(xor(start, n), lt(n, start)))
// forgefmt: disable-next-item
result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
mul(gt(n, start), sub(n, start)), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the bytes.
function sha2(bytes memory b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(staticcall(gas(), 2, add(b, 0x20), mload(b), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function sha2Calldata(bytes calldata b, uint256 start, uint256 end)
internal
view
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(end, start), sub(end, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
function sha2Calldata(bytes calldata b, uint256 start) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(b.length, start), sub(b.length, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the bytes.
function sha2Calldata(bytes calldata b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
calldatacopy(mload(0x40), b.offset, b.length)
result := mload(staticcall(gas(), 2, mload(0x40), b.length, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @notice Reentrancy guard mixin (transient storage variant).
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuardTransient.sol)
///
/// @dev Note: This implementation utilizes the `TSTORE` and `TLOAD` opcodes.
/// Please ensure that the chain you are deploying on supports them.
abstract contract ReentrancyGuardTransient {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unauthorized reentrant call.
error Reentrancy();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to: `uint32(bytes4(keccak256("Reentrancy()"))) | 1 << 71`.
/// 9 bytes is large enough to avoid collisions in practice,
/// but not too large to result in excessive bytecode bloat.
uint256 private constant _REENTRANCY_GUARD_SLOT = 0x8000000000ab143c06;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* REENTRANCY GUARD */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Guards a function from reentrancy.
modifier nonReentrant() virtual {
if (_useTransientReentrancyGuardOnlyOnMainnet()) {
uint256 s = _REENTRANCY_GUARD_SLOT;
if (block.chainid == 1) {
/// @solidity memory-safe-assembly
assembly {
if tload(s) {
mstore(0x00, s) // `Reentrancy()`.
revert(0x1c, 0x04)
}
tstore(s, address())
}
} else {
/// @solidity memory-safe-assembly
assembly {
if eq(sload(s), address()) {
mstore(0x00, s) // `Reentrancy()`.
revert(0x1c, 0x04)
}
sstore(s, address())
}
}
} else {
/// @solidity memory-safe-assembly
assembly {
if tload(_REENTRANCY_GUARD_SLOT) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
tstore(_REENTRANCY_GUARD_SLOT, address())
}
}
_;
if (_useTransientReentrancyGuardOnlyOnMainnet()) {
uint256 s = _REENTRANCY_GUARD_SLOT;
if (block.chainid == 1) {
/// @solidity memory-safe-assembly
assembly {
tstore(s, 0)
}
} else {
/// @solidity memory-safe-assembly
assembly {
sstore(s, s)
}
}
} else {
/// @solidity memory-safe-assembly
assembly {
tstore(_REENTRANCY_GUARD_SLOT, 0)
}
}
}
/// @dev Guards a view function from read-only reentrancy.
modifier nonReadReentrant() virtual {
if (_useTransientReentrancyGuardOnlyOnMainnet()) {
uint256 s = _REENTRANCY_GUARD_SLOT;
if (block.chainid == 1) {
/// @solidity memory-safe-assembly
assembly {
if tload(s) {
mstore(0x00, s) // `Reentrancy()`.
revert(0x1c, 0x04)
}
}
} else {
/// @solidity memory-safe-assembly
assembly {
if eq(sload(s), address()) {
mstore(0x00, s) // `Reentrancy()`.
revert(0x1c, 0x04)
}
}
}
} else {
/// @solidity memory-safe-assembly
assembly {
if tload(_REENTRANCY_GUARD_SLOT) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
}
}
_;
}
/// @dev For widespread compatibility with L2s.
/// Only Ethereum mainnet is expensive anyways.
function _useTransientReentrancyGuardOnlyOnMainnet() internal view virtual returns (bool) {
return true;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Contract for EIP-712 typed structured data hashing and signing.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol)
/// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol)
///
/// @dev Note, this implementation:
/// - Uses `address(this)` for the `verifyingContract` field.
/// - Does NOT use the optional EIP-712 salt.
/// - Does NOT use any EIP-712 extensions.
/// This is for simplicity and to save gas.
/// If you need to customize, please fork / modify accordingly.
abstract contract EIP712 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS AND IMMUTABLES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
bytes32 internal constant _DOMAIN_TYPEHASH =
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
/// @dev `keccak256("EIP712Domain(string name,string version,address verifyingContract)")`.
/// This is only used in `_hashTypedDataSansChainId`.
bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID =
0x91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a2766;
/// @dev `keccak256("EIP712Domain(string name,string version)")`.
/// This is only used in `_hashTypedDataSansChainIdAndVerifyingContract`.
bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT =
0xb03948446334eb9b2196d5eb166f69b9d49403eb4a12f36de8d3f9f3cb8e15c3;
/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId)")`.
/// This is only used in `_hashTypedDataSansVerifyingContract`.
bytes32 internal constant _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT =
0xc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e;
uint256 private immutable _cachedThis;
uint256 private immutable _cachedChainId;
bytes32 private immutable _cachedNameHash;
bytes32 private immutable _cachedVersionHash;
bytes32 private immutable _cachedDomainSeparator;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTRUCTOR */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Cache the hashes for cheaper runtime gas costs.
/// In the case of upgradeable contracts (i.e. proxies),
/// or if the chain id changes due to a hard fork,
/// the domain separator will be seamlessly calculated on-the-fly.
constructor() {
_cachedThis = uint256(uint160(address(this)));
_cachedChainId = block.chainid;
string memory name;
string memory version;
if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion();
bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name));
bytes32 versionHash =
_domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version));
_cachedNameHash = nameHash;
_cachedVersionHash = versionHash;
bytes32 separator;
if (!_domainNameAndVersionMayChange()) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), versionHash)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
separator := keccak256(m, 0xa0)
}
}
_cachedDomainSeparator = separator;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Please override this function to return the domain name and version.
/// ```
/// function _domainNameAndVersion()
/// internal
/// pure
/// virtual
/// returns (string memory name, string memory version)
/// {
/// name = "Solady";
/// version = "1";
/// }
/// ```
///
/// Note: If the returned result may change after the contract has been deployed,
/// you must override `_domainNameAndVersionMayChange()` to return true.
function _domainNameAndVersion()
internal
view
virtual
returns (string memory name, string memory version);
/// @dev Returns if `_domainNameAndVersion()` may change
/// after the contract has been deployed (i.e. after the constructor).
/// Default: false.
function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the EIP-712 domain separator.
function _domainSeparator() internal view virtual returns (bytes32 separator) {
if (_domainNameAndVersionMayChange()) {
separator = _buildDomainSeparator();
} else {
separator = _cachedDomainSeparator;
if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator();
}
}
/// @dev Returns the hash of the fully encoded EIP-712 message for this domain,
/// given `structHash`, as defined in
/// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
///
/// The hash can be used together with {ECDSA-recover} to obtain the signer of a message:
/// ```
/// bytes32 digest = _hashTypedData(keccak256(abi.encode(
/// keccak256("Mail(address to,string contents)"),
/// mailTo,
/// keccak256(bytes(mailContents))
/// )));
/// address signer = ECDSA.recover(digest, signature);
/// ```
function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) {
// We will use `digest` to store the domain separator to save a bit of gas.
if (_domainNameAndVersionMayChange()) {
digest = _buildDomainSeparator();
} else {
digest = _cachedDomainSeparator;
if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator();
}
/// @solidity memory-safe-assembly
assembly {
// Compute the digest.
mstore(0x00, 0x1901000000000000) // Store "\x19\x01".
mstore(0x1a, digest) // Store the domain separator.
mstore(0x3a, structHash) // Store the struct hash.
digest := keccak256(0x18, 0x42)
// Restore the part of the free memory slot that was overwritten.
mstore(0x3a, 0)
}
}
/// @dev Variant of `_hashTypedData` that excludes the chain ID.
/// Included for the niche use case of cross-chain workflows.
function _hashTypedDataSansChainId(bytes32 structHash)
internal
view
virtual
returns (bytes32 digest)
{
(string memory name, string memory version) = _domainNameAndVersion();
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(0x00, _DOMAIN_TYPEHASH_SANS_CHAIN_ID)
mstore(0x20, keccak256(add(name, 0x20), mload(name)))
mstore(0x40, keccak256(add(version, 0x20), mload(version)))
mstore(0x60, address())
// Compute the digest.
mstore(0x20, keccak256(0x00, 0x80)) // Store the domain separator.
mstore(0x00, 0x1901) // Store "\x19\x01".
mstore(0x40, structHash) // Store the struct hash.
digest := keccak256(0x1e, 0x42)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero pointer.
}
}
/// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
/// Included for the niche use case of cross-chain and multi-verifier workflows.
function _hashTypedDataSansChainIdAndVerifyingContract(bytes32 structHash)
internal
view
virtual
returns (bytes32 digest)
{
(string memory name, string memory version) = _domainNameAndVersion();
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(0x00, _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT)
mstore(0x20, keccak256(add(name, 0x20), mload(name)))
mstore(0x40, keccak256(add(version, 0x20), mload(version)))
// Compute the digest.
mstore(0x20, keccak256(0x00, 0x60)) // Store the domain separator.
mstore(0x00, 0x1901) // Store "\x19\x01".
mstore(0x40, structHash) // Store the struct hash.
digest := keccak256(0x1e, 0x42)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero pointer.
}
}
/// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
/// Included for the niche use case of multi-verifier workflows.
function _hashTypedDataSansVerifyingContract(bytes32 structHash)
internal
view
virtual
returns (bytes32 digest)
{
(string memory name, string memory version) = _domainNameAndVersion();
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(0x00, _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT)
mstore(0x20, keccak256(add(name, 0x20), mload(name)))
mstore(0x40, keccak256(add(version, 0x20), mload(version)))
mstore(0x60, chainid())
// Compute the digest.
mstore(0x20, keccak256(0x00, 0x80)) // Store the domain separator.
mstore(0x00, 0x1901) // Store "\x19\x01".
mstore(0x40, structHash) // Store the struct hash.
digest := keccak256(0x1e, 0x42)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EIP-5267 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev See: https://eips.ethereum.org/EIPS/eip-5267
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
fields = hex"0f"; // `0b01111`.
(name, version) = _domainNameAndVersion();
chainId = block.chainid;
verifyingContract = address(this);
salt = salt; // `bytes32(0)`.
extensions = extensions; // `new uint256[](0)`.
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the EIP-712 domain separator.
function _buildDomainSeparator() private view returns (bytes32 separator) {
// We will use `separator` to store the name hash to save a bit of gas.
bytes32 versionHash;
if (_domainNameAndVersionMayChange()) {
(string memory name, string memory version) = _domainNameAndVersion();
separator = keccak256(bytes(name));
versionHash = keccak256(bytes(version));
} else {
separator = _cachedNameHash;
versionHash = _cachedVersionHash;
}
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), separator) // Name hash.
mstore(add(m, 0x40), versionHash)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
separator := keccak256(m, 0xa0)
}
}
/// @dev Returns if the cached domain separator has been invalidated.
function _cachedDomainSeparatorInvalidated() private view returns (bool result) {
uint256 cachedChainId = _cachedChainId;
uint256 cachedThis = _cachedThis;
/// @solidity memory-safe-assembly
assembly {
result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis)))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for bit twiddling and boolean operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)
/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)
library LibBit {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BIT TWIDDLING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Find last set.
/// Returns the index of the most significant bit of `x`,
/// counting from the least significant bit position.
/// If `x` is zero, returns 256.
function fls(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x)))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Count leading zeros.
/// Returns the number of zeros preceding the most significant one bit.
/// If `x` is zero, returns 256.
function clz(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))
}
}
/// @dev Find first set.
/// Returns the index of the least significant bit of `x`,
/// counting from the least significant bit position.
/// If `x` is zero, returns 256.
/// Equivalent to `ctz` (count trailing zeros), which gives
/// the number of zeros following the least significant one bit.
function ffs(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Isolate the least significant bit.
x := and(x, add(not(x), 1))
// For the upper 3 bits of the result, use a De Bruijn-like lookup.
// Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/
// forgefmt: disable-next-item
r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,
0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),
0x8040405543005266443200005020610674053026020000107506200176117077)))
// For the lower 5 bits of the result, use a De Bruijn lookup.
// forgefmt: disable-next-item
r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
/// @dev Returns the number of set bits in `x`.
function popCount(uint256 x) internal pure returns (uint256 c) {
/// @solidity memory-safe-assembly
assembly {
let max := not(0)
let isMax := eq(x, max)
x := sub(x, and(shr(1, x), div(max, 3)))
x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))
x := and(add(x, shr(4, x)), div(max, 17))
c := or(shl(8, isMax), shr(248, mul(x, div(max, 255))))
}
}
/// @dev Returns the number of zero bytes in `x`.
/// To get the number of non-zero bytes, simply do `32 - countZeroBytes(x)`.
function countZeroBytes(uint256 x) internal pure returns (uint256 c) {
/// @solidity memory-safe-assembly
assembly {
let m := 0x7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
c := byte(0, mul(shr(7, not(m)), shr(7, not(or(or(add(and(x, m), m), x), m)))))
}
}
/// @dev Returns the number of zero bytes in `s`.
/// To get the number of non-zero bytes, simply do `s.length - countZeroBytes(s)`.
function countZeroBytes(bytes memory s) internal pure returns (uint256 c) {
/// @solidity memory-safe-assembly
assembly {
function czb(x_) -> _c {
let _m := 0x7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
_c := shr(7, not(or(or(add(and(x_, _m), _m), x_), _m)))
_c := byte(0, mul(shr(7, not(_m)), _c))
}
let n := mload(s)
let l := shl(5, shr(5, n))
s := add(s, 0x20)
for { let i } xor(i, l) { i := add(i, 0x20) } { c := add(czb(mload(add(s, i))), c) }
if lt(l, n) { c := add(czb(or(shr(shl(3, sub(n, l)), not(0)), mload(add(s, l)))), c) }
}
}
/// @dev Returns the number of zero bytes in `s`.
/// To get the number of non-zero bytes, simply do `s.length - countZeroBytes(s)`.
function countZeroBytesCalldata(bytes calldata s) internal pure returns (uint256 c) {
/// @solidity memory-safe-assembly
assembly {
function czb(x_) -> _c {
let _m := 0x7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
_c := shr(7, not(or(or(add(and(x_, _m), _m), x_), _m)))
_c := byte(0, mul(shr(7, not(_m)), _c))
}
let l := shl(5, shr(5, s.length))
for { let i } xor(i, l) { i := add(i, 0x20) } {
c := add(czb(calldataload(add(s.offset, i))), c)
}
if lt(l, s.length) {
let m := shr(shl(3, sub(s.length, l)), not(0))
c := add(czb(or(m, calldataload(add(s.offset, l)))), c)
}
}
}
/// @dev Returns whether `x` is a power of 2.
function isPo2(uint256 x) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `x && !(x & (x - 1))`.
result := iszero(add(and(x, sub(x, 1)), iszero(x)))
}
}
/// @dev Returns `x` reversed at the bit level.
function reverseBits(uint256 x) internal pure returns (uint256 r) {
uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;
uint256 m1 = m0 ^ (m0 << 2);
uint256 m2 = m1 ^ (m1 << 1);
r = reverseBytes(x);
r = (m2 & (r >> 1)) | ((m2 & r) << 1);
r = (m1 & (r >> 2)) | ((m1 & r) << 2);
r = (m0 & (r >> 4)) | ((m0 & r) << 4);
}
/// @dev Returns `x` reversed at the byte level.
function reverseBytes(uint256 x) internal pure returns (uint256 r) {
unchecked {
// Computing masks on-the-fly reduces bytecode size by about 200 bytes.
uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == uint256(0)) >> 192);
uint256 m1 = m0 ^ (m0 << 32);
uint256 m2 = m1 ^ (m1 << 16);
uint256 m3 = m2 ^ (m2 << 8);
r = (m3 & (x >> 8)) | ((m3 & x) << 8);
r = (m2 & (r >> 16)) | ((m2 & r) << 16);
r = (m1 & (r >> 32)) | ((m1 & r) << 32);
r = (m0 & (r >> 64)) | ((m0 & r) << 64);
r = (r >> 128) | (r << 128);
}
}
/// @dev Returns the common prefix of `x` and `y` at the bit level.
function commonBitPrefix(uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
uint256 s = 256 - clz(x ^ y);
return (x >> s) << s;
}
}
/// @dev Returns the common prefix of `x` and `y` at the nibble level.
function commonNibblePrefix(uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
uint256 s = (64 - (clz(x ^ y) >> 2)) << 2;
return (x >> s) << s;
}
}
/// @dev Returns the common prefix of `x` and `y` at the byte level.
function commonBytePrefix(uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
uint256 s = (32 - (clz(x ^ y) >> 3)) << 3;
return (x >> s) << s;
}
}
/// @dev hex"ABCD" -> hex"0A0B0C0D".
function toNibbles(bytes memory s) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let n := mload(s)
mstore(result, add(n, n)) // Store the new length.
s := add(s, 0x20)
let o := add(result, 0x20)
// forgefmt: disable-next-item
for { let i := 0 } lt(i, n) { i := add(i, 0x10) } {
let x := shr(128, mload(add(s, i)))
x := and(0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff, or(shl(64, x), x))
x := and(0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff, or(shl(32, x), x))
x := and(0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff, or(shl(16, x), x))
x := and(0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff, or(shl(8, x), x))
mstore(add(o, add(i, i)),
and(0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f, or(shl(4, x), x)))
}
mstore(add(o, add(s, s)), 0) // Zeroize slot after result.
mstore(0x40, add(0x40, add(o, add(s, s)))) // Allocate memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BOOLEAN OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// A Solidity bool on the stack or memory is represented as a 256-bit word.
// Non-zero values are true, zero is false.
// A clean bool is either 0 (false) or 1 (true) under the hood.
// Usually, if not always, the bool result of a regular Solidity expression,
// or the argument of a public/external function will be a clean bool.
// You can usually use the raw variants for more performance.
// If uncertain, test (best with exact compiler settings).
// Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s).
/// @dev Returns `x & y`. Inputs must be clean.
function rawAnd(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := and(x, y)
}
}
/// @dev Returns `x & y`.
function and(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := and(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns `w & x & y`.
function and(bool w, bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(or(iszero(w), or(iszero(x), iszero(y))))
}
}
/// @dev Returns `v & w & x & y`.
function and(bool v, bool w, bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(or(or(iszero(v), iszero(w)), or(iszero(x), iszero(y))))
}
}
/// @dev Returns `x | y`. Inputs must be clean.
function rawOr(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, y)
}
}
/// @dev Returns `x | y`.
function or(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(iszero(or(x, y)))
}
}
/// @dev Returns `w | x | y`.
function or(bool w, bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(iszero(or(w, or(x, y))))
}
}
/// @dev Returns `v | w | x | y`.
function or(bool v, bool w, bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(iszero(or(v, or(w, or(x, y)))))
}
}
/// @dev Returns 1 if `b` is true, else 0. Input must be clean.
function rawToUint(bool b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := b
}
}
/// @dev Returns 1 if `b` is true, else 0.
function toUint(bool b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for byte related operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
library LibBytes {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct BytesStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the bytes.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the bytes storage `$` to `s`.
function set(BytesStorage storage $, bytes memory s) internal {
/// @solidity memory-safe-assembly
assembly {
let n := mload(s)
let packed := or(0xff, shl(8, n))
for { let i := 0 } 1 {} {
if iszero(gt(n, 0xfe)) {
i := 0x1f
packed := or(n, shl(8, mload(add(s, i))))
if iszero(gt(n, i)) { break }
}
let o := add(s, 0x20)
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), mload(add(o, i)))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to `s`.
function setCalldata(BytesStorage storage $, bytes calldata s) internal {
/// @solidity memory-safe-assembly
assembly {
let packed := or(0xff, shl(8, s.length))
for { let i := 0 } 1 {} {
if iszero(gt(s.length, 0xfe)) {
i := 0x1f
packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
if iszero(gt(s.length, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
i := add(i, 0x20)
if iszero(lt(i, s.length)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to the empty bytes.
function clear(BytesStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty bytes "".
function isEmpty(BytesStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(BytesStorage storage $) internal view returns (uint256 result) {
result = uint256($._spacer);
/// @solidity memory-safe-assembly
assembly {
let n := and(0xff, result)
result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
}
}
/// @dev Returns the value stored in `$`.
function get(BytesStorage storage $) internal view returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
let packed := sload($.slot)
let n := shr(8, packed)
for { let i := 0 } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
mstore(o, packed)
n := and(0xff, packed)
i := 0x1f
if iszero(gt(n, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
mstore(add(o, i), sload(add(p, shr(5, i))))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
mstore(result, n) // Store the length of the memory.
mstore(add(o, n), 0) // Zeroize the slot after the bytes.
mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
}
}
/// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0.
function uint8At(BytesStorage storage $, uint256 i) internal view returns (uint8 result) {
/// @solidity memory-safe-assembly
assembly {
for { let packed := sload($.slot) } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
if iszero(gt(i, 0x1e)) {
result := byte(i, packed)
break
}
if iszero(gt(i, and(0xff, packed))) {
mstore(0x00, $.slot)
let j := sub(i, 0x1f)
result := byte(and(j, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, j))))
}
break
}
if iszero(gt(i, shr(8, packed))) {
mstore(0x00, $.slot)
result := byte(and(i, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, i))))
}
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let needleLen := mload(needle)
let replacementLen := mload(replacement)
let d := sub(result, subject) // Memory difference.
let i := add(subject, 0x20) // Subject bytes pointer.
mstore(0x00, add(i, mload(subject))) // End of subject.
if iszero(gt(needleLen, mload(subject))) {
let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, needleLen), h)) {
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
j := add(j, 0x20)
if iszero(lt(j, replacementLen)) { break }
}
d := sub(add(d, replacementLen), needleLen)
if needleLen {
i := add(i, needleLen)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
}
let end := mload(0x00)
let n := add(sub(d, add(result, 0x20)), end)
// Copy the rest of the bytes one word at a time.
for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
let o := add(i, d)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
for { let subjectLen := mload(subject) } 1 {} {
if iszero(mload(needle)) {
result := from
if iszero(gt(from, subjectLen)) { break }
result := subjectLen
break
}
let needleLen := mload(needle)
let subjectStart := add(subject, 0x20)
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
let s := mload(add(needle, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }
if iszero(lt(needleLen, 0x20)) {
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, subjectStart)
break
}
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
result := sub(subject, subjectStart)
break
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`. Optimized for byte needles.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOfByte(bytes memory subject, bytes1 needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
if gt(mload(subject), from) {
let start := add(subject, 0x20)
let end := add(start, mload(subject))
let m := div(not(0), 255) // `0x0101 ... `.
let h := mul(byte(0, needle), m) // Replicating needle mask.
m := not(shl(7, m)) // `0x7f7f ... `.
for { let i := add(start, from) } 1 {} {
let c := xor(mload(i), h) // Load 32-byte chunk and xor with mask.
c := not(or(or(add(and(c, m), m), c), m)) // Each needle byte will be `0x80`.
if c {
c := and(not(shr(shl(3, sub(end, i)), not(0))), c) // Truncate bytes past the end.
if c {
let r := shl(7, lt(0x8421084210842108cc6318c6db6d54be, c)) // Save bytecode.
r := or(shl(6, lt(0xffffffffffffffff, shr(r, c))), r)
// forgefmt: disable-next-item
result := add(sub(i, start), shr(3, xor(byte(and(0x1f, shr(byte(24,
mul(0x02040810204081, shr(r, c))), 0x8421084210842108cc6318c6db6d54be)),
0xc0c8c8d0c8e8d0d8c8e8e0e8d0d8e0f0c8d0e8d0e0e0d8f0d0d0e0d8f8f8f8f8), r)))
break
}
}
i := add(i, 0x20)
if iszero(lt(i, end)) { break }
}
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right. Optimized for byte needles.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOfByte(bytes memory subject, bytes1 needle)
internal
pure
returns (uint256 result)
{
return indexOfByte(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
return indexOf(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let needleLen := mload(needle)
if gt(needleLen, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), needleLen)
if iszero(gt(fromMax, from)) { from := fromMax }
let end := add(add(subject, 0x20), w)
subject := add(add(subject, 0x20), from)
if iszero(gt(subject, end)) { break }
// As this function is not too often used,
// we shall simply use keccak256 for smaller bytecode size.
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, add(end, 1))
break
}
subject := add(subject, w) // `sub(subject, 1)`.
if iszero(gt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256)
{
return lastIndexOf(subject, needle, type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
return indexOf(subject, needle) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
// Just using keccak256 directly is actually cheaper.
let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
result := lt(gt(n, mload(subject)), t)
}
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
let notInRange := gt(n, mload(subject))
// `subject + 0x20 + max(subject.length - needle.length, 0)`.
let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
// Just using keccak256 directly is actually cheaper.
result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(bytes memory subject, uint256 times)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(or(iszero(times), iszero(l))) {
result := mload(0x40)
subject := add(subject, 0x20)
let o := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(o, j), mload(add(subject, j)))
j := add(j, 0x20)
if iszero(lt(j, l)) { break }
}
o := add(o, l)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(bytes memory subject, uint256 start, uint256 end)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(gt(l, end)) { end := l }
if iszero(gt(l, start)) { start := l }
if lt(start, end) {
result := mload(0x40)
let n := sub(end, start)
let i := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let j := and(add(n, 0x1f), w) } 1 {} {
mstore(add(result, j), mload(add(i, j)))
j := add(j, w) // `sub(j, 0x20)`.
if iszero(j) { break }
}
let o := add(add(result, 0x20), n)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset.
function slice(bytes memory subject, uint256 start)
internal
pure
returns (bytes memory result)
{
result = slice(subject, start, type(uint256).max);
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, end), sub(end, start))
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, subject.length), sub(subject.length, start))
}
}
/// @dev Reduces the size of `subject` to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncate(bytes memory subject, uint256 n)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := subject
mstore(mul(lt(n, mload(result)), result), n)
}
}
/// @dev Returns a copy of `subject`, with the length reduced to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncatedCalldata(bytes calldata subject, uint256 n)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
result.offset := subject.offset
result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
}
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLen := mload(needle)
if iszero(gt(searchLen, mload(subject))) {
result := mload(0x40)
let i := add(subject, 0x20)
let o := add(result, 0x20)
let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, searchLen), h)) {
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
o := add(o, 0x20)
i := add(i, searchLen) // Advance `i` by `searchLen`.
if searchLen {
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(o, 0x20))
}
}
}
/// @dev Returns an arrays of bytess based on the `delimiter` inside of the `subject` bytes.
function split(bytes memory subject, bytes memory delimiter)
internal
pure
returns (bytes[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
let indexPtr := add(indices, 0x20)
let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
for { let prevIndex := 0 } 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let l := sub(index, prevIndex)
mstore(element, l) // Store the length of the element.
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(l, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
// Allocate memory for the length and the bytes, rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(l, 0x3f), w)))
mstore(indexPtr, element) // Store the `element` into the array.
}
prevIndex := add(index, mload(delimiter))
indexPtr := add(indexPtr, 0x20)
if iszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
if iszero(mload(delimiter)) {
result := add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
/// @dev Returns a concatenated bytes of `a` and `b`.
/// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let w := not(0x1f)
let aLen := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLen, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLen := mload(b)
let output := add(result, aLen)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLen, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLen := add(aLen, bLen)
let last := add(add(result, 0x20), totalLen)
mstore(last, 0) // Zeroize the slot after the bytes.
mstore(result, totalLen) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(bytes memory a, bytes memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes.
function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) {
/// @solidity memory-safe-assembly
assembly {
let aLen := mload(a)
let bLen := mload(b)
let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f))
if n {
for { let i := 0x20 } 1 {} {
let x := mload(add(a, i))
let y := mload(add(b, i))
if iszero(or(xor(x, y), eq(i, n))) {
i := add(i, 0x20)
continue
}
result := sub(gt(x, y), lt(x, y))
break
}
}
// forgefmt: disable-next-item
if iszero(result) {
let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0)))
let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0)))
result := sub(gt(x, y), lt(x, y))
if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) }
}
}
}
/// @dev Directly returns `a` without copying.
function directReturn(bytes memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the bytes does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the bytes is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the bytes.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
/// @dev Directly returns `a` with minimal copying.
function directReturn(bytes[] memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(a) // `a.length`.
let o := add(a, 0x20) // Start of elements in `a`.
let u := a // Highest memory slot.
let w := not(0x1f)
for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
let s := mload(c) // `a[i]`.
let l := mload(s) // `a[i].length`.
let r := and(l, 0x1f) // `a[i].length % 32`.
let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
// If `s` comes before `o`, or `s` is not zero right padded.
if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
let m := mload(0x40)
mstore(m, l) // Copy `a[i].length`.
for {} 1 {} {
mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
z := add(z, w) // `sub(z, 0x20)`.
if iszero(z) { break }
}
let e := add(add(m, 0x20), l)
mstore(e, 0) // Zeroize the slot after the copied bytes.
mstore(0x40, add(e, 0x20)) // Allocate memory.
s := m
}
mstore(c, sub(s, o)) // Convert to calldata offset.
let t := add(l, add(s, 0x20))
if iszero(lt(t, u)) { u := t }
}
let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
mstore(retStart, 0x20) // Store the return offset.
return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(add(add(a, 0x20), offset))
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
function loadCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
result := calldataload(add(a.offset, offset))
}
}
/// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks.
function staticStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
result.offset := add(a.offset, offset)
result.length := sub(a.length, offset)
if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks.
function dynamicStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(a.offset, s)
result.length := sub(a.length, s)
if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns bytes in calldata. Performs bounds checks.
function bytesInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(add(a.offset, s), 0x20)
result.length := calldataload(add(a.offset, s))
// forgefmt: disable-next-item
if or(shr(64, or(result.length, or(s, or(l, a.offset)))),
or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) }
}
}
/// @dev Checks if `x` is in `a`. Assumes `a` has been checked.
function checkInCalldata(bytes calldata x, bytes calldata a) internal pure {
/// @solidity memory-safe-assembly
assembly {
if or(
or(lt(x.offset, a.offset), gt(add(x.offset, x.length), add(a.length, a.offset))),
shr(64, or(x.length, x.offset))
) { revert(0x00, 0x00) }
}
}
/// @dev Checks if `x` is in `a`. Assumes `a` has been checked.
function checkInCalldata(bytes[] calldata x, bytes calldata a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let e := sub(add(a.length, a.offset), 0x20)
if or(lt(x.offset, a.offset), shr(64, x.offset)) { revert(0x00, 0x00) }
for { let i := 0 } iszero(eq(x.length, i)) { i := add(i, 1) } {
let o := calldataload(add(x.offset, shl(5, i)))
let t := add(o, x.offset)
let l := calldataload(t)
if or(shr(64, or(l, o)), gt(add(t, l), e)) { revert(0x00, 0x00) }
}
}
}
/// @dev Returns empty calldata bytes. For silencing the compiler.
function emptyCalldata() internal pure returns (bytes calldata result) {
/// @solidity memory-safe-assembly
assembly {
result.length := 0
}
}
/// @dev Returns the most significant 20 bytes as an address.
function msbToAddress(bytes32 x) internal pure returns (address) {
return address(bytes20(x));
}
/// @dev Returns the least significant 20 bytes as an address.
function lsbToAddress(bytes32 x) internal pure returns (address) {
return address(uint160(uint256(x)));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for basic storage operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibStorage.sol)
library LibStorage {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The storage slot seed for calculating a bumped storage slot.
/// `bytes4(keccak256("_BUMPED_STORAGE_REF_SLOT_SEED"))`.
uint256 private constant _BUMPED_STORAGE_REF_SLOT_SEED = 0xd4203f8b;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Generates a storage slot that can be invalidated.
struct Bump {
uint256 _current;
}
/// @dev Pointer struct to a `uint256` in storage.
/// We have opted for a `uint256` as the inner type,
/// as it requires less casting to get / set specific bits.
struct Ref {
uint256 value;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the current storage slot pointed by the bump.
/// Use inline-assembly to cast the result to a desired custom data type storage pointer.
function slot(Bump storage b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x1f, sload(b.slot))
mstore(0x04, _BUMPED_STORAGE_REF_SLOT_SEED)
mstore(0x00, b.slot)
result := keccak256(0x00, 0x3f)
}
}
/// @dev Makes the bump point to a whole new storage slot.
function invalidate(Bump storage b) internal {
unchecked {
++b._current;
}
}
/// @dev Returns a bump at the storage slot.
function bump(bytes32 sSlot) internal pure returns (Bump storage $) {
/// @solidity memory-safe-assembly
assembly {
$.slot := sSlot
}
}
/// @dev Returns a bump at the storage slot.
function bump(uint256 sSlot) internal pure returns (Bump storage $) {
/// @solidity memory-safe-assembly
assembly {
$.slot := sSlot
}
}
/// @dev Returns a pointer to a `uint256` in storage.
function ref(bytes32 sSlot) internal pure returns (Ref storage $) {
/// @solidity memory-safe-assembly
assembly {
$.slot := sSlot
}
}
/// @dev Returns a pointer to a `uint256` in storage.
function ref(uint256 sSlot) internal pure returns (Ref storage $) {
/// @solidity memory-safe-assembly
assembly {
$.slot := sSlot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Call context checker mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/CallContextChecker.sol)
contract CallContextChecker {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The call is from an unauthorized call context.
error UnauthorizedCallContext();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* IMMUTABLES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev For checking if the context is a delegate call.
///
/// Note: To enable use cases with an immutable default implementation in the bytecode,
/// (see: ERC6551Proxy), we don't require that the proxy address must match the
/// value stored in the implementation slot, which may not be initialized.
uint256 private immutable __self = uint256(uint160(address(this)));
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CALL CONTEXT CHECKS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// A proxy call can be either via a `delegatecall` to an implementation,
// or a 7702 call on an authority that points to a delegation.
/// @dev Returns whether the current call context is on a EIP7702 authority
/// (i.e. externally owned account).
function _onEIP7702Authority() internal view virtual returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
extcodecopy(address(), 0x00, 0x00, 0x20)
// Note: Checking that it starts with hex"ef01" is the most general and futureproof.
// 7702 bytecode is `abi.encodePacked(hex"ef01", uint8(version), address(delegation))`.
result := eq(0xef01, shr(240, mload(0x00)))
}
}
/// @dev Returns the implementation of this contract.
function _selfImplementation() internal view virtual returns (address) {
return address(uint160(__self));
}
/// @dev Returns whether the current call context is on the implementation itself.
function _onImplementation() internal view virtual returns (bool) {
return __self == uint160(address(this));
}
/// @dev Requires that the current call context is performed via a EIP7702 authority.
function _checkOnlyEIP7702Authority() internal view virtual {
if (!_onEIP7702Authority()) _revertUnauthorizedCallContext();
}
/// @dev Requires that the current call context is performed via a proxy.
function _checkOnlyProxy() internal view virtual {
if (_onImplementation()) _revertUnauthorizedCallContext();
}
/// @dev Requires that the current call context is NOT performed via a proxy.
/// This is the opposite of `checkOnlyProxy`.
function _checkNotDelegated() internal view virtual {
if (!_onImplementation()) _revertUnauthorizedCallContext();
}
/// @dev Requires that the current call context is performed via a EIP7702 authority.
modifier onlyEIP7702Authority() virtual {
_checkOnlyEIP7702Authority();
_;
}
/// @dev Requires that the current call context is performed via a proxy.
modifier onlyProxy() virtual {
_checkOnlyProxy();
_;
}
/// @dev Requires that the current call context is NOT performed via a proxy.
/// This is the opposite of `onlyProxy`.
modifier notDelegated() virtual {
_checkNotDelegated();
_;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
function _revertUnauthorizedCallContext() private pure {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`.
revert(0x1c, 0x04)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if gt(x, div(not(0), y)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if iszero(eq(div(z, y), x)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := add(iszero(iszero(mod(z, WAD))), div(z, WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(mul(y, eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
/// Note: This function is an approximation.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
/// Note: This function is an approximation. Monotonically increasing.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
(int256 wad, int256 p) = (int256(WAD), x);
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (uint256(w >> 63) == uint256(0)) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == uint256(0)) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != uint256(0));
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c == uint256(0)) return w;
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `a * b == x * y`, with full precision.
function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0))))
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Temporarily use `z` as `p0` to save gas.
z := mul(x, y) // Lower 256 bits of `x * y`.
for {} 1 {} {
// If overflows.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
let r := mulmod(x, y, d) // Compute remainder using mulmod.
let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`.
// Make sure `z` is less than `2**256`. Also prevents `d == 0`.
// Placing the check here seems to give more optimal stack operations.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
d := div(d, t) // Divide `d` by `t`, which is a power of two.
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use 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.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
z :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256
)
break
}
z := div(z, d)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits.
/// Performs the full 512 bit calculation regardless.
function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z)))
let t := and(d, sub(0, d))
let r := mulmod(x, y, d)
d := div(d, t)
let inv := xor(2, mul(3, d))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
z :=
mul(
or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
mul(sub(2, mul(d, inv)), inv)
)
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
z = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
z := add(z, 1)
if iszero(z) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Calculates `floor(x * y / 2 ** n)` with full precision.
/// Throws if result overflows a uint256.
/// Credit to Philogy under MIT license:
/// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol
function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Temporarily use `z` as `p0` to save gas.
z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`.
for {} 1 {} {
if iszero(or(iszero(x), eq(div(z, x), y))) {
let k := and(n, 0xff) // `n`, cleaned.
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
// | p1 | z |
// Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 |
// Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 |
// Check that final `z` doesn't overflow by checking that p1_0 = 0.
if iszero(shr(k, p1)) {
z := add(shl(sub(256, k), p1), shr(k, z))
break
}
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
z := shr(and(n, 0xff), z)
break
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(z, d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(z, d))), div(z, d))
}
}
/// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`.
function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) {
/// @solidity memory-safe-assembly
assembly {
let g := n
let r := mod(a, n)
for { let y := 1 } 1 {} {
let q := div(g, r)
let t := g
g := r
r := sub(t, mul(r, q))
let u := x
x := y
y := sub(u, mul(y, q))
if iszero(r) { break }
}
x := mul(eq(g, 1), add(x, mul(slt(x, 0), n)))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`. Alias for `saturatingSub`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Returns `max(0, x - y)`.
function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Returns `min(2 ** 256 - 1, x + y)`.
function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(sub(0, lt(add(x, y), x)), add(x, y))
}
}
/// @dev Returns `min(2 ** 256 - 1, x * y)`.
function saturatingMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(sub(or(iszero(x), eq(div(mul(x, y), x), y)), 1), mul(x, y))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, address x, address y) internal pure returns (address z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `x != 0 ? x : y`, without branching.
function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(x)))
}
}
/// @dev Returns `x != bytes32(0) ? x : y`, without branching.
function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(x)))
}
}
/// @dev Returns `x != address(0) ? x : y`, without branching.
function coalesce(address x, address y) internal pure returns (address z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(shl(96, x))))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if x {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`, rounded down.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`, rounded down.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/snekmate/utils/math.vy
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// Makeshift lookup table to nudge the approximate log2 result.
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
// Newton-Raphson's.
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
// Round down.
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`, rounded down.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18);
z = (1 + sqrt(x)) * 10 ** 9;
z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1;
}
/// @solidity memory-safe-assembly
assembly {
z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down.
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down.
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36);
z = (1 + cbrt(x)) * 10 ** 12;
z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3;
}
/// @solidity memory-safe-assembly
assembly {
let p := x
for {} 1 {} {
if iszero(shr(229, p)) {
if iszero(shr(199, p)) {
p := mul(p, 100000000000000000) // 10 ** 17.
break
}
p := mul(p, 100000000) // 10 ** 8.
break
}
if iszero(shr(249, p)) { p := mul(p, 100) }
break
}
let t := mulmod(mul(z, z), z, p)
z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down.
}
}
/// @dev Returns `sqrt(x * y)`. Also called the geometric mean.
function mulSqrt(uint256 x, uint256 y) internal pure returns (uint256 z) {
if (x == y) return x;
uint256 p = rawMul(x, y);
if (y == rawDiv(p, x)) return sqrt(p);
for (z = saturatingMul(rawAdd(sqrt(x), 1), rawAdd(sqrt(y), 1));; z = avg(z, p)) {
if ((p = fullMulDivUnchecked(x, y, z)) >= z) break;
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := 1
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for {} x { x := sub(x, 1) } { z := mul(z, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards zero.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards negative infinity.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
unchecked {
z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255);
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`,
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end)
internal
pure
returns (uint256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
unchecked {
if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin);
return a - fullMulDiv(a - b, t - begin, end - begin);
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`.
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end)
internal
pure
returns (int256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
// forgefmt: disable-next-item
unchecked {
if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a),
uint256(t - begin), uint256(end - begin)));
return int256(uint256(a) - fullMulDiv(uint256(a - b),
uint256(t - begin), uint256(end - begin)));
}
}
/// @dev Returns if `x` is an even number. Some people may need this.
function isEven(uint256 x) internal pure returns (bool) {
return x & uint256(1) == uint256(0);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
/// @title TokenTransferLib
/// @notice A library to handle token transfers.
library TokenTransferLib {
////////////////////////////////////////////////////////////////////////
// Operations
////////////////////////////////////////////////////////////////////////
/// @dev ERC20 or native token balance query.
/// If `token` is `address(0)`, it is treated as a native token balance query.
function balanceOf(address token, address owner) internal view returns (uint256) {
if (token == address(0)) return owner.balance;
return SafeTransferLib.balanceOf(token, owner);
}
/// @dev ERC20 or native token transfer function.
/// If `token` is `address(0)`, it is treated as a native token transfer.
function safeTransfer(address token, address to, uint256 amount) internal {
if (token == address(0)) {
SafeTransferLib.safeTransferETH(to, amount);
} else {
SafeTransferLib.safeTransfer(token, to, amount);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/// @dev The ERC20 `totalSupply` query has failed.
error TotalSupplyQueryFailed();
/// @dev The Permit2 operation has failed.
error Permit2Failed();
/// @dev The Permit2 amount must be less than `2**160 - 1`.
error Permit2AmountOverflow();
/// @dev The Permit2 approve operation has failed.
error Permit2ApproveFailed();
/// @dev The Permit2 lockdown operation has failed.
error Permit2LockdownFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/// @dev The unique EIP-712 domain separator for the DAI token contract.
bytes32 internal constant DAI_DOMAIN_SEPARATOR =
0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;
/// @dev The address for the WETH9 contract on Ethereum mainnet.
address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
/// @dev The canonical Permit2 address.
/// [Github](https://github.com/Uniswap/permit2)
/// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
/// @dev The canonical address of the `SELFDESTRUCT` ETH mover.
/// See: https://gist.github.com/Vectorized/1cb8ad4cf393b1378e08f23f79bd99fa
/// [Etherscan](https://etherscan.io/address/0x00000000000073c48c8055bD43D1A53799176f0D)
address internal constant ETH_MOVER = 0x00000000000073c48c8055bD43D1A53799176f0D;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// forgefmt: disable-next-item
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Force transfers ETH to `to`, without triggering the fallback (if any).
/// This method attempts to use a separate contract to send via `SELFDESTRUCT`,
/// and upon failure, deploys a minimal vault to accrue the ETH.
function safeMoveETH(address to, uint256 amount) internal returns (address vault) {
/// @solidity memory-safe-assembly
assembly {
to := shr(96, shl(96, to)) // Clean upper 96 bits.
for { let mover := ETH_MOVER } iszero(eq(to, address())) {} {
let selfBalanceBefore := selfbalance()
if or(lt(selfBalanceBefore, amount), eq(to, mover)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if extcodesize(mover) {
let balanceBefore := balance(to) // Check via delta, in case `SELFDESTRUCT` is bricked.
mstore(0x00, to)
pop(call(gas(), mover, amount, 0x00, 0x20, codesize(), 0x00))
// If `address(to).balance >= amount + balanceBefore`, skip vault workflow.
if iszero(lt(balance(to), add(amount, balanceBefore))) { break }
// Just in case `SELFDESTRUCT` is changed to not revert and do nothing.
if lt(selfBalanceBefore, selfbalance()) { invalid() }
}
let m := mload(0x40)
// If the mover is missing or bricked, deploy a minimal vault
// that withdraws all ETH to `to` when being called only by `to`.
// forgefmt: disable-next-item
mstore(add(m, 0x20), 0x33146025575b600160005260206000f35b3d3d3d3d47335af1601a5760003dfd)
mstore(m, or(to, shl(160, 0x6035600b3d3960353df3fe73)))
// Compute and store the bytecode hash.
mstore8(0x00, 0xff) // Write the prefix.
mstore(0x35, keccak256(m, 0x40))
mstore(0x01, shl(96, address())) // Deployer.
mstore(0x15, 0) // Salt.
vault := keccak256(0x00, 0x55)
pop(call(gas(), vault, amount, codesize(), 0x00, codesize(), 0x00))
// The vault returns a single word on success. Failure reverts with empty data.
if iszero(returndatasize()) {
if iszero(create2(0, m, 0x40, 0)) { revert(codesize(), codesize()) } // For gas estimation.
}
mstore(0x40, m) // Restore the free memory pointer.
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
///
/// The `from` account must have at least `amount` approved for the current contract to manage.
function trySafeTransferFrom(address token, address from, address to, uint256 amount)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
success := lt(or(iszero(extcodesize(token)), returndatasize()), success)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
// Check the `extcodesize` again just in case the token selfdestructs lol.
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul( // The arguments of `mul` are evaluated from right to left.
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
/// @dev Performs a `token.balanceOf(account)` check.
/// `implemented` denotes whether the `token` does not implement `balanceOf`.
/// `amount` is zero if the `token` does not implement `balanceOf`.
function checkBalanceOf(address token, address account)
internal
view
returns (bool implemented, uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
implemented :=
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
amount := mul(mload(0x20), implemented)
}
}
/// @dev Returns the total supply of the `token`.
/// Reverts if the token does not exist or does not implement `totalSupply()`.
function totalSupply(address token) internal view returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x18160ddd) // `totalSupply()`.
if iszero(
and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20))
) {
mstore(0x00, 0x54cd9435) // `TotalSupplyQueryFailed()`.
revert(0x1c, 0x04)
}
result := mload(0x00)
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// If the initial attempt fails, try to use Permit2 to transfer the token.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for the current contract to manage.
function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
if (!trySafeTransferFrom(token, from, to, amount)) {
permit2TransferFrom(token, from, to, amount);
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
/// Reverts upon failure.
function permit2TransferFrom(address token, address from, address to, uint256 amount)
internal
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(add(m, 0x74), shr(96, shl(96, token)))
mstore(add(m, 0x54), amount)
mstore(add(m, 0x34), to)
mstore(add(m, 0x20), shl(96, from))
// `transferFrom(address,address,uint160,address)`.
mstore(m, 0x36c78516000000000000000000000000)
let p := PERMIT2
let exists := eq(chainid(), 1)
if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
if iszero(
and(
call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00),
lt(iszero(extcodesize(token)), exists) // Token has code and Permit2 exists.
)
) {
mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
}
}
}
/// @dev Permit a user to spend a given amount of
/// another user's tokens via native EIP-2612 permit if possible, falling
/// back to Permit2 if native permit fails or is not implemented on the token.
function permit2(
address token,
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
for {} shl(96, xor(token, WETH9)) {} {
mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
// Gas stipend to limit gas burn for tokens that don't refund gas when
// an non-existing function is called. 5K should be enough for a SLOAD.
staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
)
) { break }
// After here, we can be sure that token is a contract.
let m := mload(0x40)
mstore(add(m, 0x34), spender)
mstore(add(m, 0x20), shl(96, owner))
mstore(add(m, 0x74), deadline)
if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
mstore(0x14, owner)
mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
mstore(
add(m, 0x94),
lt(iszero(amount), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
)
mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
// `nonces` is already at `add(m, 0x54)`.
// `amount != 0` is already stored at `add(m, 0x94)`.
mstore(add(m, 0xb4), and(0xff, v))
mstore(add(m, 0xd4), r)
mstore(add(m, 0xf4), s)
success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
break
}
mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
mstore(add(m, 0x54), amount)
mstore(add(m, 0x94), and(0xff, v))
mstore(add(m, 0xb4), r)
mstore(add(m, 0xd4), s)
success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
break
}
}
if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
}
/// @dev Simple permit on the Permit2 contract.
function simplePermit2(
address token,
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, 0x927da105) // `allowance(address,address,address)`.
{
let addressMask := shr(96, not(0))
mstore(add(m, 0x20), and(addressMask, owner))
mstore(add(m, 0x40), and(addressMask, token))
mstore(add(m, 0x60), and(addressMask, spender))
mstore(add(m, 0xc0), and(addressMask, spender))
}
let p := mul(PERMIT2, iszero(shr(160, amount)))
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
)
) {
mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
revert(add(0x18, shl(2, iszero(p))), 0x04)
}
mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
// `owner` is already `add(m, 0x20)`.
// `token` is already at `add(m, 0x40)`.
mstore(add(m, 0x60), amount)
mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
// `nonce` is already at `add(m, 0xa0)`.
// `spender` is already at `add(m, 0xc0)`.
mstore(add(m, 0xe0), deadline)
mstore(add(m, 0x100), 0x100) // `signature` offset.
mstore(add(m, 0x120), 0x41) // `signature` length.
mstore(add(m, 0x140), r)
mstore(add(m, 0x160), s)
mstore(add(m, 0x180), shl(248, v))
if iszero( // Revert if token does not have code, or if the call fails.
mul(extcodesize(token), call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00))) {
mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Approves `spender` to spend `amount` of `token` for `address(this)`.
function permit2Approve(address token, address spender, uint160 amount, uint48 expiration)
internal
{
/// @solidity memory-safe-assembly
assembly {
let addressMask := shr(96, not(0))
let m := mload(0x40)
mstore(m, 0x87517c45) // `approve(address,address,uint160,uint48)`.
mstore(add(m, 0x20), and(addressMask, token))
mstore(add(m, 0x40), and(addressMask, spender))
mstore(add(m, 0x60), and(addressMask, amount))
mstore(add(m, 0x80), and(0xffffffffffff, expiration))
if iszero(call(gas(), PERMIT2, 0, add(m, 0x1c), 0xa0, codesize(), 0x00)) {
mstore(0x00, 0x324f14ae) // `Permit2ApproveFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Revokes an approval for `token` and `spender` for `address(this)`.
function permit2Lockdown(address token, address spender) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, 0xcc53287f) // `Permit2.lockdown`.
mstore(add(m, 0x20), 0x20) // Offset of the `approvals`.
mstore(add(m, 0x40), 1) // `approvals.length`.
mstore(add(m, 0x60), shr(96, shl(96, token)))
mstore(add(m, 0x80), shr(96, shl(96, spender)))
if iszero(call(gas(), PERMIT2, 0, add(m, 0x1c), 0xa0, codesize(), 0x00)) {
mstore(0x00, 0x96b3de23) // `Permit2LockdownFailed()`.
revert(0x1c, 0x04)
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {ICommon} from "../interfaces/ICommon.sol";
/// @title IIthacaAccount
/// @notice Interface for the Account contract
interface IIthacaAccount is ICommon {
/// @dev Pays `paymentAmount` of `paymentToken` to the `paymentRecipient`.
/// @param keyHash The hash of the key used to authorize the operation
/// @param encodedIntent The encoded user operation
/// @param intentDigest The digest of the user operation
function pay(
uint256 paymentAmount,
bytes32 keyHash,
bytes32 intentDigest,
bytes calldata encodedIntent
) external;
/// @dev Returns if the signature is valid, along with its `keyHash`.
/// The `signature` is a wrapped signature, given by
/// `abi.encodePacked(bytes(innerSignature), bytes32(keyHash), bool(prehash))`.
function unwrapAndValidateSignature(bytes32 digest, bytes calldata signature)
external
view
returns (bool isValid, bytes32 keyHash);
/// @dev Return current nonce with sequence key.
function getNonce(uint192 seqKey) external view returns (uint256 nonce);
/// @dev Return the key hash that signed the latest execution context.
/// @dev Returns bytes32(0) if the EOA key was used.
function getContextKeyHash() external view returns (bytes32);
/// @dev Check and increment the nonce.
function checkAndIncrementNonce(uint256 nonce) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {ICommon} from "../interfaces/ICommon.sol";
/// @title IOrchestrator
/// @notice Interface for the Orchestrator contract
interface IOrchestrator is ICommon {
/// @dev Executes a single encoded intent.
/// @param encodedIntent The encoded intent
/// @return err The error selector (non-zero if there is an error)
function execute(bytes calldata encodedIntent) external payable returns (bytes4 err);
/// @dev Executes an array of encoded intents.
/// @param encodedIntents Array of encoded intents
/// @return errs Array of error selectors (non-zero if there are errors)
function execute(bytes[] calldata encodedIntents)
external
payable
returns (bytes4[] memory errs);
/// @dev Minimal function, to allow hooking into the _execute function with the simulation flags set to true.
/// When simulationFlags is set to true, all errors are bubbled up. Also signature verification always returns true.
/// But the codepaths for signature verification are still hit, for correct gas measurement.
/// @dev If `isStateOverride` is false, then this function will always revert. If the simulation is successful, then it reverts with `SimulationPassed` error.
/// If `isStateOverride` is true, then this function will not revert if the simulation is successful.
/// But the balance of tx.origin has to be greater than or equal to uint192.max, to prove that a state override has been made offchain,
/// and this is not an onchain call. This mode has been added so that receipt logs can be generated for `eth_simulateV1`
/// @return gasUsed The amount of gas used by the execution. (Only returned if `isStateOverride` is true)
function simulateExecute(
bool isStateOverride,
uint256 combinedGasOverride,
bytes calldata encodedIntent
) external payable returns (uint256 gasUsed);
/// @dev Allows the orchestrator owner to withdraw tokens.
/// @param token The token address (0 for native token)
/// @param recipient The recipient address
/// @param amount The amount to withdraw
function withdrawTokens(address token, address recipient, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
interface ICommon {
////////////////////////////////////////////////////////////////////////
// Data Structures
////////////////////////////////////////////////////////////////////////
/// @dev A struct to hold the intent fields.
/// Since L2s already include calldata compression with savings forwarded to users,
/// we don't need to be too concerned about calldata overhead
struct Intent {
////////////////////////////////////////////////////////////////////////
// EIP-712 Fields
////////////////////////////////////////////////////////////////////////
/// @dev The user's address.
address eoa;
/// @dev An encoded array of calls, using ERC7579 batch execution encoding.
/// `abi.encode(calls)`, where `calls` is of type `Call[]`.
/// This allows for more efficient safe forwarding to the EOA.
bytes executionData;
/// @dev Per delegated EOA.
/// This nonce is a 4337-style 2D nonce with some specializations:
/// - Upper 192 bits are used for the `seqKey` (sequence key).
/// The upper 16 bits of the `seqKey` is `MULTICHAIN_NONCE_PREFIX`,
/// then the Intent EIP712 hash will exclude the chain ID.
/// - Lower 64 bits are used for the sequential nonce corresponding to the `seqKey`.
uint256 nonce;
/// @dev The account paying the payment token.
/// If this is `address(0)`, it defaults to the `eoa`.
address payer;
/// @dev The ERC20 or native token used to pay for gas.
address paymentToken;
/// @dev The maximum amount of the token to pay.
uint256 paymentMaxAmount;
/// @dev The combined gas limit for payment, verification, and calling the EOA.
uint256 combinedGas;
/// @dev Optional array of encoded SignedCalls that will be verified and executed
/// before the validation of the overall Intent.
/// A PreCall will NOT have its gas limit or payment applied.
/// The overall Intent's gas limit and payment will be applied, encompassing all its PreCalls.
/// The execution of a PreCall will check and increment the nonce in the PreCall.
/// If at any point, any PreCall cannot be verified to be correct, or fails in execution,
/// the overall Intent will revert before validation, and execute will return a non-zero error.
bytes[] encodedPreCalls;
/// @dev Only relevant for multi chain intents.
/// There should not be any duplicate token addresses. Use address(0) for native token.
/// If native token is used, the first transfer should be the native token transfer.
/// If encodedFundTransfers is not empty, then the intent is considered the output intent.
bytes[] encodedFundTransfers;
/// @dev The settler address.
address settler;
/// @dev The expiry timestamp for the intent. The intent is invalid after this timestamp.
/// If expiry timestamp is set to 0, then expiry is considered to be infinite.
uint256 expiry;
////////////////////////////////////////////////////////////////////////
// Additional Fields (Not included in EIP-712)
////////////////////////////////////////////////////////////////////////
/// @dev Whether the intent should use the multichain mode - i.e verify with merkle sigs
/// and send the cross chain message.
bool isMultichain;
/// @dev The funder address.
address funder;
/// @dev The funder signature.
bytes funderSignature;
/// @dev The settler context data to be passed to the settler.
bytes settlerContext;
/// @dev The actual payment amount, requested by the filler. MUST be less than or equal to `paymentMaxAmount`
uint256 paymentAmount;
/// @dev The payment recipient for the ERC20 token.
/// Excluded from signature. The filler can replace this with their own address.
/// This enables multiple fillers, allowing for competitive filling, better uptime.
address paymentRecipient;
/// @dev The wrapped signature.
/// `abi.encodePacked(innerSignature, keyHash, prehash)`.
bytes signature;
/// @dev Optional payment signature to be passed into the `compensate` function
/// on the `payer`. This signature is NOT included in the EIP712 signature.
bytes paymentSignature;
/// @dev Optional. If non-zero, the EOA must use `supportedAccountImplementation`.
/// Otherwise, if left as `address(0)`, any EOA implementation will be supported.
/// This field is NOT included in the EIP712 signature.
address supportedAccountImplementation;
}
/// @dev A struct to hold the fields for a SignedCall.
/// A SignedCall is a struct that contains a signed execution batch along with the nonce
// and address of the user.
struct SignedCall {
/// @dev The user's address.
/// This can be set to `address(0)`, which allows it to be
/// coalesced to the parent Intent's EOA.
address eoa;
/// @dev An encoded array of calls, using ERC7579 batch execution encoding.
/// `abi.encode(calls)`, where `calls` is of type `Call[]`.
/// This allows for more efficient safe forwarding to the EOA.
bytes executionData;
/// @dev Per delegated EOA. Same logic as the `nonce` in Intent.
uint256 nonce;
/// @dev The wrapped signature.
/// `abi.encodePacked(innerSignature, keyHash, prehash)`.
bytes signature;
}
struct Transfer {
address token;
uint256 amount;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ICommon} from "./ICommon.sol";
interface IFunderV4 {
/// @dev Should fund the account with the given transfers, after verifying the signature.
function fund(
address account,
bytes32 digest,
ICommon.Transfer[] memory transfers,
bytes memory funderSignature
) external;
}
interface IFunder is IFunderV4 {
/// @dev Checks if fund transfers are valid given a funderSignature.
/// @dev Funder implementations must revert if the signature is invalid.
function fund(bytes32 digest, ICommon.Transfer[] memory transfers, bytes memory funderSignature)
external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
interface ISettler {
/// @dev Allows anyone to attest to any settlementId, on all the input chains.
/// Input chain readers can choose which attestations they want to trust.
/// @param settlementId The ID of the settlement to attest to
/// @param settlerContext Encoded context data that the settler can decode (e.g., array of input chains)
function send(bytes32 settlementId, bytes calldata settlerContext) external payable;
/// @dev Check if an attester from a particular output chain, has attested to the settlementId.
/// For our case, the attester is the orchestrator.
/// And the settlementId, is the root of the merkle tree which is signed by the user.
function read(bytes32 settlementId, address attester, uint256 chainId)
external
view
returns (bool isSettled);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)
library MerkleProofLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MERKLE PROOF VERIFICATION OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf)
internal
pure
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
if mload(proof) {
// Initialize `offset` to the offset of `proof` elements in memory.
let offset := add(proof, 0x20)
// Left shift by 5 is equivalent to multiplying by 0x20.
let end := add(offset, shl(5, mload(proof)))
// Iterate over proof elements to compute root hash.
for {} 1 {} {
// Slot of `leaf` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(leaf, mload(offset)))
// Store elements to hash contiguously in scratch space.
// Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
mstore(scratch, leaf)
mstore(xor(scratch, 0x20), mload(offset))
// Reuse `leaf` to store the hash to reduce stack operations.
leaf := keccak256(0x00, 0x40)
offset := add(offset, 0x20)
if iszero(lt(offset, end)) { break }
}
}
isValid := eq(leaf, root)
}
}
/// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf)
internal
pure
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
if proof.length {
// Left shift by 5 is equivalent to multiplying by 0x20.
let end := add(proof.offset, shl(5, proof.length))
// Initialize `offset` to the offset of `proof` in the calldata.
let offset := proof.offset
// Iterate over proof elements to compute root hash.
for {} 1 {} {
// Slot of `leaf` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(leaf, calldataload(offset)))
// Store elements to hash contiguously in scratch space.
// Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
mstore(scratch, leaf)
mstore(xor(scratch, 0x20), calldataload(offset))
// Reuse `leaf` to store the hash to reduce stack operations.
leaf := keccak256(0x00, 0x40)
offset := add(offset, 0x20)
if iszero(lt(offset, end)) { break }
}
}
isValid := eq(leaf, root)
}
}
/// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
/// given `proof` and `flags`.
///
/// Note:
/// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
/// will always return false.
/// - The sum of the lengths of `proof` and `leaves` must never overflow.
/// - Any non-zero word in the `flags` array is treated as true.
/// - The memory offset of `proof` must be non-zero
/// (i.e. `proof` is not pointing to the scratch space).
function verifyMultiProof(
bytes32[] memory proof,
bytes32 root,
bytes32[] memory leaves,
bool[] memory flags
) internal pure returns (bool isValid) {
// Rebuilds the root by consuming and producing values on a queue.
// The queue starts with the `leaves` array, and goes into a `hashes` array.
// After the process, the last element on the queue is verified
// to be equal to the `root`.
//
// The `flags` array denotes whether the sibling
// should be popped from the queue (`flag == true`), or
// should be popped from the `proof` (`flag == false`).
/// @solidity memory-safe-assembly
assembly {
// Cache the lengths of the arrays.
let leavesLength := mload(leaves)
let proofLength := mload(proof)
let flagsLength := mload(flags)
// Advance the pointers of the arrays to point to the data.
leaves := add(0x20, leaves)
proof := add(0x20, proof)
flags := add(0x20, flags)
// If the number of flags is correct.
for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} {
// For the case where `proof.length + leaves.length == 1`.
if iszero(flagsLength) {
// `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root)
break
}
// The required final proof offset if `flagsLength` is not zero, otherwise zero.
let proofEnd := add(proof, shl(5, proofLength))
// We can use the free memory space for the queue.
// We don't need to allocate, since the queue is temporary.
let hashesFront := mload(0x40)
// Copy the leaves into the hashes.
// Sometimes, a little memory expansion costs less than branching.
// Should cost less, even with a high free memory offset of 0x7d00.
leavesLength := shl(5, leavesLength)
for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } {
mstore(add(hashesFront, i), mload(add(leaves, i)))
}
// Compute the back of the hashes.
let hashesBack := add(hashesFront, leavesLength)
// This is the end of the memory for the queue.
// We recycle `flagsLength` to save on stack variables (sometimes save gas).
flagsLength := add(hashesBack, shl(5, flagsLength))
for {} 1 {} {
// Pop from `hashes`.
let a := mload(hashesFront)
// Pop from `hashes`.
let b := mload(add(hashesFront, 0x20))
hashesFront := add(hashesFront, 0x40)
// If the flag is false, load the next proof,
// else, pops from the queue.
if iszero(mload(flags)) {
// Loads the next proof.
b := mload(proof)
proof := add(proof, 0x20)
// Unpop from `hashes`.
hashesFront := sub(hashesFront, 0x20)
}
// Advance to the next flag.
flags := add(flags, 0x20)
// Slot of `a` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(a, b))
// Hash the scratch space and push the result onto the queue.
mstore(scratch, a)
mstore(xor(scratch, 0x20), b)
mstore(hashesBack, keccak256(0x00, 0x40))
hashesBack := add(hashesBack, 0x20)
if iszero(lt(hashesBack, flagsLength)) { break }
}
isValid :=
and(
// Checks if the last value in the queue is same as the root.
eq(mload(sub(hashesBack, 0x20)), root),
// And whether all the proofs are used, if required.
eq(proofEnd, proof)
)
break
}
}
}
/// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
/// given `proof` and `flags`.
///
/// Note:
/// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
/// will always return false.
/// - Any non-zero word in the `flags` array is treated as true.
/// - The calldata offset of `proof` must be non-zero
/// (i.e. `proof` is from a regular Solidity function with a 4-byte selector).
function verifyMultiProofCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32[] calldata leaves,
bool[] calldata flags
) internal pure returns (bool isValid) {
// Rebuilds the root by consuming and producing values on a queue.
// The queue starts with the `leaves` array, and goes into a `hashes` array.
// After the process, the last element on the queue is verified
// to be equal to the `root`.
//
// The `flags` array denotes whether the sibling
// should be popped from the queue (`flag == true`), or
// should be popped from the `proof` (`flag == false`).
/// @solidity memory-safe-assembly
assembly {
// If the number of flags is correct.
for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} {
// For the case where `proof.length + leaves.length == 1`.
if iszero(flags.length) {
// `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
// forgefmt: disable-next-item
isValid := eq(
calldataload(
xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length))
),
root
)
break
}
// The required final proof offset if `flagsLength` is not zero, otherwise zero.
let proofEnd := add(proof.offset, shl(5, proof.length))
// We can use the free memory space for the queue.
// We don't need to allocate, since the queue is temporary.
let hashesFront := mload(0x40)
// Copy the leaves into the hashes.
// Sometimes, a little memory expansion costs less than branching.
// Should cost less, even with a high free memory offset of 0x7d00.
calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length))
// Compute the back of the hashes.
let hashesBack := add(hashesFront, shl(5, leaves.length))
// This is the end of the memory for the queue.
// We recycle `flagsLength` to save on stack variables (sometimes save gas).
flags.length := add(hashesBack, shl(5, flags.length))
// We don't need to make a copy of `proof.offset` or `flags.offset`,
// as they are pass-by-value (this trick may not always save gas).
for {} 1 {} {
// Pop from `hashes`.
let a := mload(hashesFront)
// Pop from `hashes`.
let b := mload(add(hashesFront, 0x20))
hashesFront := add(hashesFront, 0x40)
// If the flag is false, load the next proof,
// else, pops from the queue.
if iszero(calldataload(flags.offset)) {
// Loads the next proof.
b := calldataload(proof.offset)
proof.offset := add(proof.offset, 0x20)
// Unpop from `hashes`.
hashesFront := sub(hashesFront, 0x20)
}
// Advance to the next flag offset.
flags.offset := add(flags.offset, 0x20)
// Slot of `a` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(a, b))
// Hash the scratch space and push the result onto the queue.
mstore(scratch, a)
mstore(xor(scratch, 0x20), b)
mstore(hashesBack, keccak256(0x00, 0x40))
hashesBack := add(hashesBack, 0x20)
if iszero(lt(hashesBack, flags.length)) { break }
}
isValid :=
and(
// Checks if the last value in the queue is same as the root.
eq(mload(sub(hashesBack, 0x20)), root),
// And whether all the proofs are used, if required.
eq(proofEnd, proof.offset)
)
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EMPTY CALLDATA HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an empty calldata bytes32 array.
function emptyProof() internal pure returns (bytes32[] calldata proof) {
/// @solidity memory-safe-assembly
assembly {
proof.length := 0
}
}
/// @dev Returns an empty calldata bytes32 array.
function emptyLeaves() internal pure returns (bytes32[] calldata leaves) {
/// @solidity memory-safe-assembly
assembly {
leaves.length := 0
}
}
/// @dev Returns an empty calldata bool array.
function emptyFlags() internal pure returns (bool[] calldata flags) {
/// @solidity memory-safe-assembly
assembly {
flags.length := 0
}
}
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"solady/=lib/solady/src/",
"murky/=lib/murky/src/",
"@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/",
"@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/",
"@layerzerolabs/lz-evm-oapp-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/oapp/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"LayerZero-v2/=lib/LayerZero-v2/",
"devtools/=lib/devtools/packages/toolbox-foundry/src/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"CallError","type":"error"},{"inputs":[],"name":"InsufficientGas","type":"error"},{"inputs":[],"name":"IntentExpired","type":"error"},{"inputs":[],"name":"InvalidPreCallEOA","type":"error"},{"inputs":[],"name":"OrderAlreadyFilled","type":"error"},{"inputs":[],"name":"PaymentError","type":"error"},{"inputs":[],"name":"PreCallError","type":"error"},{"inputs":[],"name":"PreCallVerificationError","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SimulateExecuteFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"gUsed","type":"uint256"}],"name":"SimulationPassed","type":"error"},{"inputs":[],"name":"StateOverrideError","type":"error"},{"inputs":[],"name":"UnauthorizedCallContext","type":"error"},{"inputs":[],"name":"UnsupportedAccountImplementation","type":"error"},{"inputs":[],"name":"VerificationError","type":"error"},{"inputs":[],"name":"VerifiedCallError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"eoa","type":"address"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bool","name":"incremented","type":"bool"},{"indexed":false,"internalType":"bytes4","name":"err","type":"bytes4"}],"name":"IntentExecuted","type":"event"},{"inputs":[],"name":"CALL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INTENT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MULTICHAIN_NONCE_PREFIX","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIGNED_CALL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"eoa","type":"address"}],"name":"accountImplementationOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedIntent","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes4","name":"err","type":"bytes4"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"encodedIntents","type":"bytes[]"}],"name":"execute","outputs":[{"internalType":"bytes4[]","name":"errs","type":"bytes4[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"parentEOA","type":"address"},{"components":[{"internalType":"address","name":"eoa","type":"address"},{"internalType":"bytes","name":"executionData","type":"bytes"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct ICommon.SignedCall[]","name":"preCalls","type":"tuple[]"}],"name":"executePreCalls","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"selfCallPayVerifyCall537021665","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"isStateOverride","type":"bool"},{"internalType":"uint256","name":"combinedGasOverride","type":"uint256"},{"internalType":"bytes","name":"encodedIntent","type":"bytes"}],"name":"simulateExecute","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6101406040523061012052348015610015575f5ffd5b50306080524660a052606080610066604080518082018252600c81526b27b931b432b9ba3930ba37b960a11b60208083019190915282518084019093526005835264302e352e3360d81b9083015291565b815160209283012081519183019190912060c082905260e0819052604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152938401929092529082015246606082015230608082015260a0902061010052506100cf9050565b60805160a05160c05160e05161010051610120516123516101135f395f50505f6115ec01525f6116a601525f61168001525f61163001525f61160d01526123515ff3fe6080604052600436106100bd575f3560e01c80635e35359e1161007c578063a973567411610057578063a973567414610223578063b082a27414610242578063d2f308f714610275578063fcd4e707146102ac575f5ffd5b80635e35359e146101ca57806384b0196e146101e957806391210ad314610210575f5ffd5b80156100c857806309c5eabe146100d25780631a912f3e1461010357806320606b70146101445780632dffc9381461017757806344471415146101aa575f5ffd5b366100c457005b5f5ffd5b6100d06102d4565b005b6100e56100e0366004611bb6565b6105d4565b6040516001600160e01b031990911681526020015b60405180910390f35b34801561010e575f5ffd5b506101367f9085b19ea56248c94d86174b3784cfaaa8673d1041d6441f61ff52752dac848381565b6040519081526020016100fa565b34801561014f575f5ffd5b506101367f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b348015610182575f5ffd5b506101367fb3ab12b09e311d9da599763c22609320b6f3d062ecd1b9454761710f8db60cb781565b6101bd6101b8366004611c34565b61064c565b6040516100fa9190611c66565b3480156101d5575f5ffd5b506100d06101e4366004611cc9565b61072f565b3480156101f4575f5ffd5b506101fd61073f565b6040516100fa9796959493929190611d35565b61013661021e366004611dd8565b610765565b34801561022e575f5ffd5b506100d061023d366004611e2f565b6107f0565b34801561024d575f5ffd5b506101367f32ea001e8ffe499807c3f32d34d7e040163b7744091bec80a98c54abd384138681565b348015610280575f5ffd5b5061029461028f366004611e7f565b610938565b6040516001600160a01b0390911681526020016100fa565b3480156102b7575f5ffd5b506102c161c1d081565b60405161ffff90911681526020016100fa565b3330146102df575f5ffd5b602480359081019060043590610164013515801590610302575081610140013542115b1561032057604051631022c88d60e21b815260040160405180910390fd5b5f61032e6020840184611e7f565b905060408301355f61033f85610949565b90506103b6836103576101a088016101808901611e7f565b836103666101008a018a611e9a565b61036f91611f6b565b61037d6101a08b018b612012565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610abd92505050565b6103c360e0860186611e9a565b1590506103e1576103e183856103dc60e0890189611e9a565b610cab565b5f806103f561018088016101608901612054565b156104e257610446838661040d6102208b018b612012565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610e3592505050565b90925090505f61045a610100890189611e9a565b905011156104dd5761047461014088016101208901611e7f565b6001600160a01b0316634fdf7085846104916101c08b018b612012565b6040518463ffffffff1660e01b81526004016104af9392919061206f565b5f604051808303815f87803b1580156104c6575f5ffd5b505af11580156104d8573d5f5f3e3d5ffd5b505050505b610500565b6104fa83866104f56102208b018b612012565b610ef0565b90925090505b6001860361050d57600191505b8161052b57604051633ef2c2cd60e21b815260040160405180910390fd5b6105358585610f42565b6101e08701351561054b5761054b818489610f6c565b5f61058a690100000000007821000160b01b61056a60208b018b612012565b604080516020810188905201604051602081830303815290604052611080565b90505f5f5260205f8251836020015f8a5af16105ca57600187036105b4573d5f6040513e3d604051fd5b5f516105c557630d93a8fd60e31b5f525b60205ff35b5050505050505050565b5f688000000000ab143c065c156105f25763ab143c065f526004601cfd5b30688000000000ab143c065d61060a83835f5f6110bd565b91505f90505b1561063957688000000000ab143c064660010361062f575f815d610633565b8081555b50610646565b5f688000000000ab143c065d5b92915050565b6060688000000000ab143c065c1561066b5763ab143c065f526004601cfd5b30688000000000ab143c065d816001600160401b0381111561068f5761068f611edf565b6040519080825280602002602001820160405280156106b8578160200160208202803683370190505b5090505f5b82811015610728576106f38484838181106106da576106da6120a4565b90506020028101906106ec9190612012565b5f5f6110bd565b9050828281518110610707576107076120a4565b6001600160e01b0319909216602092830291909101909101526001016106bd565b505f610610565b61073a838383611367565b505050565b600f60f81b6060805f80808361075361138a565b97989097965046955030945091925090565b5f5f5f61077585858860016110bd565b90925090506001600160e01b031981161561079257805f5260205ffd5b86156107c8576001600160c01b033231106107af575090506107e8565b604051635207031d60e01b815260040160405180910390fd5b6040516313c300a360e21b81526004810183905260240160405180910390fd5b949350505050565b5f5b81811015610932573683838381811061080d5761080d6120a4565b905060200281019061081f91906120b8565b90505f61083e6108326020840184611e7f565b87606082901b15021790565b905060408201355f80610861610853866113cc565b856104f56060890189612012565b915091508161088357604051636ac5b32f60e01b815260040160405180910390fd5b61088d8484610f42565b5f6108ac690100000000007821000160b01b61056a6020890189612012565b90505f5f5260205f8251836020015f895af16108d8575f516108d357632228d5db60e01b5f525b60205ffd5b60408051600181525f602082015281880135916001600160a01b038816917f23a3c1343409f01965611c9c4c8b99e36d7b09ca22516507d5486ce0584379b8910160405180910390a35050505050508060010190506107f2565b50505050565b5f61094282611452565b9392505050565b60408051600d81526101c0810182527f32ea001e8ffe499807c3f32d34d7e040163b7744091bec80a98c54abd384138660208201525f9183013560f01c61c1d014906109a16001835b600190910160051b8301528190565b506109cc60026109b46020870187611e7f565b6001600160a01b0316600190910160051b8301528190565b506109e760036109926109e26020880188612012565b61148a565b50604084013560a0820152610a0760056109b46080870160608801611e7f565b50610a1d60066109b460a0870160808801611e7f565b5060a084013561010082015260c0840135610120820152610a4e6009610992610a4960e0880188611e9a565b611567565b50610a65600a610992610a49610100880188611e9a565b50610a7d600b6109b461014087016101208801611e7f565b506101408401356101a0820152805b5081610aaa57805160051b6020820120610aa5906115ea565b6107e8565b805160051b60208201206107e890611700565b815115610ca4575f82516001600160401b03811115610ade57610ade611edf565b604051908082528060200260200182016040528015610b2257816020015b604080518082019091525f8082526020820152815260200190600190039081610afc5790505b5090505f5b8351811015610b8257838181518110610b4257610b426120a4565b6020026020010151806020019051810190610b5d91906120d6565b828281518110610b6f57610b6f6120a4565b6020908102919091010152600101610b27565b5060405163dd16ec8760e01b81526001600160a01b0386169063dd16ec8790610bb39087908590879060040161212d565b5f604051808303815f87803b158015610bca575f5ffd5b505af1158015610bdc573d5f5f3e3d5ffd5b505050505f5f6001600160a01b0316825f81518110610bfd57610bfd6120a4565b60200260200101515f01516001600160a01b031603610c4b57610c3d87835f81518110610c2c57610c2c6120a4565b602002602001015160200151611774565b80610c47816121a2565b9150505b8151811015610ca157610c99828281518110610c6957610c696120a4565b60200260200101515f01518789858581518110610c8857610c886120a4565b60200260200101516020015161178d565b600101610c4b565b50505b5050505050565b5f5b81811015610ca45736610ce4848484818110610ccb57610ccb6120a4565b9050602002810190610cdd9190612012565b5080350190565b90505f610d03610cf76020840184611e7f565b88606082901b15021790565b905060408201356001600160a01b0380831690891614610d365760405163e798001d60e01b815260040160405180910390fd5b5f5f610d44610853866113cc565b9150915060018903610d5557600191505b81610d7357604051636ac5b32f60e01b815260040160405180910390fd5b610d7d8484610f42565b5f610d9c690100000000007821000160b01b61056a6020890189612012565b90505f5f5260205f8251836020015f895af1610ddb5760018a03610dc6573d5f6040513e3d604051fd5b5f516108d357632228d5db60e01b5f5260205ffd5b60408051600181525f602082015281880135916001600160a01b038816917f23a3c1343409f01965611c9c4c8b99e36d7b09ca22516507d5486ce0584379b8910160405180910390a3505050505050806001019050610cad565b5f5f5f5f5f85806020019051810190610e4e9190612213565b925092509250610e5f83838a6117e6565b15610ede5760405163033bdced60e21b81526001600160a01b03881690630cef73b490610e9290859085906004016122d7565b6040805180830381865afa158015610eac573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ed091906122ef565b9095509350610ee892505050565b505f935083925050505b935093915050565b5f5f604051630cef73b481528660208201526040808201528360608201528385608083013760405f60648601601c8401895afa92505081603f3d111660015f5114169150602051905094509492505050565b639e49fbf15f52806020525f5f6024601c5f865af1610f685763756688fe5f526004601cfd5b5050565b6101e08101355f610fac610fa0610f8960a0860160808701611e7f565b610f9b61022087016102008801611e7f565b611826565b8381019081105f031790565b90505f610fda610fc26080860160608701611e7f565b610fcf6020870187611e7f565b606082901b15021790565b905060405163f81d87a781528360208201528660408201528560608201526080808201528436036020810160a0830152602060c0830152808660e084013760205f8260c401601c85015f875af16110305760205ffd5b5082905061105961104760a0870160808801611e7f565b610f9b61022088016102008901611e7f565b10156110785760405163abab8fc960e01b815260040160405180910390fd5b505050505050565b606061108d848484611850565b905080516064820391506040604483015285602483015263e9ae5c53600483015280606401825250949350505050565b5f5f366110ca87876118bb565b90505f6bffffffffffffffffffffffff8616801560c0840135021790505f5a90508260a00135836101e0013511156111275763abab8fc960e01b93505f1986016111275760405163abab8fc960e01b815260040160405180910390fd5b620186a082018281105f031760065a603f02901c10156111625760018614611162576040516307099c5360e21b815260040160405180910390fd5b5f61117561028085016102608601611e7f565b6001600160a01b0316146111e75761119561028084016102608501611e7f565b6001600160a01b03166111ae61028f6020860186611e7f565b6001600160a01b0316146111e757636c875b4d60e01b93505f1986016111e757604051636c875b4d60e01b815260040160405180910390fd5b5f6111fb610fc26080860160608701611e7f565b905061120f61018085016101608601612054565b15801561122d57506001600160e01b03198516156101e08501351515165b15611282576101e084013561125161124b60a0870160808801611e7f565b83611826565b10156112825763abab8fc960e01b94505f1987016112825760405163abab8fc960e01b815260040160405180910390fd5b5f604051866112dc578a8c60408301375f81528860208201525f5f5260205f60248d01601c84015f308af191505f519650816112dc57600189036112cc573d5f6040513e3d604051fd5b866112dc57632b536c8960e21b96505b5060408501356112ef6020870187611e7f565b6001600160a01b03167f23a3c1343409f01965611c9c4c8b99e36d7b09ca22516507d5486ce0584379b8838960405161133e92919091151582526001600160e01b031916602082015260400190565b60405180910390a3801561135957611356835a900390565b96505b505050505094509492505050565b6001600160a01b03831661137f5761073a8282611774565b61073a83838361195c565b604080518082018252600c81526b27b931b432b9ba3930ba37b960a11b60208083019190915282518084019093526005835264302e352e3360d81b9083015291565b604080516005815260c0810182527fb3ab12b09e311d9da599763c22609320b6f3d062ecd1b9454761710f8db60cb760208201525f9183013560f01c61c1d01490611418600183610992565b5061142b60026109b46020870187611e7f565b5061144160036109926109e26020880188612012565b50604084013560a082015280610a8c565b5f5f61145d836119a6565b9150611468826119c4565b15611485575f5f5260205f60015f865afa611481575f5ffd5b505f515b915091565b5f365f6114978585611a09565b604080518281526001830160051b810190915291935091505f5b80831461155257600581901b8401358401803590602080820135916040810135019081019035611542856115337f9085b19ea56248c94d86174b3784cfaaa8673d1041d6441f61ff52752dac84836001600160a01b038816876115148888611a9f565b6040805194855260208501939093529183015260608201526080902090565b600190910160051b8801528690565b50505050508060010190506114b1565b50805160051b60208201209695505050505050565b5f806115838360408051828152600190920160051b8201905290565b90505f5b838110156115d7576115ce816115bf8787858181106115a8576115a86120a4565b90506020028101906115ba9190612012565b611a9f565b600190910160051b8401528290565b50600101611587565b50805160051b6020820120949350505050565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f00000000000000000000000000000000000000000000000000000000000000004614166116dd5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000009181019190915246606082015230608082015260a090205b6719010000000000005f5280601a5281603a52604260182090505f603a52919050565b5f5f5f61170b61138a565b915091506040517f91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a27665f5282516020840120602052815160208301206040523060605260805f206020526119015f52846040526042601e20935080604052505f6060525050919050565b5f385f3884865af1610f685763b12d13eb5f526004601cfd5b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af18060015f5114166117d857803d873b1517106117d857637939f4245f526004601cfd5b505f60605260405250505050565b5f83511561181f5760208401845160051b81015b8151841160051b938452815160209485185260405f2093909101908082106117fa5750505b5014919050565b5f6001600160a01b03831661184657506001600160a01b03811631610646565b6109428383611ab0565b60606040516064019050833580840360406020840152808287016060850137806040016040840152806060840101915050808303816020018451015b81830151835260208301925080831061188c576020840183038452604036823750506020016040529392505050565b36365f6118c985855f611ada565b90935083925090506118e86118e16020840184612012565b8484611b0b565b6118ff6118f860e0850185611e9a565b8484611b26565b6119106118f8610100850185611e9a565b6119216118e16101a0850185612012565b6119326118e16101c0850185612012565b6119436118e1610220850185612012565b6119546118e1610240850185612012565b505092915050565b816014528060345263a9059cbb60601b5f5260205f604460105f875af18060015f51141661199c57803d853b15171061199c576390b8ec185f526004601cfd5b505f603452505050565b5f60205f5f843c5f5160f01c61ef011460035160601c029050919050565b5f6040516101ba5f82853c5f6006820181905260278201526101ba90207ff8710866f390ac7c12640457f9cb9663657ac8168b7d4ce6418a982932b3043e1492915050565b365f833580850160208587010360208201945081359350808460051b8301118360401c1715611a3f5763ba597e7e5f526004601cfd5b8315611a95578392505b6001830392508260051b850135915081850160408101358082018381358201118460408501111782861782351760401c1715611a8c5763ba597e7e5f526004601cfd5b50505082611a49575b5050509250929050565b5f8183604051375060405120919050565b5f816014526370a0823160601b5f5260208060246010865afa601f3d111660205102905092915050565b828101358084019080840390601f19850190868217811760401c8286111715611b01575f82fd5b5050935093915050565b83831760401c82820184860111838610171715610932575f5ffd5b6020828201038460401c8386101715611b3d575f5ffd5b5f5b808514611078578060051b8601358681018035848183011183821760401c1715611b67575f5ffd5b505050600101611b3f565b5f5f83601f840112611b82575f5ffd5b5081356001600160401b03811115611b98575f5ffd5b602083019150836020828501011115611baf575f5ffd5b9250929050565b5f5f60208385031215611bc7575f5ffd5b82356001600160401b03811115611bdc575f5ffd5b611be885828601611b72565b90969095509350505050565b5f5f83601f840112611c04575f5ffd5b5081356001600160401b03811115611c1a575f5ffd5b6020830191508360208260051b8501011115611baf575f5ffd5b5f5f60208385031215611c45575f5ffd5b82356001600160401b03811115611c5a575f5ffd5b611be885828601611bf4565b602080825282518282018190525f918401906040840190835b81811015611ca75783516001600160e01b031916835260209384019390920191600101611c7f565b509095945050505050565b6001600160a01b0381168114611cc6575f5ffd5b50565b5f5f5f60608486031215611cdb575f5ffd5b8335611ce681611cb2565b92506020840135611cf681611cb2565b929592945050506040919091013590565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60ff60f81b8816815260e060208201525f611d5360e0830189611d07565b8281036040840152611d658189611d07565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015611dba578351835260209384019390920191600101611d9c565b50909b9a5050505050505050505050565b8015158114611cc6575f5ffd5b5f5f5f5f60608587031215611deb575f5ffd5b8435611df681611dcb565b93506020850135925060408501356001600160401b03811115611e17575f5ffd5b611e2387828801611b72565b95989497509550505050565b5f5f5f60408486031215611e41575f5ffd5b8335611e4c81611cb2565b925060208401356001600160401b03811115611e66575f5ffd5b611e7286828701611bf4565b9497909650939450505050565b5f60208284031215611e8f575f5ffd5b813561094281611cb2565b5f5f8335601e19843603018112611eaf575f5ffd5b8301803591506001600160401b03821115611ec8575f5ffd5b6020019150600581901b3603821315611baf575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715611f1b57611f1b611edf565b604052919050565b5f6001600160401b03821115611f3b57611f3b611edf565b5060051b60200190565b5f6001600160401b03821115611f5d57611f5d611edf565b50601f01601f191660200190565b5f611f7d611f7884611f23565b611ef3565b8381526020810190600585901b840136811115611f98575f5ffd5b845b81811015611ca75780356001600160401b03811115611fb7575f5ffd5b860136601f820112611fc7575f5ffd5b8035611fd5611f7882611f45565b818152366020838501011115611fe9575f5ffd5b816020840160208301375f60208383010152808752505050602084019350602081019050611f9a565b5f5f8335601e19843603018112612027575f5ffd5b8301803591506001600160401b03821115612040575f5ffd5b602001915036819003821315611baf575f5ffd5b5f60208284031215612064575f5ffd5b813561094281611dcb565b83815260406020820152816040820152818360608301375f818301606090810191909152601f909201601f1916010192915050565b634e487b7160e01b5f52603260045260245ffd5b5f8235607e198336030181126120cc575f5ffd5b9190910192915050565b5f60408284031280156120e7575f5ffd5b50604080519081016001600160401b038111828210171561210a5761210a611edf565b604052825161211881611cb2565b81526020928301519281019290925250919050565b5f60608201858352606060208401528085518083526080850191506020870192505f5b8181101561218357835180516001600160a01b031684526020908101518185015290930192604090920191600101612150565b505083810360408501526121978186611d07565b979650505050505050565b5f600182016121bf57634e487b7160e01b5f52601160045260245ffd5b5060010190565b5f82601f8301126121d5575f5ffd5b81516121e3611f7882611f45565b8181528460208386010111156121f7575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f5f5f60608486031215612225575f5ffd5b83516001600160401b0381111561223a575f5ffd5b8401601f8101861361224a575f5ffd5b8051612258611f7882611f23565b8082825260208201915060208360051b850101925088831115612279575f5ffd5b6020840193505b8284101561229b578351825260209384019390910190612280565b602088015160408901519197509550925050506001600160401b038111156122c1575f5ffd5b6122cd868287016121c6565b9150509250925092565b828152604060208201525f6107e86040830184611d07565b5f5f60408385031215612300575f5ffd5b825161230b81611dcb565b602093909301519294929350505056fea26469706673582212208d91cf27755e3ba172c1fbbea89a0ffafe94c7ec01ebeffa37baec4f4b7fd05864736f6c634300081c0033
Deployed Bytecode
0x6080604052600436106100bd575f3560e01c80635e35359e1161007c578063a973567411610057578063a973567414610223578063b082a27414610242578063d2f308f714610275578063fcd4e707146102ac575f5ffd5b80635e35359e146101ca57806384b0196e146101e957806391210ad314610210575f5ffd5b80156100c857806309c5eabe146100d25780631a912f3e1461010357806320606b70146101445780632dffc9381461017757806344471415146101aa575f5ffd5b366100c457005b5f5ffd5b6100d06102d4565b005b6100e56100e0366004611bb6565b6105d4565b6040516001600160e01b031990911681526020015b60405180910390f35b34801561010e575f5ffd5b506101367f9085b19ea56248c94d86174b3784cfaaa8673d1041d6441f61ff52752dac848381565b6040519081526020016100fa565b34801561014f575f5ffd5b506101367f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b348015610182575f5ffd5b506101367fb3ab12b09e311d9da599763c22609320b6f3d062ecd1b9454761710f8db60cb781565b6101bd6101b8366004611c34565b61064c565b6040516100fa9190611c66565b3480156101d5575f5ffd5b506100d06101e4366004611cc9565b61072f565b3480156101f4575f5ffd5b506101fd61073f565b6040516100fa9796959493929190611d35565b61013661021e366004611dd8565b610765565b34801561022e575f5ffd5b506100d061023d366004611e2f565b6107f0565b34801561024d575f5ffd5b506101367f32ea001e8ffe499807c3f32d34d7e040163b7744091bec80a98c54abd384138681565b348015610280575f5ffd5b5061029461028f366004611e7f565b610938565b6040516001600160a01b0390911681526020016100fa565b3480156102b7575f5ffd5b506102c161c1d081565b60405161ffff90911681526020016100fa565b3330146102df575f5ffd5b602480359081019060043590610164013515801590610302575081610140013542115b1561032057604051631022c88d60e21b815260040160405180910390fd5b5f61032e6020840184611e7f565b905060408301355f61033f85610949565b90506103b6836103576101a088016101808901611e7f565b836103666101008a018a611e9a565b61036f91611f6b565b61037d6101a08b018b612012565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610abd92505050565b6103c360e0860186611e9a565b1590506103e1576103e183856103dc60e0890189611e9a565b610cab565b5f806103f561018088016101608901612054565b156104e257610446838661040d6102208b018b612012565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610e3592505050565b90925090505f61045a610100890189611e9a565b905011156104dd5761047461014088016101208901611e7f565b6001600160a01b0316634fdf7085846104916101c08b018b612012565b6040518463ffffffff1660e01b81526004016104af9392919061206f565b5f604051808303815f87803b1580156104c6575f5ffd5b505af11580156104d8573d5f5f3e3d5ffd5b505050505b610500565b6104fa83866104f56102208b018b612012565b610ef0565b90925090505b6001860361050d57600191505b8161052b57604051633ef2c2cd60e21b815260040160405180910390fd5b6105358585610f42565b6101e08701351561054b5761054b818489610f6c565b5f61058a690100000000007821000160b01b61056a60208b018b612012565b604080516020810188905201604051602081830303815290604052611080565b90505f5f5260205f8251836020015f8a5af16105ca57600187036105b4573d5f6040513e3d604051fd5b5f516105c557630d93a8fd60e31b5f525b60205ff35b5050505050505050565b5f688000000000ab143c065c156105f25763ab143c065f526004601cfd5b30688000000000ab143c065d61060a83835f5f6110bd565b91505f90505b1561063957688000000000ab143c064660010361062f575f815d610633565b8081555b50610646565b5f688000000000ab143c065d5b92915050565b6060688000000000ab143c065c1561066b5763ab143c065f526004601cfd5b30688000000000ab143c065d816001600160401b0381111561068f5761068f611edf565b6040519080825280602002602001820160405280156106b8578160200160208202803683370190505b5090505f5b82811015610728576106f38484838181106106da576106da6120a4565b90506020028101906106ec9190612012565b5f5f6110bd565b9050828281518110610707576107076120a4565b6001600160e01b0319909216602092830291909101909101526001016106bd565b505f610610565b61073a838383611367565b505050565b600f60f81b6060805f80808361075361138a565b97989097965046955030945091925090565b5f5f5f61077585858860016110bd565b90925090506001600160e01b031981161561079257805f5260205ffd5b86156107c8576001600160c01b033231106107af575090506107e8565b604051635207031d60e01b815260040160405180910390fd5b6040516313c300a360e21b81526004810183905260240160405180910390fd5b949350505050565b5f5b81811015610932573683838381811061080d5761080d6120a4565b905060200281019061081f91906120b8565b90505f61083e6108326020840184611e7f565b87606082901b15021790565b905060408201355f80610861610853866113cc565b856104f56060890189612012565b915091508161088357604051636ac5b32f60e01b815260040160405180910390fd5b61088d8484610f42565b5f6108ac690100000000007821000160b01b61056a6020890189612012565b90505f5f5260205f8251836020015f895af16108d8575f516108d357632228d5db60e01b5f525b60205ffd5b60408051600181525f602082015281880135916001600160a01b038816917f23a3c1343409f01965611c9c4c8b99e36d7b09ca22516507d5486ce0584379b8910160405180910390a35050505050508060010190506107f2565b50505050565b5f61094282611452565b9392505050565b60408051600d81526101c0810182527f32ea001e8ffe499807c3f32d34d7e040163b7744091bec80a98c54abd384138660208201525f9183013560f01c61c1d014906109a16001835b600190910160051b8301528190565b506109cc60026109b46020870187611e7f565b6001600160a01b0316600190910160051b8301528190565b506109e760036109926109e26020880188612012565b61148a565b50604084013560a0820152610a0760056109b46080870160608801611e7f565b50610a1d60066109b460a0870160808801611e7f565b5060a084013561010082015260c0840135610120820152610a4e6009610992610a4960e0880188611e9a565b611567565b50610a65600a610992610a49610100880188611e9a565b50610a7d600b6109b461014087016101208801611e7f565b506101408401356101a0820152805b5081610aaa57805160051b6020820120610aa5906115ea565b6107e8565b805160051b60208201206107e890611700565b815115610ca4575f82516001600160401b03811115610ade57610ade611edf565b604051908082528060200260200182016040528015610b2257816020015b604080518082019091525f8082526020820152815260200190600190039081610afc5790505b5090505f5b8351811015610b8257838181518110610b4257610b426120a4565b6020026020010151806020019051810190610b5d91906120d6565b828281518110610b6f57610b6f6120a4565b6020908102919091010152600101610b27565b5060405163dd16ec8760e01b81526001600160a01b0386169063dd16ec8790610bb39087908590879060040161212d565b5f604051808303815f87803b158015610bca575f5ffd5b505af1158015610bdc573d5f5f3e3d5ffd5b505050505f5f6001600160a01b0316825f81518110610bfd57610bfd6120a4565b60200260200101515f01516001600160a01b031603610c4b57610c3d87835f81518110610c2c57610c2c6120a4565b602002602001015160200151611774565b80610c47816121a2565b9150505b8151811015610ca157610c99828281518110610c6957610c696120a4565b60200260200101515f01518789858581518110610c8857610c886120a4565b60200260200101516020015161178d565b600101610c4b565b50505b5050505050565b5f5b81811015610ca45736610ce4848484818110610ccb57610ccb6120a4565b9050602002810190610cdd9190612012565b5080350190565b90505f610d03610cf76020840184611e7f565b88606082901b15021790565b905060408201356001600160a01b0380831690891614610d365760405163e798001d60e01b815260040160405180910390fd5b5f5f610d44610853866113cc565b9150915060018903610d5557600191505b81610d7357604051636ac5b32f60e01b815260040160405180910390fd5b610d7d8484610f42565b5f610d9c690100000000007821000160b01b61056a6020890189612012565b90505f5f5260205f8251836020015f895af1610ddb5760018a03610dc6573d5f6040513e3d604051fd5b5f516108d357632228d5db60e01b5f5260205ffd5b60408051600181525f602082015281880135916001600160a01b038816917f23a3c1343409f01965611c9c4c8b99e36d7b09ca22516507d5486ce0584379b8910160405180910390a3505050505050806001019050610cad565b5f5f5f5f5f85806020019051810190610e4e9190612213565b925092509250610e5f83838a6117e6565b15610ede5760405163033bdced60e21b81526001600160a01b03881690630cef73b490610e9290859085906004016122d7565b6040805180830381865afa158015610eac573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ed091906122ef565b9095509350610ee892505050565b505f935083925050505b935093915050565b5f5f604051630cef73b481528660208201526040808201528360608201528385608083013760405f60648601601c8401895afa92505081603f3d111660015f5114169150602051905094509492505050565b639e49fbf15f52806020525f5f6024601c5f865af1610f685763756688fe5f526004601cfd5b5050565b6101e08101355f610fac610fa0610f8960a0860160808701611e7f565b610f9b61022087016102008801611e7f565b611826565b8381019081105f031790565b90505f610fda610fc26080860160608701611e7f565b610fcf6020870187611e7f565b606082901b15021790565b905060405163f81d87a781528360208201528660408201528560608201526080808201528436036020810160a0830152602060c0830152808660e084013760205f8260c401601c85015f875af16110305760205ffd5b5082905061105961104760a0870160808801611e7f565b610f9b61022088016102008901611e7f565b10156110785760405163abab8fc960e01b815260040160405180910390fd5b505050505050565b606061108d848484611850565b905080516064820391506040604483015285602483015263e9ae5c53600483015280606401825250949350505050565b5f5f366110ca87876118bb565b90505f6bffffffffffffffffffffffff8616801560c0840135021790505f5a90508260a00135836101e0013511156111275763abab8fc960e01b93505f1986016111275760405163abab8fc960e01b815260040160405180910390fd5b620186a082018281105f031760065a603f02901c10156111625760018614611162576040516307099c5360e21b815260040160405180910390fd5b5f61117561028085016102608601611e7f565b6001600160a01b0316146111e75761119561028084016102608501611e7f565b6001600160a01b03166111ae61028f6020860186611e7f565b6001600160a01b0316146111e757636c875b4d60e01b93505f1986016111e757604051636c875b4d60e01b815260040160405180910390fd5b5f6111fb610fc26080860160608701611e7f565b905061120f61018085016101608601612054565b15801561122d57506001600160e01b03198516156101e08501351515165b15611282576101e084013561125161124b60a0870160808801611e7f565b83611826565b10156112825763abab8fc960e01b94505f1987016112825760405163abab8fc960e01b815260040160405180910390fd5b5f604051866112dc578a8c60408301375f81528860208201525f5f5260205f60248d01601c84015f308af191505f519650816112dc57600189036112cc573d5f6040513e3d604051fd5b866112dc57632b536c8960e21b96505b5060408501356112ef6020870187611e7f565b6001600160a01b03167f23a3c1343409f01965611c9c4c8b99e36d7b09ca22516507d5486ce0584379b8838960405161133e92919091151582526001600160e01b031916602082015260400190565b60405180910390a3801561135957611356835a900390565b96505b505050505094509492505050565b6001600160a01b03831661137f5761073a8282611774565b61073a83838361195c565b604080518082018252600c81526b27b931b432b9ba3930ba37b960a11b60208083019190915282518084019093526005835264302e352e3360d81b9083015291565b604080516005815260c0810182527fb3ab12b09e311d9da599763c22609320b6f3d062ecd1b9454761710f8db60cb760208201525f9183013560f01c61c1d01490611418600183610992565b5061142b60026109b46020870187611e7f565b5061144160036109926109e26020880188612012565b50604084013560a082015280610a8c565b5f5f61145d836119a6565b9150611468826119c4565b15611485575f5f5260205f60015f865afa611481575f5ffd5b505f515b915091565b5f365f6114978585611a09565b604080518281526001830160051b810190915291935091505f5b80831461155257600581901b8401358401803590602080820135916040810135019081019035611542856115337f9085b19ea56248c94d86174b3784cfaaa8673d1041d6441f61ff52752dac84836001600160a01b038816876115148888611a9f565b6040805194855260208501939093529183015260608201526080902090565b600190910160051b8801528690565b50505050508060010190506114b1565b50805160051b60208201209695505050505050565b5f806115838360408051828152600190920160051b8201905290565b90505f5b838110156115d7576115ce816115bf8787858181106115a8576115a86120a4565b90506020028101906115ba9190612012565b611a9f565b600190910160051b8401528290565b50600101611587565b50805160051b6020820120949350505050565b7fa8d60c37a33310c6c99f14b8dac83aee14239bf3f4d970b02353c099d853fed87f000000000000000000000000deaa976dff2cf11dfebc06350950fe06f75b98a530147f00000000000000000000000000000000000000000000000000000000000b67d24614166116dd5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527fe233b71d56c139c749983f0d4368accc502097f07075b70fe2207c58c80684f460208201527f4360b5d7efd3a6f35040c2e5af68b065a708e431f7391a8a94fba6b770810bcb9181019190915246606082015230608082015260a090205b6719010000000000005f5280601a5281603a52604260182090505f603a52919050565b5f5f5f61170b61138a565b915091506040517f91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a27665f5282516020840120602052815160208301206040523060605260805f206020526119015f52846040526042601e20935080604052505f6060525050919050565b5f385f3884865af1610f685763b12d13eb5f526004601cfd5b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af18060015f5114166117d857803d873b1517106117d857637939f4245f526004601cfd5b505f60605260405250505050565b5f83511561181f5760208401845160051b81015b8151841160051b938452815160209485185260405f2093909101908082106117fa5750505b5014919050565b5f6001600160a01b03831661184657506001600160a01b03811631610646565b6109428383611ab0565b60606040516064019050833580840360406020840152808287016060850137806040016040840152806060840101915050808303816020018451015b81830151835260208301925080831061188c576020840183038452604036823750506020016040529392505050565b36365f6118c985855f611ada565b90935083925090506118e86118e16020840184612012565b8484611b0b565b6118ff6118f860e0850185611e9a565b8484611b26565b6119106118f8610100850185611e9a565b6119216118e16101a0850185612012565b6119326118e16101c0850185612012565b6119436118e1610220850185612012565b6119546118e1610240850185612012565b505092915050565b816014528060345263a9059cbb60601b5f5260205f604460105f875af18060015f51141661199c57803d853b15171061199c576390b8ec185f526004601cfd5b505f603452505050565b5f60205f5f843c5f5160f01c61ef011460035160601c029050919050565b5f6040516101ba5f82853c5f6006820181905260278201526101ba90207ff8710866f390ac7c12640457f9cb9663657ac8168b7d4ce6418a982932b3043e1492915050565b365f833580850160208587010360208201945081359350808460051b8301118360401c1715611a3f5763ba597e7e5f526004601cfd5b8315611a95578392505b6001830392508260051b850135915081850160408101358082018381358201118460408501111782861782351760401c1715611a8c5763ba597e7e5f526004601cfd5b50505082611a49575b5050509250929050565b5f8183604051375060405120919050565b5f816014526370a0823160601b5f5260208060246010865afa601f3d111660205102905092915050565b828101358084019080840390601f19850190868217811760401c8286111715611b01575f82fd5b5050935093915050565b83831760401c82820184860111838610171715610932575f5ffd5b6020828201038460401c8386101715611b3d575f5ffd5b5f5b808514611078578060051b8601358681018035848183011183821760401c1715611b67575f5ffd5b505050600101611b3f565b5f5f83601f840112611b82575f5ffd5b5081356001600160401b03811115611b98575f5ffd5b602083019150836020828501011115611baf575f5ffd5b9250929050565b5f5f60208385031215611bc7575f5ffd5b82356001600160401b03811115611bdc575f5ffd5b611be885828601611b72565b90969095509350505050565b5f5f83601f840112611c04575f5ffd5b5081356001600160401b03811115611c1a575f5ffd5b6020830191508360208260051b8501011115611baf575f5ffd5b5f5f60208385031215611c45575f5ffd5b82356001600160401b03811115611c5a575f5ffd5b611be885828601611bf4565b602080825282518282018190525f918401906040840190835b81811015611ca75783516001600160e01b031916835260209384019390920191600101611c7f565b509095945050505050565b6001600160a01b0381168114611cc6575f5ffd5b50565b5f5f5f60608486031215611cdb575f5ffd5b8335611ce681611cb2565b92506020840135611cf681611cb2565b929592945050506040919091013590565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60ff60f81b8816815260e060208201525f611d5360e0830189611d07565b8281036040840152611d658189611d07565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015611dba578351835260209384019390920191600101611d9c565b50909b9a5050505050505050505050565b8015158114611cc6575f5ffd5b5f5f5f5f60608587031215611deb575f5ffd5b8435611df681611dcb565b93506020850135925060408501356001600160401b03811115611e17575f5ffd5b611e2387828801611b72565b95989497509550505050565b5f5f5f60408486031215611e41575f5ffd5b8335611e4c81611cb2565b925060208401356001600160401b03811115611e66575f5ffd5b611e7286828701611bf4565b9497909650939450505050565b5f60208284031215611e8f575f5ffd5b813561094281611cb2565b5f5f8335601e19843603018112611eaf575f5ffd5b8301803591506001600160401b03821115611ec8575f5ffd5b6020019150600581901b3603821315611baf575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715611f1b57611f1b611edf565b604052919050565b5f6001600160401b03821115611f3b57611f3b611edf565b5060051b60200190565b5f6001600160401b03821115611f5d57611f5d611edf565b50601f01601f191660200190565b5f611f7d611f7884611f23565b611ef3565b8381526020810190600585901b840136811115611f98575f5ffd5b845b81811015611ca75780356001600160401b03811115611fb7575f5ffd5b860136601f820112611fc7575f5ffd5b8035611fd5611f7882611f45565b818152366020838501011115611fe9575f5ffd5b816020840160208301375f60208383010152808752505050602084019350602081019050611f9a565b5f5f8335601e19843603018112612027575f5ffd5b8301803591506001600160401b03821115612040575f5ffd5b602001915036819003821315611baf575f5ffd5b5f60208284031215612064575f5ffd5b813561094281611dcb565b83815260406020820152816040820152818360608301375f818301606090810191909152601f909201601f1916010192915050565b634e487b7160e01b5f52603260045260245ffd5b5f8235607e198336030181126120cc575f5ffd5b9190910192915050565b5f60408284031280156120e7575f5ffd5b50604080519081016001600160401b038111828210171561210a5761210a611edf565b604052825161211881611cb2565b81526020928301519281019290925250919050565b5f60608201858352606060208401528085518083526080850191506020870192505f5b8181101561218357835180516001600160a01b031684526020908101518185015290930192604090920191600101612150565b505083810360408501526121978186611d07565b979650505050505050565b5f600182016121bf57634e487b7160e01b5f52601160045260245ffd5b5060010190565b5f82601f8301126121d5575f5ffd5b81516121e3611f7882611f45565b8181528460208386010111156121f7575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f5f5f60608486031215612225575f5ffd5b83516001600160401b0381111561223a575f5ffd5b8401601f8101861361224a575f5ffd5b8051612258611f7882611f23565b8082825260208201915060208360051b850101925088831115612279575f5ffd5b6020840193505b8284101561229b578351825260209384019390910190612280565b602088015160408901519197509550925050506001600160401b038111156122c1575f5ffd5b6122cd868287016121c6565b9150509250925092565b828152604060208201525f6107e86040830184611d07565b5f5f60408385031215612300575f5ffd5b825161230b81611dcb565b602093909301519294929350505056fea26469706673582212208d91cf27755e3ba172c1fbbea89a0ffafe94c7ec01ebeffa37baec4f4b7fd05864736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.