false
true
0

Contract Address Details

0xC1fbe75Ad4cb8Ed4cA122bA2146d57B9eAe07dcf

Contract Name
Consumer
Creator
0xaf2ce0–4ab9b0 at 0x6d1ba2–be66c8
Balance
0 tPLS
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
25428758
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Consumer




Optimization enabled
false
Compiler version
v0.8.25+commit.b61c2a91




EVM Version
cancun




Verified at
2024-08-13T21:28:38.323196Z

Constructor Arguments

0x00000000000000000000000080493d07ddfce7a8b507c407459935a88c62ad8e

Arg [0] (address) : 0x80493d07ddfce7a8b507c407459935a88c62ad8e

              

contracts/Consumer.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {SSTORE2} from "solady/src/utils/SSTORE2.sol";
import {LibPRNG} from "solady/src/utils/LibPRNG.sol";
import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol";
import {EfficientHashLib} from "solady/src/utils/EfficientHashLib.sol";
import {LibMulticaller} from "multicaller/src/LibMulticaller.sol";
import {IRandom} from "./implementations/IRandom.sol";
import {PreimageLocation} from "./PreimageLocation.sol";
import {ERC20} from "solady/src/tokens/ERC20.sol";
import {Errors} from "./Constants.sol";

error SecretMismatch();

event Undermine(uint256 id, bytes32 preimage);

event Chain(bytes32 indexed owner, uint256 id, bytes32 key);

event Reveal(uint256 id, bytes32 formerSecret);

contract Consumer {
    using EfficientHashLib for bytes32;
    using SafeTransferLib for address;

    uint256 internal constant ZERO = 0;
    uint256 internal constant ONE = 1;
    uint256 internal constant NINE_SIX = 96;
    uint256 internal constant ONE_SIX_ZERO = 160;

    bytes32 internal immutable PREIMAGE_ZERO;

    address internal immutable rand;

    uint256 internal _id;

    struct Link {
        uint256 id;
        address owner;
        bool underminable;
        bytes32 key;
        bytes32 preimage;
        bytes32 revealed;
    }

    constructor(address _rand) payable {
        rand = _rand;
        PREIMAGE_ZERO = bytes32(ZERO).hash();
    }

    mapping(bytes32 preimage => bytes32 formerSecret) internal _preimageToSecret;
    mapping(bytes32 preimage => uint256 id) internal _preimageToId;
    mapping(uint256 id => bytes32 owner) internal _owner;
    mapping(uint256 id => bytes32 preimage) internal _preimage;
    mapping(uint256 id => bytes32 key) internal _key;

    function _undermineExpired(uint256 id, bytes32 hashed, IRandom.Randomness memory r) internal {
        // order preimage cannot be overriden until after all secrets have been revealed
        // this creates a high incentive for both player 1, and rule enforcer to get secrets on chain
        // before the expired line is crossed. either:
        // 1) player 1 wins, and they want to claim their winnings (high incentive to keep secret safe)
        // 2) player 1 loses, so the rule enforcer is incented to claim their winnings
        // 3) if either one waits too long - and allows others overwrite the preimage,
        //    then the benefiting party risks a re-roll of the randomness seed
        unchecked {
            if (r.seed == bytes32(ZERO)) {
                return;
            }
            if (hashed == _preimage[id]) {
                return;
            }
            if (uint256(_owner[id] >> ONE_SIX_ZERO) == ZERO) {
                revert Errors.Misconfigured();
            }
            // originator of the chained secret+preimage can reject updates
            // it is up to anyone who would wish to turn this feature on to check that it will work ahead of time
            // we allow non secret holdes to update the order preimage in order to maximally incent
            // randomenss campaign completion
            // think of it like chips with an expiry time. you might be able to cash them in,
            // but the desk might also refuse to honor them if the expiry time is too far from the defined values
            // in that case, they are worthless
            // if a casino wants to have an intermediate period they can enforce that in their own contract
            emit Undermine({id: id, preimage: hashed});
            _preimage[id] = hashed;
            // note that the preimage may not be what was originally intended - we do not track in the contract
        }
    }

    /**
     * @param id the id of the chained randomness to reveal
     * @dev calling tell should be considered risky in that it will revert if you are
     * a) do not have the original secret
     * b) unable to set the preimage to the hash of your revealed secret because you were too late
     * either way, at the end of this function call, you should have a preimageToSecret
     * that is set so that you can use it (it will not be bytes32(0))
     */
    function tell(uint256 id, bytes32 revealedSecret) external {
        unchecked {
            if (_preimageToSecret[_preimage[id]] != bytes32(ZERO)) {
                return;
            }
            bytes32 key = _key[id];
            IRandom.Randomness memory r = IRandom(rand).randomness(key);
            bytes32 hashed = revealedSecret.hash();
            if (IRandom(rand).expired(r.timeline)) {
                _undermineExpired(id, hashed, r);
            }
            if (hashed != _preimage[id]) {
                revert SecretMismatch();
            }
            _preimageToSecret[hashed] = revealedSecret;
            emit Reveal({id: id, formerSecret: revealedSecret});
            // we do not emit an event here because it is more likely that users will simply
            // do it themselves via a contract or only care about the latest
        }
    }

    function chain(address owner, bool onlySameTx, bool underminable, bytes32 preimage)
        external
        payable
        returns (uint256 id)
    {
        bytes32 key = IRandom(rand).latest(owner, onlySameTx);
        if (key == bytes32(ZERO)) {
            revert Errors.Misconfigured();
        }
        return _chainTo(LibMulticaller.senderOrSigner(), underminable, preimage, key);
    }

    function chainTo(address owner, bool underminable, bytes32 preimage, bytes32 key)
        external
        payable
        returns (uint256)
    {
        return _chainTo(owner, underminable, preimage, key);
    }

    function latestId() external view returns (uint256) {
        return _id;
    }

    function link(uint256 idParam) external view returns (Link memory l) {
        bytes32 key = _key[idParam];
        if (key == bytes32(ZERO)) {
            return l;
        }
        bytes32 preimage = _preimage[idParam];
        bytes32 o = _owner[idParam];
        l = Link({
            id: idParam,
            key: key,
            owner: address(bytes20(o << NINE_SIX)),
            underminable: o >> ONE_SIX_ZERO == 0x00 ? false : true,
            preimage: preimage,
            revealed: _preimageToSecret[preimage]
        });
    }

    function _chainTo(address owner, bool underminable, bytes32 preimage, bytes32 key) internal returns (uint256 id) {
        unchecked {
            if (preimage == bytes32(ZERO) || preimage == PREIMAGE_ZERO) {
                revert Errors.Misconfigured();
            }
            id = _preimageToId[preimage];
            bytes32 o = bytes32((underminable ? (ONE << ONE_SIX_ZERO) : ZERO) | uint256(uint160(owner)));
            if (_preimage[id] == preimage) {
                if (_owner[id] == o) {
                    return id;
                }
            }
            id = ++_id;
            _owner[id] = o;
            _preimage[id] = preimage;
            _key[id] = key;
            // allow for reverse lookup
            _preimageToId[preimage] = id;
            emit Chain({owner: o, id: id, key: key});
        }
    }
}
        

solady/src/utils/SafeTransferLib.sol

// 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.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
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 Permit2 operation has failed.
    error Permit2Failed();

    /// @dev The Permit2 amount must be less than `2**160 - 1`.
    error Permit2AmountOverflow();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         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 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;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       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)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      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)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                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 :=
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            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.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                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.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                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.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                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)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                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.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                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.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    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 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), 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), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
                    // `nonces` is already at `add(m, 0x54)`.
                    // `1` 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(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {
                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}
          

contracts/Constants.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

event Ok(address indexed provider, bytes32 section);

event Bleach(address indexed provider, bytes32 section);

event Reprice(address indexed provider, uint256 pricePer);

event Ink(address indexed provider, uint256 offset, address pointer);

event Heat(address indexed provider, bytes32 section, uint256 index);

event Start(address indexed owner, bytes32 key); // no need to index because all keys should be unique

event Reveal(address indexed provider, bytes32 location, bytes32 formerSecret);

event Expired(address indexed recipient, address indexed ender, bytes32 key);

event FundingScattered(address indexed recipient, uint256 amount, bytes32 key);

event Cast(bytes32 key, bytes32 seed);

event Chop(bytes32 key);

abstract contract Errors {
    error DeploymentFailed();
    error Misconfigured();
    error UnableToService();
    error MissingPayment();
    error SecretMismatch();
    error ZeroSecret();
    error NotInCohort();
    error SignerMismatch();
}
          

contracts/PreimageLocation.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {EfficientHashLib} from "solady/src/utils/EfficientHashLib.sol";

library PreimageLocation {
    struct Info {
        address provider;
        address token;
        uint256 price;
        uint256 offset;
        uint256 index;
    }

    function hash(Info memory info) internal pure returns (bytes32) {
        return EfficientHashLib.hash(
            bytes32(uint256(uint160(info.provider))),
            bytes32(uint256(uint160(info.token))),
            bytes32(info.price),
            bytes32(info.offset),
            bytes32(info.index)
        );
    }

    function section(Info memory info) internal pure returns (bytes32) {
        return EfficientHashLib.hash(
            bytes32(uint256(uint160(info.provider))),
            bytes32(uint256(uint160(info.token))),
            bytes32(info.price),
            bytes32(info.offset)
        );
    }
}
          

contracts/implementations/IRandom.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {PreimageLocation} from "../PreimageLocation.sol";

abstract contract IRandom {
    uint256 internal constant ZERO = 0;
    uint256 internal constant ONE = 1;
    uint256 internal constant EIGHT = 8;
    uint256 internal constant ONE_SIX = 16;
    uint256 internal constant THREE_TWO = 32;
    uint256 internal constant FOUR_EIGHT = 48;
    uint256 internal constant NINE_SIX = 96;
    uint256 internal constant ONE_TWO_EIGHT = 128;
    uint256 internal constant ONE_SIX_ZERO = 160;
    uint256 internal constant TWO_ZERO_EIGHT = 208;
    uint256 internal constant TWO_ZERO_NINE = ONE + TWO_ZERO_EIGHT;
    uint256 internal constant TWO_FOUR_EIGHT = 248;
    uint256 internal constant TWO_FIVE_FIVE = 255;
    uint256 internal constant TWO_FIVE_SIX = 256;

    mapping(bytes32 key => uint256 timeline) internal _timeline;
    mapping(bytes32 key => bytes32 seed) internal _seed;

    struct Randomness {
        uint256 timeline;
        bytes32 seed;
    }

    function heat(uint256 required, uint256 expiryOffset, address token, PreimageLocation.Info[] calldata info)
        external
        payable
        virtual
        returns (bytes32);
    function pointer(PreimageLocation.Info calldata info) external view virtual returns (address);
    function consumed(PreimageLocation.Info calldata info) external view virtual returns (bool);
    function randomness(bytes32 key) external view virtual returns (Randomness memory);
    function latest(address account, bool onlySameTx) external view virtual returns (bytes32);

    function expired(uint256 timeline) external view virtual returns (bool) {
        return _expired(timeline);
    }

    function _expired(uint256 timeline) internal view virtual returns (bool) {
        unchecked {
            // end
            return (timeline << (TWO_FIVE_FIVE - EIGHT) >> TWO_FIVE_FIVE == ZERO ? block.number : block.timestamp)
            // start
            - (uint256(uint48(timeline >> FOUR_EIGHT)))
            // expiration delta
            > (uint256(uint40(timeline) >> (EIGHT + ONE)));
        }
    }
}
          

multicaller/src/LibMulticaller.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/**
 * @title LibMulticaller
 * @author vectorized.eth
 * @notice Library to read the `msg.sender` of the multicaller with sender contract.
 *
 * @dev Note:
 * The functions in this library do NOT guard against reentrancy.
 * A single transaction can recurse through different Multicallers
 * (e.g. `MulticallerWithSender -> contract -> MulticallerWithSigner -> contract`).
 *
 * Think of these functions like `msg.sender`.
 *
 * If your contract `C` can handle reentrancy safely with plain old `msg.sender`
 * for any `A -> C -> B -> C`, you should be fine substituting `msg.sender` with these functions.
 */
library LibMulticaller {
    /**
     * @dev The address of the multicaller contract.
     */
    address internal constant MULTICALLER = 0x0000000000002Bdbf1Bf3279983603Ec279CC6dF;

    /**
     * @dev The address of the multicaller with sender contract.
     */
    address internal constant MULTICALLER_WITH_SENDER = 0x00000000002Fd5Aeb385D324B580FCa7c83823A0;

    /**
     * @dev The address of the multicaller with signer contract.
     */
    address internal constant MULTICALLER_WITH_SIGNER = 0x000000000000D9ECebf3C23529de49815Dac1c4c;

    /**
     * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`.
     */
    function multicallerSender() internal view returns (address result) {
        return at(MULTICALLER_WITH_SENDER);
    }

    /**
     * @dev Returns the signer of `aggregateWithSigner` on `MULTICALLER_WITH_SIGNER`.
     */
    function multicallerSigner() internal view returns (address result) {
        return at(MULTICALLER_WITH_SIGNER);
    }

    /**
     * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`,
     *      if the current context's `msg.sender` is `MULTICALLER_WITH_SENDER`.
     *      Otherwise, returns `msg.sender`.
     */
    function sender() internal view returns (address result) {
        return resolve(MULTICALLER_WITH_SENDER);
    }

    /**
     * @dev Returns the caller of `aggregateWithSigner` on `MULTICALLER_WITH_SIGNER`,
     *      if the current context's `msg.sender` is `MULTICALLER_WITH_SIGNER`.
     *      Otherwise, returns `msg.sender`.
     */
    function signer() internal view returns (address) {
        return resolve(MULTICALLER_WITH_SIGNER);
    }

    /**
     * @dev Returns the caller or signer at `a`.
     * @param a The multicaller with sender / signer.
     */
    function at(address a) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x00)
            if iszero(staticcall(gas(), a, codesize(), 0x00, 0x00, 0x20)) {
                revert(codesize(), codesize()) // For better gas estimation.
            }
            result := mload(0x00)
        }
    }

    /**
     * @dev Returns the caller or signer at `a`, if the caller is `a`.
     * @param a The multicaller with sender / signer.
     */
    function resolve(address a) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, caller())
            if eq(caller(), a) {
                if iszero(staticcall(gas(), a, codesize(), 0x00, 0x00, 0x20)) {
                    revert(codesize(), codesize()) // For better gas estimation.
                }
            }
            result := mload(0x00)
        }
    }

    /**
     * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`,
     *      if the current context's `msg.sender` is `MULTICALLER_WITH_SENDER`.
     *      Returns the signer of `aggregateWithSigner` on `MULTICALLER_WITH_SIGNER`,
     *      if the current context's `msg.sender` is `MULTICALLER_WITH_SIGNER`.
     *      Otherwise, returns `msg.sender`.
     */
    function senderOrSigner() internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, caller())
            let withSender := MULTICALLER_WITH_SENDER
            if eq(caller(), withSender) {
                if iszero(staticcall(gas(), withSender, codesize(), 0x00, 0x00, 0x20)) {
                    revert(codesize(), codesize()) // For better gas estimation.
                }
            }
            let withSigner := MULTICALLER_WITH_SIGNER
            if eq(caller(), withSigner) {
                if iszero(staticcall(gas(), withSigner, codesize(), 0x00, 0x00, 0x20)) {
                    revert(codesize(), codesize()) // For better gas estimation.
                }
            }
            result := mload(0x00)
        }
    }
}
          

solady/src/tokens/ERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple ERC20 + EIP-2612 implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)
///
/// @dev Note:
/// - The ERC20 standard allows minting and transferring to and from the zero address,
///   minting and transferring zero tokens, as well as self-approvals.
///   For performance, this implementation WILL NOT revert for such actions.
///   Please add any checks with overrides if desired.
/// - The `permit` function uses the ecrecover precompile (0x1).
///
/// If you are overriding:
/// - NEVER violate the ERC20 invariant:
///   the total sum of all balances must be equal to `totalSupply()`.
/// - Check that the overridden function is actually used in the function you want to
///   change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC20 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The total supply has overflowed.
    error TotalSupplyOverflow();

    /// @dev The allowance has overflowed.
    error AllowanceOverflow();

    /// @dev The allowance has underflowed.
    error AllowanceUnderflow();

    /// @dev Insufficient balance.
    error InsufficientBalance();

    /// @dev Insufficient allowance.
    error InsufficientAllowance();

    /// @dev The permit is invalid.
    error InvalidPermit();

    /// @dev The permit has expired.
    error PermitExpired();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 amount);

    /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 private constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The storage slot for the total supply.
    uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;

    /// @dev The balance slot of `owner` is given by:
    /// ```
    ///     mstore(0x0c, _BALANCE_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let balanceSlot := keccak256(0x0c, 0x20)
    /// ```
    uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;

    /// @dev The allowance slot of (`owner`, `spender`) is given by:
    /// ```
    ///     mstore(0x20, spender)
    ///     mstore(0x0c, _ALLOWANCE_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let allowanceSlot := keccak256(0x0c, 0x34)
    /// ```
    uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;

    /// @dev The nonce slot of `owner` is given by:
    /// ```
    ///     mstore(0x0c, _NONCES_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let nonceSlot := keccak256(0x0c, 0x20)
    /// ```
    uint256 private constant _NONCES_SLOT_SEED = 0x38377508;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`.
    uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
    bytes32 private constant _DOMAIN_TYPEHASH =
        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    /// @dev `keccak256("1")`.
    bytes32 private constant _VERSION_HASH =
        0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;

    /// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`.
    bytes32 private constant _PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ERC20 METADATA                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the name of the token.
    function name() public view virtual returns (string memory);

    /// @dev Returns the symbol of the token.
    function symbol() public view virtual returns (string memory);

    /// @dev Returns the decimals places of the token.
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           ERC20                            */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the amount of tokens in existence.
    function totalSupply() public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_TOTAL_SUPPLY_SLOT)
        }
    }

    /// @dev Returns the amount of tokens owned by `owner`.
    function balanceOf(address owner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _BALANCE_SLOT_SEED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
    function allowance(address owner, address spender)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, spender)
            mstore(0x0c, _ALLOWANCE_SLOT_SEED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x34))
        }
    }

    /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
    ///
    /// Emits a {Approval} event.
    function approve(address spender, uint256 amount) public virtual returns (bool) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the allowance slot and store the amount.
            mstore(0x20, spender)
            mstore(0x0c, _ALLOWANCE_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x34), amount)
            // Emit the {Approval} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))
        }
        return true;
    }

    /// @dev Transfer `amount` tokens from the caller to `to`.
    ///
    /// Requirements:
    /// - `from` must at least have `amount`.
    ///
    /// Emits a {Transfer} event.
    function transfer(address to, uint256 amount) public virtual returns (bool) {
        _beforeTokenTransfer(msg.sender, to, amount);
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the balance slot and load its value.
            mstore(0x0c, _BALANCE_SLOT_SEED)
            mstore(0x00, caller())
            let fromBalanceSlot := keccak256(0x0c, 0x20)
            let fromBalance := sload(fromBalanceSlot)
            // Revert if insufficient balance.
            if gt(amount, fromBalance) {
                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                revert(0x1c, 0x04)
            }
            // Subtract and store the updated balance.
            sstore(fromBalanceSlot, sub(fromBalance, amount))
            // Compute the balance slot of `to`.
            mstore(0x00, to)
            let toBalanceSlot := keccak256(0x0c, 0x20)
            // Add and store the updated balance of `to`.
            // Will not overflow because the sum of all user balances
            // cannot exceed the maximum uint256 value.
            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
            // Emit the {Transfer} event.
            mstore(0x20, amount)
            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
        }
        _afterTokenTransfer(msg.sender, to, amount);
        return true;
    }

    /// @dev Transfers `amount` tokens from `from` to `to`.
    ///
    /// Note: Does not update the allowance if it is the maximum uint256 value.
    ///
    /// Requirements:
    /// - `from` must at least have `amount`.
    /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
        _beforeTokenTransfer(from, to, amount);
        /// @solidity memory-safe-assembly
        assembly {
            let from_ := shl(96, from)
            // Compute the allowance slot and load its value.
            mstore(0x20, caller())
            mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))
            let allowanceSlot := keccak256(0x0c, 0x34)
            let allowance_ := sload(allowanceSlot)
            // If the allowance is not the maximum uint256 value.
            if add(allowance_, 1) {
                // Revert if the amount to be transferred exceeds the allowance.
                if gt(amount, allowance_) {
                    mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated allowance.
                sstore(allowanceSlot, sub(allowance_, amount))
            }
            // Compute the balance slot and load its value.
            mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
            let fromBalanceSlot := keccak256(0x0c, 0x20)
            let fromBalance := sload(fromBalanceSlot)
            // Revert if insufficient balance.
            if gt(amount, fromBalance) {
                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                revert(0x1c, 0x04)
            }
            // Subtract and store the updated balance.
            sstore(fromBalanceSlot, sub(fromBalance, amount))
            // Compute the balance slot of `to`.
            mstore(0x00, to)
            let toBalanceSlot := keccak256(0x0c, 0x20)
            // Add and store the updated balance of `to`.
            // Will not overflow because the sum of all user balances
            // cannot exceed the maximum uint256 value.
            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
            // Emit the {Transfer} event.
            mstore(0x20, amount)
            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
        }
        _afterTokenTransfer(from, to, amount);
        return true;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          EIP-2612                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev For more performance, override to return the constant value
    /// of `keccak256(bytes(name()))` if `name()` will never change.
    function _constantNameHash() internal view virtual returns (bytes32 result) {}

    /// @dev Returns the current nonce for `owner`.
    /// This value is used to compute the signature for EIP-2612 permit.
    function nonces(address owner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the nonce slot and load its value.
            mstore(0x0c, _NONCES_SLOT_SEED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,
    /// authorized by a signed approval by `owner`.
    ///
    /// Emits a {Approval} event.
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        bytes32 nameHash = _constantNameHash();
        //  We simply calculate it on-the-fly to allow for cases where the `name` may change.
        if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
        /// @solidity memory-safe-assembly
        assembly {
            // Revert if the block timestamp is greater than `deadline`.
            if gt(timestamp(), deadline) {
                mstore(0x00, 0x1a15a3cc) // `PermitExpired()`.
                revert(0x1c, 0x04)
            }
            let m := mload(0x40) // Grab the free memory pointer.
            // Clean the upper 96 bits.
            owner := shr(96, shl(96, owner))
            spender := shr(96, shl(96, spender))
            // Compute the nonce slot and load its value.
            mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)
            mstore(0x00, owner)
            let nonceSlot := keccak256(0x0c, 0x20)
            let nonceValue := sload(nonceSlot)
            // Prepare the domain separator.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), nameHash)
            mstore(add(m, 0x40), _VERSION_HASH)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())
            mstore(0x2e, keccak256(m, 0xa0))
            // Prepare the struct hash.
            mstore(m, _PERMIT_TYPEHASH)
            mstore(add(m, 0x20), owner)
            mstore(add(m, 0x40), spender)
            mstore(add(m, 0x60), value)
            mstore(add(m, 0x80), nonceValue)
            mstore(add(m, 0xa0), deadline)
            mstore(0x4e, keccak256(m, 0xc0))
            // Prepare the ecrecover calldata.
            mstore(0x00, keccak256(0x2c, 0x42))
            mstore(0x20, and(0xff, v))
            mstore(0x40, r)
            mstore(0x60, s)
            let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)
            // If the ecrecover fails, the returndatasize will be 0x00,
            // `owner` will be checked if it equals the hash at 0x00,
            // which evaluates to false (i.e. 0), and we will revert.
            // If the ecrecover succeeds, the returndatasize will be 0x20,
            // `owner` will be compared against the returned address at 0x20.
            if iszero(eq(mload(returndatasize()), owner)) {
                mstore(0x00, 0xddafbaef) // `InvalidPermit()`.
                revert(0x1c, 0x04)
            }
            // Increment and store the updated nonce.
            sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds.
            // Compute the allowance slot and store the value.
            // The `owner` is already at slot 0x20.
            mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))
            sstore(keccak256(0x2c, 0x34), value)
            // Emit the {Approval} event.
            log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.
    function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {
        bytes32 nameHash = _constantNameHash();
        //  We simply calculate it on-the-fly to allow for cases where the `name` may change.
        if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Grab the free memory pointer.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), nameHash)
            mstore(add(m, 0x40), _VERSION_HASH)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())
            result := keccak256(m, 0xa0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL MINT FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Mints `amount` tokens to `to`, increasing the total supply.
    ///
    /// Emits a {Transfer} event.
    function _mint(address to, uint256 amount) internal virtual {
        _beforeTokenTransfer(address(0), to, amount);
        /// @solidity memory-safe-assembly
        assembly {
            let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)
            let totalSupplyAfter := add(totalSupplyBefore, amount)
            // Revert if the total supply overflows.
            if lt(totalSupplyAfter, totalSupplyBefore) {
                mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`.
                revert(0x1c, 0x04)
            }
            // Store the updated total supply.
            sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)
            // Compute the balance slot and load its value.
            mstore(0x0c, _BALANCE_SLOT_SEED)
            mstore(0x00, to)
            let toBalanceSlot := keccak256(0x0c, 0x20)
            // Add and store the updated balance.
            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
            // Emit the {Transfer} event.
            mstore(0x20, amount)
            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
        }
        _afterTokenTransfer(address(0), to, amount);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL BURN FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Burns `amount` tokens from `from`, reducing the total supply.
    ///
    /// Emits a {Transfer} event.
    function _burn(address from, uint256 amount) internal virtual {
        _beforeTokenTransfer(from, address(0), amount);
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the balance slot and load its value.
            mstore(0x0c, _BALANCE_SLOT_SEED)
            mstore(0x00, from)
            let fromBalanceSlot := keccak256(0x0c, 0x20)
            let fromBalance := sload(fromBalanceSlot)
            // Revert if insufficient balance.
            if gt(amount, fromBalance) {
                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                revert(0x1c, 0x04)
            }
            // Subtract and store the updated balance.
            sstore(fromBalanceSlot, sub(fromBalance, amount))
            // Subtract and store the updated total supply.
            sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))
            // Emit the {Transfer} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
        }
        _afterTokenTransfer(from, address(0), amount);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL TRANSFER FUNCTIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Moves `amount` of tokens from `from` to `to`.
    function _transfer(address from, address to, uint256 amount) internal virtual {
        _beforeTokenTransfer(from, to, amount);
        /// @solidity memory-safe-assembly
        assembly {
            let from_ := shl(96, from)
            // Compute the balance slot and load its value.
            mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
            let fromBalanceSlot := keccak256(0x0c, 0x20)
            let fromBalance := sload(fromBalanceSlot)
            // Revert if insufficient balance.
            if gt(amount, fromBalance) {
                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                revert(0x1c, 0x04)
            }
            // Subtract and store the updated balance.
            sstore(fromBalanceSlot, sub(fromBalance, amount))
            // Compute the balance slot of `to`.
            mstore(0x00, to)
            let toBalanceSlot := keccak256(0x0c, 0x20)
            // Add and store the updated balance of `to`.
            // Will not overflow because the sum of all user balances
            // cannot exceed the maximum uint256 value.
            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
            // Emit the {Transfer} event.
            mstore(0x20, amount)
            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
        }
        _afterTokenTransfer(from, to, amount);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL ALLOWANCE FUNCTIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Updates the allowance of `owner` for `spender` based on spent `amount`.
    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the allowance slot and load its value.
            mstore(0x20, spender)
            mstore(0x0c, _ALLOWANCE_SLOT_SEED)
            mstore(0x00, owner)
            let allowanceSlot := keccak256(0x0c, 0x34)
            let allowance_ := sload(allowanceSlot)
            // If the allowance is not the maximum uint256 value.
            if add(allowance_, 1) {
                // Revert if the amount to be transferred exceeds the allowance.
                if gt(amount, allowance_) {
                    mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated allowance.
                sstore(allowanceSlot, sub(allowance_, amount))
            }
        }
    }

    /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.
    ///
    /// Emits a {Approval} event.
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let owner_ := shl(96, owner)
            // Compute the allowance slot and store the amount.
            mstore(0x20, spender)
            mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))
            sstore(keccak256(0x0c, 0x34), amount)
            // Emit the {Approval} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HOOKS TO OVERRIDE                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Hook that is called before any transfer of tokens.
    /// This includes minting and burning.
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}

    /// @dev Hook that is called after any transfer of tokens.
    /// This includes minting and burning.
    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
          

solady/src/utils/EfficientHashLib.sol

// 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 {
    /// @dev Returns `keccak256(abi.encode(value0))`.
    function hash(bytes32 value0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, value0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0))`.
    function hash(uint256 value0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, value0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1))`.
    function hash(bytes32 value0, bytes32 value1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, value0)
            mstore(0x20, value1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1))`.
    function hash(uint256 value0, uint256 value1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, value0)
            mstore(0x20, value1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1, value2))`.
    function hash(bytes32 value0, bytes32 value1, bytes32 value2)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1, value2))`.
    function hash(uint256 value0, uint256 value1, uint256 value2)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1, value2, value3))`.
    function hash(bytes32 value0, bytes32 value1, bytes32 value2, bytes32 value3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1, value2, value3))`.
    function hash(uint256 value0, uint256 value1, uint256 value2, uint256 value3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value4))`.
    function hash(bytes32 value0, bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value4))`.
    function hash(uint256 value0, uint256 value1, uint256 value2, uint256 value3, uint256 value4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value5))`.
    function hash(
        bytes32 value0,
        bytes32 value1,
        bytes32 value2,
        bytes32 value3,
        bytes32 value4,
        bytes32 value5
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value5))`.
    function hash(
        uint256 value0,
        uint256 value1,
        uint256 value2,
        uint256 value3,
        uint256 value4,
        uint256 value5
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value6))`.
    function hash(
        bytes32 value0,
        bytes32 value1,
        bytes32 value2,
        bytes32 value3,
        bytes32 value4,
        bytes32 value5,
        bytes32 value6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            mstore(add(m, 0xc0), value6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value6))`.
    function hash(
        uint256 value0,
        uint256 value1,
        uint256 value2,
        uint256 value3,
        uint256 value4,
        uint256 value5,
        uint256 value6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            mstore(add(m, 0xc0), value6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value7))`.
    function hash(
        bytes32 value0,
        bytes32 value1,
        bytes32 value2,
        bytes32 value3,
        bytes32 value4,
        bytes32 value5,
        bytes32 value6,
        bytes32 value7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            mstore(add(m, 0xc0), value6)
            mstore(add(m, 0xe0), value7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value7))`.
    function hash(
        uint256 value0,
        uint256 value1,
        uint256 value2,
        uint256 value3,
        uint256 value4,
        uint256 value5,
        uint256 value6,
        uint256 value7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            mstore(add(m, 0xc0), value6)
            mstore(add(m, 0xe0), value7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(buffer[0], .., value[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)
        }
    }
}
          

solady/src/utils/LibPRNG.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for generating pseudorandom numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibPRNG.sol)
/// @author LazyShuffler based on NextShuffler by aschlosberg (divergencearran)
/// (https://github.com/divergencetech/ethier/blob/main/contracts/random/NextShuffler.sol)
library LibPRNG {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The initial length must be greater than zero and less than `2**32 - 1`.
    error InvalidInitialLazyShufflerLength();

    /// @dev The new length must not be less than the current length.
    error InvalidNewLazyShufflerLength();

    /// @dev The lazy shuffler has not been initialized.
    error LazyShufflerNotInitialized();

    /// @dev Cannot double initialize the lazy shuffler.
    error LazyShufflerAlreadyInitialized();

    /// @dev The lazy shuffle has finished.
    error LazyShuffleFinished();

    /// @dev The queried index is out of bounds.
    error LazyShufflerGetOutOfBounds();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The scalar of ETH and most ERC20s.
    uint256 internal constant WAD = 1e18;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev A pseudorandom number state in memory.
    struct PRNG {
        uint256 state;
    }

    /// @dev A lazy Fisher-Yates shuffler for a range `[0..n)` in storage.
    struct LazyShuffler {
        // Bits Layout:
        // - [0..31]    `numShuffled`
        // - [32..223]  `permutationSlot`
        // - [224..255] `length`
        uint256 _state;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         OPERATIONS                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Seeds the `prng` with `state`.
    function seed(PRNG memory prng, uint256 state) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(prng, state)
        }
    }

    /// @dev Returns the next pseudorandom uint256.
    /// All bits of the returned uint256 pass the NIST Statistical Test Suite.
    function next(PRNG memory prng) internal pure returns (uint256 result) {
        // We simply use `keccak256` for a great balance between
        // runtime gas costs, bytecode size, and statistical properties.
        //
        // A high-quality LCG with a 32-byte state
        // is only about 30% more gas efficient during runtime,
        // but requires a 32-byte multiplier, which can cause bytecode bloat
        // when this function is inlined.
        //
        // Using this method is about 2x more efficient than
        // `nextRandomness = uint256(keccak256(abi.encode(randomness)))`.
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(prng, 0x20)
            mstore(prng, result)
        }
    }

    /// @dev Returns a pseudorandom uint256, uniformly distributed
    /// between 0 (inclusive) and `upper` (exclusive).
    /// If your modulus is big, this method is recommended
    /// for uniform sampling to avoid modulo bias.
    /// For uniform sampling across all uint256 values,
    /// or for small enough moduli such that the bias is negligible,
    /// use {next} instead.
    function uniform(PRNG memory prng, uint256 upper) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                result := keccak256(prng, 0x20)
                mstore(prng, result)
                if iszero(lt(result, mod(sub(0, upper), upper))) { break }
            }
            result := mod(result, upper)
        }
    }

    /// @dev Returns a sample from the standard normal distribution denominated in `WAD`.
    function standardNormalWad(PRNG memory prng) internal pure returns (int256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Technically, this is the Irwin-Hall distribution with 20 samples.
            // The chance of drawing a sample outside 10 σ from the standard normal distribution
            // is ≈ 0.000000000000000000000015, which is insignificant for most practical purposes.
            // Passes the Kolmogorov-Smirnov test for 200k samples. Uses about 322 gas.
            result := keccak256(prng, 0x20)
            mstore(prng, result)
            let n := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43 // Prime.
            let a := 0x100000000000000000000000000000051 // Prime and a primitive root of `n`.
            let m := 0x1fffffffffffffff1fffffffffffffff1fffffffffffffff1fffffffffffffff
            let s := 0x1000000000000000100000000000000010000000000000001
            let r1 := mulmod(result, a, n)
            let r2 := mulmod(r1, a, n)
            let r3 := mulmod(r2, a, n)
            // forgefmt: disable-next-item
            result := sub(sar(96, mul(26614938895861601847173011183,
                add(add(shr(192, mul(s, add(and(m, result), and(m, r1)))),
                shr(192, mul(s, add(and(m, r2), and(m, r3))))),
                shr(192, mul(s, and(m, mulmod(r3, a, n))))))), 7745966692414833770)
        }
    }

    /// @dev Returns a sample from the unit exponential distribution denominated in `WAD`.
    function exponentialWad(PRNG memory prng) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Passes the Kolmogorov-Smirnov test for 200k samples.
            // Gas usage varies, starting from about 172+ gas.
            let r := keccak256(prng, 0x20)
            mstore(prng, r)
            let p := shl(129, r)
            let w := shl(1, r)
            if iszero(gt(w, p)) {
                let n := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43 // Prime.
                let a := 0x100000000000000000000000000000051 // Prime and a primitive root of `n`.
                for {} 1 {} {
                    r := mulmod(r, a, n)
                    if iszero(lt(shl(129, r), w)) {
                        r := mulmod(r, a, n)
                        result := add(1000000000000000000, result)
                        w := shl(1, r)
                        p := shl(129, r)
                        if iszero(lt(w, p)) { break }
                        continue
                    }
                    w := shl(1, r)
                    if iszero(lt(w, shl(129, r))) { break }
                }
            }
            result := add(div(p, shl(129, 170141183460469231732)), result)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*             MEMORY ARRAY SHUFFLING OPERATIONS              */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Shuffles the array in-place with Fisher-Yates shuffle.
    function shuffle(PRNG memory prng, uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a)
            let w := not(0)
            let mask := shr(128, w)
            if n {
                for { a := add(a, 0x20) } 1 {} {
                    // We can just directly use `keccak256`, cuz
                    // the other approaches don't save much.
                    let r := keccak256(prng, 0x20)
                    mstore(prng, r)

                    // Note that there will be a very tiny modulo bias
                    // if the length of the array is not a power of 2.
                    // For all practical purposes, it is negligible
                    // and will not be a fairness or security concern.
                    {
                        let j := add(a, shl(5, mod(shr(128, r), n)))
                        n := add(n, w) // `sub(n, 1)`.
                        if iszero(n) { break }

                        let i := add(a, shl(5, n))
                        let t := mload(i)
                        mstore(i, mload(j))
                        mstore(j, t)
                    }

                    {
                        let j := add(a, shl(5, mod(and(r, mask), n)))
                        n := add(n, w) // `sub(n, 1)`.
                        if iszero(n) { break }

                        let i := add(a, shl(5, n))
                        let t := mload(i)
                        mstore(i, mload(j))
                        mstore(j, t)
                    }
                }
            }
        }
    }

    /// @dev Shuffles the array in-place with Fisher-Yates shuffle.
    function shuffle(PRNG memory prng, int256[] memory a) internal pure {
        shuffle(prng, _toUints(a));
    }

    /// @dev Shuffles the array in-place with Fisher-Yates shuffle.
    function shuffle(PRNG memory prng, address[] memory a) internal pure {
        shuffle(prng, _toUints(a));
    }

    /// @dev Partially shuffles the array in-place with Fisher-Yates shuffle.
    /// The first `k` elements will be uniformly sampled without replacement.
    function shuffle(PRNG memory prng, uint256[] memory a, uint256 k) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a)
            k := xor(k, mul(xor(k, n), lt(n, k))) // `min(n, k)`.
            if k {
                let mask := shr(128, not(0))
                let b := 0
                for { a := add(a, 0x20) } 1 {} {
                    // We can just directly use `keccak256`, cuz
                    // the other approaches don't save much.
                    let r := keccak256(prng, 0x20)
                    mstore(prng, r)

                    // Note that there will be a very tiny modulo bias
                    // if the length of the array is not a power of 2.
                    // For all practical purposes, it is negligible
                    // and will not be a fairness or security concern.
                    {
                        let j := add(a, shl(5, add(b, mod(shr(128, r), sub(n, b)))))
                        let i := add(a, shl(5, b))
                        let t := mload(i)
                        mstore(i, mload(j))
                        mstore(j, t)
                        b := add(b, 1)
                        if eq(b, k) { break }
                    }

                    {
                        let j := add(a, shl(5, add(b, mod(and(r, mask), sub(n, b)))))
                        let i := add(a, shl(5, b))
                        let t := mload(i)
                        mstore(i, mload(j))
                        mstore(j, t)
                        b := add(b, 1)
                        if eq(b, k) { break }
                    }
                }
            }
        }
    }

    /// @dev Partially shuffles the array in-place with Fisher-Yates shuffle.
    /// The first `k` elements will be uniformly sampled without replacement.
    function shuffle(PRNG memory prng, int256[] memory a, uint256 k) internal pure {
        shuffle(prng, _toUints(a), k);
    }

    /// @dev Partially shuffles the array in-place with Fisher-Yates shuffle.
    /// The first `k` elements will be uniformly sampled without replacement.
    function shuffle(PRNG memory prng, address[] memory a, uint256 k) internal pure {
        shuffle(prng, _toUints(a), k);
    }

    /// @dev Shuffles the bytes in-place with Fisher-Yates shuffle.
    function shuffle(PRNG memory prng, bytes memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a)
            let w := not(0)
            let mask := shr(128, w)
            if n {
                let b := add(a, 0x01)
                for { a := add(a, 0x20) } 1 {} {
                    // We can just directly use `keccak256`, cuz
                    // the other approaches don't save much.
                    let r := keccak256(prng, 0x20)
                    mstore(prng, r)

                    // Note that there will be a very tiny modulo bias
                    // if the length of the array is not a power of 2.
                    // For all practical purposes, it is negligible
                    // and will not be a fairness or security concern.
                    {
                        let o := mod(shr(128, r), n)
                        n := add(n, w) // `sub(n, 1)`.
                        if iszero(n) { break }

                        let t := mload(add(b, n))
                        mstore8(add(a, n), mload(add(b, o)))
                        mstore8(add(a, o), t)
                    }

                    {
                        let o := mod(and(r, mask), n)
                        n := add(n, w) // `sub(n, 1)`.
                        if iszero(n) { break }

                        let t := mload(add(b, n))
                        mstore8(add(a, n), mload(add(b, o)))
                        mstore8(add(a, o), t)
                    }
                }
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*       STORAGE-BASED RANGE LAZY SHUFFLING OPERATIONS        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Initializes the state for lazy-shuffling the range `[0..n)`.
    /// Reverts if `n == 0 || n >= 2**32 - 1`.
    /// Reverts if `$` has already been initialized.
    /// If you need to reduce the length after initialization, just use a fresh new `$`.
    function initialize(LazyShuffler storage $, uint256 n) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(sub(n, 1), 0xfffffffe)) {
                mstore(0x00, 0x83b53941) // `InvalidInitialLazyShufflerLength()`.
                revert(0x1c, 0x04)
            }
            if sload($.slot) {
                mstore(0x00, 0x0c9f11f2) // `LazyShufflerAlreadyInitialized()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, $.slot)
            sstore($.slot, or(shl(224, n), shl(32, shr(64, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Increases the length of `$`.
    /// Reverts if `$` has not been initialized.
    function grow(LazyShuffler storage $, uint256 n) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let state := sload($.slot) // The packed value at `$`.
            // If the new length is smaller than the old length, revert.
            if lt(n, shr(224, state)) {
                mstore(0x00, 0xbed37c6e) // `InvalidNewLazyShufflerLength()`.
                revert(0x1c, 0x04)
            }
            if iszero(state) {
                mstore(0x00, 0x1ead2566) // `LazyShufflerNotInitialized()`.
                revert(0x1c, 0x04)
            }
            sstore($.slot, or(shl(224, n), shr(32, shl(32, state))))
        }
    }

    /// @dev Restarts the shuffler by setting `numShuffled` to zero,
    /// such that all elements can be drawn again.
    /// Restarting does NOT clear the internal permutation, nor changes the length.
    /// Even with the same sequence of randomness, reshuffling can yield different results.
    function restart(LazyShuffler storage $) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let state := sload($.slot)
            if iszero(state) {
                mstore(0x00, 0x1ead2566) // `LazyShufflerNotInitialized()`.
                revert(0x1c, 0x04)
            }
            sstore($.slot, shl(32, shr(32, state)))
        }
    }

    /// @dev Returns the number of elements that have been shuffled.
    function numShuffled(LazyShuffler storage $) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(0xffffffff, sload($.slot))
        }
    }

    /// @dev Returns the length of `$`.
    /// Returns zero if `$` is not initialized, else a non-zero value less than `2**32 - 1`.
    function length(LazyShuffler storage $) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := shr(224, sload($.slot))
        }
    }

    /// @dev Returns if `$` has been initialized.
    function initialized(LazyShuffler storage $) internal view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(iszero(sload($.slot)))
        }
    }

    /// @dev Returns if there are any more elements left to shuffle.
    /// Reverts if `$` is not initialized.
    function finished(LazyShuffler storage $) internal view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let state := sload($.slot) // The packed value at `$`.
            if iszero(state) {
                mstore(0x00, 0x1ead2566) // `LazyShufflerNotInitialized()`.
                revert(0x1c, 0x04)
            }
            result := eq(shr(224, state), and(0xffffffff, state))
        }
    }

    /// @dev Returns the current value stored at `index`, accounting for all historical shuffling.
    /// Reverts if `index` is greater than or equal to the `length` of `$`.
    function get(LazyShuffler storage $, uint256 index) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let state := sload($.slot) // The packed value at `$`.
            let n := shr(224, state) // Length of `$`.
            if iszero(lt(index, n)) {
                mstore(0x00, 0x61367cc4) // `LazyShufflerGetOutOfBounds()`.
                revert(0x1c, 0x04)
            }
            let u32 := gt(n, 0xfffe)
            let s := add(shr(sub(4, u32), index), shr(64, shl(32, state))) // Bucket slot.
            let o := shl(add(4, u32), and(index, shr(u32, 15))) // Bucket slot offset (bits).
            let m := sub(shl(shl(u32, 16), 1), 1) // Value mask.
            result := and(m, shr(o, sload(s)))
            result := xor(index, mul(xor(index, sub(result, 1)), iszero(iszero(result))))
        }
    }

    /// @dev Does a single Fisher-Yates shuffle step, increments the `numShuffled` in `$`,
    /// and returns the next value in the shuffled range.
    /// `randomness` can be taken from a good-enough source, or a higher quality source like VRF.
    /// Reverts if there are no more values to shuffle, which includes the case if `$` is not initialized.
    function next(LazyShuffler storage $, uint256 randomness) internal returns (uint256 chosen) {
        /// @solidity memory-safe-assembly
        assembly {
            function _get(u32_, state_, i_) -> _value {
                let s_ := add(shr(sub(4, u32_), i_), shr(64, shl(32, state_))) // Bucket slot.
                let o_ := shl(add(4, u32_), and(i_, shr(u32_, 15))) // Bucket slot offset (bits).
                let m_ := sub(shl(shl(u32_, 16), 1), 1) // Value mask.
                _value := and(m_, shr(o_, sload(s_)))
                _value := xor(i_, mul(xor(i_, sub(_value, 1)), iszero(iszero(_value))))
            }
            function _set(u32_, state_, i_, value_) {
                let s_ := add(shr(sub(4, u32_), i_), shr(64, shl(32, state_))) // Bucket slot.
                let o_ := shl(add(4, u32_), and(i_, shr(u32_, 15))) // Bucket slot offset (bits).
                let m_ := sub(shl(shl(u32_, 16), 1), 1) // Value mask.
                let v_ := sload(s_) // Bucket slot value.
                value_ := mul(iszero(eq(i_, value_)), add(value_, 1))
                sstore(s_, xor(v_, shl(o_, and(m_, xor(shr(o_, v_), value_)))))
            }
            let state := sload($.slot) // The packed value at `$`.
            let shuffled := and(0xffffffff, state) // Number of elements shuffled.
            let n := shr(224, state) // Length of `$`.
            let remainder := sub(n, shuffled) // Number of elements left to shuffle.
            if iszero(remainder) {
                mstore(0x00, 0x51065f79) // `LazyShuffleFinished()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, randomness) // (Re)hash the randomness so that we don't
            mstore(0x20, shuffled) // need to expect guarantees on its distribution.
            let index := add(mod(keccak256(0x00, 0x40), remainder), shuffled)
            chosen := _get(gt(n, 0xfffe), state, index)
            _set(gt(n, 0xfffe), state, index, _get(gt(n, 0xfffe), state, shuffled))
            _set(gt(n, 0xfffe), state, shuffled, chosen)
            sstore($.slot, add(1, state)) // Increment the `numShuffled` by 1, and store it.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Reinterpret cast to an uint256 array.
    function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Reinterpret cast to an uint256 array.
    function _toUints(address[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            // As any address written to memory will have the upper 96 bits
            // of the word zeroized (as per Solidity spec), we can directly
            // compare these addresses as if they are whole uint256 words.
            casted := a
        }
    }
}
          

solady/src/utils/SSTORE2.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SSTORE2.sol)
/// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
/// @author Modified from SSTORE3 (https://github.com/Philogy/sstore3)
library SSTORE2 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The proxy initialization code.
    uint256 private constant _CREATE3_PROXY_INITCODE = 0x67363d3d37363d34f03d5260086018f3;

    /// @dev Hash of the `_CREATE3_PROXY_INITCODE`.
    /// Equivalent to `keccak256(abi.encodePacked(hex"67363d3d37363d34f03d5260086018f3"))`.
    bytes32 internal constant CREATE3_PROXY_INITCODE_HASH =
        0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unable to deploy the storage contract.
    error DeploymentFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         WRITE LOGIC                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Writes `data` into the bytecode of a storage contract and returns its address.
    function write(bytes memory data) internal returns (address pointer) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(data) // Let `l` be `n + 1`. +1 as we prefix a STOP opcode.
            /**
             * ---------------------------------------------------+
             * Opcode | Mnemonic       | Stack     | Memory       |
             * ---------------------------------------------------|
             * 61 l   | PUSH2 l        | l         |              |
             * 80     | DUP1           | l l       |              |
             * 60 0xa | PUSH1 0xa      | 0xa l l   |              |
             * 3D     | RETURNDATASIZE | 0 0xa l l |              |
             * 39     | CODECOPY       | l         | [0..l): code |
             * 3D     | RETURNDATASIZE | 0 l       | [0..l): code |
             * F3     | RETURN         |           | [0..l): code |
             * 00     | STOP           |           |              |
             * ---------------------------------------------------+
             * @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called.
             * Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16.
             */
            // Do a out-of-gas revert if `n + 1` is more than 2 bytes.
            mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n)))
            // Deploy a new contract with the generated creation code.
            pointer := create(0, add(data, 0x15), add(n, 0xb))
            if iszero(pointer) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(data, n) // Restore the length of `data`.
        }
    }

    /// @dev Writes `data` into the bytecode of a storage contract with `salt`
    /// and returns its normal CREATE2 deterministic address.
    function writeCounterfactual(bytes memory data, bytes32 salt)
        internal
        returns (address pointer)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(data)
            // Do a out-of-gas revert if `n + 1` is more than 2 bytes.
            mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n)))
            // Deploy a new contract with the generated creation code.
            pointer := create2(0, add(data, 0x15), add(n, 0xb), salt)
            if iszero(pointer) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(data, n) // Restore the length of `data`.
        }
    }

    /// @dev Writes `data` into the bytecode of a storage contract and returns its address.
    /// This uses the so-called "CREATE3" workflow,
    /// which means that `pointer` is agnostic to `data, and only depends on `salt`.
    function writeDeterministic(bytes memory data, bytes32 salt)
        internal
        returns (address pointer)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(data)
            mstore(0x00, _CREATE3_PROXY_INITCODE) // Store the `_PROXY_INITCODE`.
            let proxy := create2(0, 0x10, 0x10, salt)
            if iszero(proxy) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, proxy) // Store the proxy's address.
            // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01).
            // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex).
            mstore(0x00, 0xd694)
            mstore8(0x34, 0x01) // Nonce of the proxy contract (1).
            pointer := keccak256(0x1e, 0x17)

            // Do a out-of-gas revert if `n + 1` is more than 2 bytes.
            mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n)))
            if iszero(
                mul( // The arguments of `mul` are evaluated last to first.
                    extcodesize(pointer),
                    call(gas(), proxy, 0, add(data, 0x15), add(n, 0xb), codesize(), 0x00)
                )
            ) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(data, n) // Restore the length of `data`.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    ADDRESS CALCULATIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the initialization code hash of the storage contract for `data`.
    /// Used for mining vanity addresses with create2crunch.
    function initCodeHash(bytes memory data) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(data)
            // Do a out-of-gas revert if `n + 1` is more than 2 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xfffe))
            mstore(data, add(0x61000180600a3d393df300, shl(0x40, n)))
            hash := keccak256(add(data, 0x15), add(n, 0xb))
            mstore(data, n) // Restore the length of `data`.
        }
    }

    /// @dev Equivalent to `predictCounterfactualAddress(data, salt, address(this))`
    function predictCounterfactualAddress(bytes memory data, bytes32 salt)
        internal
        view
        returns (address pointer)
    {
        pointer = predictCounterfactualAddress(data, salt, address(this));
    }

    /// @dev Returns the CREATE2 address of the storage contract for `data`
    /// deployed with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictCounterfactualAddress(bytes memory data, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        bytes32 hash = initCodeHash(data);
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, hash)
            mstore(0x01, shl(96, deployer))
            mstore(0x15, salt)
            predicted := keccak256(0x00, 0x55)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x35, 0)
        }
    }

    /// @dev Equivalent to `predictDeterministicAddress(salt, address(this))`.
    function predictDeterministicAddress(bytes32 salt) internal view returns (address pointer) {
        pointer = predictDeterministicAddress(salt, address(this));
    }

    /// @dev Returns the "CREATE3" deterministic address for `salt` with `deployer`.
    function predictDeterministicAddress(bytes32 salt, address deployer)
        internal
        pure
        returns (address pointer)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, deployer) // Store `deployer`.
            mstore8(0x0b, 0xff) // Store the prefix.
            mstore(0x20, salt) // Store the salt.
            mstore(0x40, CREATE3_PROXY_INITCODE_HASH) // Store the bytecode hash.

            mstore(0x14, keccak256(0x0b, 0x55)) // Store the proxy's address.
            mstore(0x40, m) // Restore the free memory pointer.
            // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01).
            // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex).
            mstore(0x00, 0xd694)
            mstore8(0x34, 0x01) // Nonce of the proxy contract (1).
            pointer := keccak256(0x1e, 0x17)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         READ LOGIC                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `read(pointer, 0, 2 ** 256 - 1)`.
    function read(address pointer) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            data := mload(0x40)
            let n := and(sub(extcodesize(pointer), 0x01), 0xffffffffff)
            extcodecopy(pointer, add(data, 0x1f), 0x00, add(n, 0x21))
            mstore(data, n) // Store the length.
            mstore(0x40, add(n, add(data, 0x40))) // Allocate memory.
        }
    }

    /// @dev Equivalent to `read(pointer, start, 2 ** 256 - 1)`.
    function read(address pointer, uint256 start) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            data := mload(0x40)
            let n := and(sub(extcodesize(pointer), 0x01), 0xffffffffff)
            extcodecopy(pointer, add(data, 0x1f), start, add(n, 0x21))
            mstore(data, mul(sub(n, start), lt(start, n))) // Store the length.
            mstore(0x40, add(data, add(0x40, mload(data)))) // Allocate memory.
        }
    }

    /// @dev Returns the a slice of the data on `pointer` from `start` to `end`.
    /// `start` and `end` will be clamped to the range `[0, args.length]`.
    /// The `pointer` MUST be deployed via the SSTORE2 write functions.
    /// Otherwise, the behavior is undefined.
    /// Out-of-gas reverts if `pointer` does not have any code.
    function read(address pointer, uint256 start, uint256 end)
        internal
        view
        returns (bytes memory data)
    {
        /// @solidity memory-safe-assembly
        assembly {
            data := mload(0x40)
            let d := and(0xffff, sub(end, start))
            extcodecopy(pointer, add(data, 0x1f), start, add(d, 0x01))
            if iszero(and(0xff, mload(add(data, d)))) {
                let n := sub(extcodesize(pointer), 0x01)
                returndatacopy(returndatasize(), returndatasize(), shr(64, n))
                d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n))))
            }
            mstore(data, mul(d, lt(start, end))) // Store the length.
            mstore(add(add(data, 0x20), d), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(data, 0x40), d)) // Allocate memory.
        }
    }
}
          

Compiler Settings

{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":false},"libraries":{},"evmVersion":"cancun"}
              

Contract ABI

[{"type":"constructor","stateMutability":"payable","inputs":[{"type":"address","name":"_rand","internalType":"address"}]},{"type":"error","name":"Misconfigured","inputs":[]},{"type":"error","name":"SecretMismatch","inputs":[]},{"type":"event","name":"Chain","inputs":[{"type":"bytes32","name":"owner","internalType":"bytes32","indexed":true},{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Reveal","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"bytes32","name":"formerSecret","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Undermine","inputs":[{"type":"uint256","name":"id","internalType":"uint256","indexed":false},{"type":"bytes32","name":"preimage","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"id","internalType":"uint256"}],"name":"chain","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"bool","name":"onlySameTx","internalType":"bool"},{"type":"bool","name":"underminable","internalType":"bool"},{"type":"bytes32","name":"preimage","internalType":"bytes32"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"chainTo","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"bool","name":"underminable","internalType":"bool"},{"type":"bytes32","name":"preimage","internalType":"bytes32"},{"type":"bytes32","name":"key","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"l","internalType":"struct Consumer.Link","components":[{"type":"uint256","name":"id","internalType":"uint256"},{"type":"address","name":"owner","internalType":"address"},{"type":"bool","name":"underminable","internalType":"bool"},{"type":"bytes32","name":"key","internalType":"bytes32"},{"type":"bytes32","name":"preimage","internalType":"bytes32"},{"type":"bytes32","name":"revealed","internalType":"bytes32"}]}],"name":"link","inputs":[{"type":"uint256","name":"idParam","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tell","inputs":[{"type":"uint256","name":"id","internalType":"uint256"},{"type":"bytes32","name":"revealedSecret","internalType":"bytes32"}]}]
              

Contract Creation Code

0x60c060405261001461000f610106565b61017c565b61001c61004a565b6112e16101b382396080518161111e015260a05181818161056b015281816108ef015261096901526112e190f35b60405190565b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061007890610050565b810190811060018060401b0382111761009057604052565b61005a565b906100a86100a161004a565b928361006e565b565b5f80fd5b60018060a01b031690565b6100c2906100ae565b90565b6100ce816100b9565b036100d557565b5f80fd5b905051906100e6826100c5565b565b90602082820312610101576100fe915f016100d9565b90565b6100aa565b6101246114948038038061011981610095565b9283398101906100e8565b90565b90565b90565b90565b61014461013f61014992610127565b61012d565b61012a565b90565b6101555f610130565b90565b90565b5f1b90565b61017461016f6101799261012a565b61015b565b610158565b90565b60a05261019761019261018d61014c565b610160565b6101a0565b608052565b5f90565b6101a861019c565b505f5260205f209056fe60806040526004361015610013575b6103ec565b61001d5f3561006c565b806342833289146100675780634bfbbe0b1461006257806377b146a51461005d5780637fbf5db0146100585763b1a867d50361000e576103b7565b6102b0565b61022c565b6101b1565b61016f565b60e01c90565b60405190565b5f80fd5b60018060a01b031690565b6100909061007c565b90565b61009c81610087565b036100a357565b5f80fd5b905035906100b482610093565b565b151590565b6100c4816100b6565b036100cb57565b5f80fd5b905035906100dc826100bb565b565b90565b6100ea816100de565b036100f157565b5f80fd5b90503590610102826100e1565b565b6080818303126101455761011a825f83016100a7565b9261014261012b84602085016100cf565b9361013981604086016100cf565b936060016100f5565b90565b610078565b90565b6101569061014a565b9052565b919061016d905f6020850194019061014d565b565b61019a610189610180366004610104565b92919091610556565b610191610072565b9182918261015a565b0390f35b5f80fd5b5f9103126101ac57565b610078565b346101e1576101c13660046101a2565b6101dd6101cc610692565b6101d4610072565b9182918261015a565b0390f35b61019e565b608081830312610227576101fc825f83016100a7565b9261022461020d84602085016100cf565b9361021b81604086016100f5565b936060016100f5565b90565b610078565b61025761024661023d3660046101e6565b929190916106a7565b61024e610072565b9182918261015a565b0390f35b6102648161014a565b0361026b57565b5f80fd5b9050359061027c8261025b565b565b91906040838203126102a6578061029a6102a3925f860161026f565b936020016100f5565b90565b610078565b5f0190565b346102df576102c96102c336600461027e565b90610881565b6102d1610072565b806102db816102ab565b0390f35b61019e565b906020828203126102fd576102fa915f0161026f565b90565b610078565b61030b9061014a565b9052565b61031890610087565b9052565b610325906100b6565b9052565b610332906100de565b9052565b9060a0806103a09361034e5f8201515f860190610302565b6103606020820151602086019061030f565b6103726040820151604086019061031c565b61038460608201516060860190610329565b61039660808201516080860190610329565b0151910190610329565b565b91906103b5905f60c08501940190610336565b565b346103e7576103e36103d26103cd3660046102e4565b610ccd565b6103da610072565b918291826103a2565b0390f35b61019e565b5f80fd5b5f90565b90565b61040b6104066104109261007c565b6103f4565b61007c565b90565b61041c906103f7565b90565b61042890610413565b90565b610434906103f7565b90565b6104409061042b565b90565b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061046b90610443565b810190811067ffffffffffffffff82111761048557604052565b61044d565b60e01b90565b9050519061049d826100e1565b565b906020828203126104b8576104b5915f01610490565b90565b610078565b6104c690610087565b9052565b6104d3906100b6565b9052565b9160206104f89294936104f160408201965f8301906104bd565b01906104ca565b565b610502610072565b3d5f823e3d90fd5b90565b61052161051c6105269261050a565b6103f4565b61014a565b90565b6105325f61050d565b90565b5f1b90565b61054e6105496105539261014a565b610535565b6100de565b90565b906020906105626103f0565b5061059461058f7f000000000000000000000000000000000000000000000000000000000000000061041f565b610437565b6105b6638492c30b9492946105c16105aa610072565b9687958694859461048a565b8452600484016104d7565b03915afa908115610664575f91610636575b50806105f66105f06105eb6105e6610529565b61053a565b6100de565b916100de565b146106135761061092610607610e08565b92909192610f3d565b90565b61061b610072565b6321f9f13f60e11b815280610632600482016102ab565b0390fd5b610657915060203d811161065d575b61064f8183610461565b81019061049f565b5f6105d3565b503d610645565b6104fa565b5f1c90565b90565b61067d61068291610669565b61066e565b90565b61068f9054610671565b90565b61069a6103f0565b506106a45f610685565b90565b916106c09391926106b66103f0565b5092909192610f3d565b90565b6106d76106d26106dc9261014a565b6103f4565b61014a565b90565b906106e9906106c3565b5f5260205260405f2090565b90565b61070461070991610669565b6106f5565b90565b61071690546106f8565b90565b610722906100de565b90565b9061072f90610719565b5f5260205260405f2090565b5f80fd5b9061075261074b610072565b9283610461565b565b905051906107618261025b565b565b919060408382031261079d576107969061077d604061073f565b9361078a825f8301610754565b5f860152602001610490565b6020830152565b61073b565b906040828203126107bb576107b8915f01610763565b90565b610078565b6107c9906100de565b9052565b91906107e0905f602085019401906107c0565b565b6107ec905161014a565b90565b905051906107fc826100bb565b565b9060208282031261081757610814915f016107ef565b90565b610078565b906108285f1991610535565b9181191691161790565b61083b90610669565b90565b9061085361084e61085a92610719565b610832565b825461081c565b9055565b91602061087f92949361087860408201965f83019061014d565b01906107c0565b565b6108a86108a3600161089d610898600486906106df565b61070c565b90610725565b61070c565b6108c96108c36108be6108b9610529565b61053a565b6100de565b916100de565b03610af85761093f60406108e76108e2600585906106df565b61070c565b6109186109137f000000000000000000000000000000000000000000000000000000000000000061041f565b610437565b610934630cf9dff7610928610072565b9586948593849361048a565b8352600483016107cd565b03915afa908115610af3575f91610ac5575b5061095b83611152565b906109c6602061099261098d7f000000000000000000000000000000000000000000000000000000000000000061041f565b610437565b63ba065e1f906109bb6109a65f87016107e2565b926109af610072565b9586948593849361048a565b83526004830161015a565b03915afa908115610ac0575f91610a92575b50610a7e575b5080610a056109ff6109fa6109f5600487906106df565b61070c565b6100de565b916100de565b03610a5b57610a1f90610a1a84916001610725565b61083e565b907f517252ac860052b1823fd92961e2f6d30a8d2bb826f16e4a6f982160e21928cb91610a56610a4d610072565b9283928361085e565b0390a1565b610a63610072565b63162c5b6560e01b815280610a7a600482016102ab565b0390fd5b610a8c908390839091611185565b5f6109de565b610ab3915060203d8111610ab9575b610aab8183610461565b8101906107fe565b5f6109d8565b503d610aa1565b6104fa565b610ae6915060403d8111610aec575b610ade8183610461565b8101906107a2565b5f610951565b503d610ad4565b6104fa565b5050565b610b0660c061073f565b90565b5f90565b5f90565b5f90565b5f90565b610b21610afc565b906020808080808087610b32610b09565b815201610b3d610b0d565b815201610b48610b11565b815201610b53610b15565b815201610b5e610b15565b815201610b69610b15565b81525050565b610b77610b19565b90565b90565b610b91610b8c610b9692610b7a565b6103f4565b61014a565b90565b610ba36060610b7d565b90565b1b90565b610bc990610bc3610bbd610bce9461014a565b916100de565b90610ba6565b6100de565b90565b6bffffffffffffffffffffffff191690565b610bec90610bd1565b90565b60601c90565b610c01610c0691610bef565b6103f7565b90565b610c1290610bf5565b90565b90565b610c2c610c27610c3192610c15565b6103f4565b61014a565b90565b610c3e60a0610c18565b90565b1c90565b610c6490610c5e610c58610c699461014a565b916100de565b90610c41565b6100de565b90565b610c80610c7b610c859261050a565b610535565b6100de565b90565b610c9260c061073f565b90565b90610c9f9061014a565b9052565b90610cad90610087565b9052565b90610cbb906100b6565b9052565b90610cc9906100de565b9052565b610cd5610b6f565b90610cea610ce5600583906106df565b61070c565b9182610d0d610d07610d02610cfd610529565b61053a565b6100de565b916100de565b14610dfe5750610df190610de8610d2e610d29600484906106df565b61070c565b610ddf610d45610d40600386906106df565b61070c565b9395610d7b610d6c610d67610d6288610d5c610b99565b90610baa565b610be3565b610c09565b95610d75610c34565b90610c45565b610d8d610d875f610c6c565b916100de565b145f14610df457610dd65f5b610dcd610daf610daa876001610725565b61070c565b97610dc4610dbb610c88565b9b5f8d01610c95565b60208b01610ca3565b60408901610cb1565b60608701610cbf565b60808501610cbf565b60a08301610cbf565b90565b610dd66001610d99565b91505090565b5f90565b610e10610e04565b50335f526e2fd5aeb385d324b580fca7c83823a0803314610e62575b506dd9ecebf3c23529de49815dac1c4c803314610e4a575b505f5190565b5f8060209238905afa15610e5e575f610e44565b3838fd5b5f8060209238905afa15610e76575f610e2c565b3838fd5b90610e8490610719565b5f5260205260405f2090565b90565b610ea7610ea2610eac92610e90565b6103f4565b61014a565b90565b610eb96001610e93565b90565b610edb90610ed5610ecf610ee09461014a565b9161014a565b90610ba6565b61014a565b90565b610eec906103f7565b90565b610f03610efe610f089261007c565b6103f4565b61014a565b90565b6001610f17910161014a565b90565b90565b90610f32610f2d610f39926106c3565b610f1a565b825461081c565b9055565b93929193610f496103f0565b5084610f6c610f66610f61610f5c610529565b61053a565b6100de565b916100de565b148015611114575b6110f157610fc890610f90610f8b60028890610e7a565b610685565b925f146110de57610fc2610fbd610fb6610fa8610eaf565b610fb0610c34565b90610ebc565b5b92610ee3565b610eef565b1761053a565b90610fdd610fd8600483906106df565b61070c565b610fef610fe9876100de565b916100de565b146110ab575b5061106561100a6110055f610685565b610f0b565b611014815f610f1d565b9461102a83611025600389906106df565b61083e565b61103f8161103a600489906106df565b61083e565b6110548461104f600589906106df565b61083e565b61106086916002610e7a565b610f1d565b83916110917f7e0786ff457ce0bc5e3f599bcc220605e18c56cd9ebed35182b29397697ea46c92610719565b926110a661109d610072565b9283928361085e565b0390a2565b6110bf6110ba600383906106df565b61070c565b6110d16110cb846100de565b916100de565b03610ff557929350505090565b610fc2610fbd6110ec610529565b610fb7565b6110f9610072565b6321f9f13f60e11b815280611110600482016102ab565b0390fd5b50846111486111427f00000000000000000000000000000000000000000000000000000000000000006100de565b916100de565b14610f74565b5f90565b61115a61114e565b505f5260205f2090565b61116e90516100de565b90565b61117d61118291610669565b6106c3565b90565b909160206111939101611164565b6111b46111ae6111a96111a4610529565b61053a565b6100de565b916100de565b146112a757816111df6111d96111d46111cf600486906106df565b61070c565b6100de565b916100de565b146112a35761121161120c6111fe6111f9600385906106df565b61070c565b611206610c34565b90610c45565b611171565b61122a61122461121f610529565b61014a565b9161014a565b146112805761127961127e9282817fbe48847c637d143d69ac15740d39544624cdfa8d4f6ce738ecf3e35085c1f4d69161126e611265610072565b9283928361085e565b0390a19160046106df565b61083e565b565b611288610072565b6321f9f13f60e11b81528061129f600482016102ab565b0390fd5b5050565b505056fea2646970667358221220a6869c4056bb23e25f4131c65282fce5515f77a57e87fe753a4745a011e1b6b064736f6c6343000819003300000000000000000000000080493d07ddfce7a8b507c407459935a88c62ad8e

Deployed ByteCode

0x60806040526004361015610013575b6103ec565b61001d5f3561006c565b806342833289146100675780634bfbbe0b1461006257806377b146a51461005d5780637fbf5db0146100585763b1a867d50361000e576103b7565b6102b0565b61022c565b6101b1565b61016f565b60e01c90565b60405190565b5f80fd5b60018060a01b031690565b6100909061007c565b90565b61009c81610087565b036100a357565b5f80fd5b905035906100b482610093565b565b151590565b6100c4816100b6565b036100cb57565b5f80fd5b905035906100dc826100bb565b565b90565b6100ea816100de565b036100f157565b5f80fd5b90503590610102826100e1565b565b6080818303126101455761011a825f83016100a7565b9261014261012b84602085016100cf565b9361013981604086016100cf565b936060016100f5565b90565b610078565b90565b6101569061014a565b9052565b919061016d905f6020850194019061014d565b565b61019a610189610180366004610104565b92919091610556565b610191610072565b9182918261015a565b0390f35b5f80fd5b5f9103126101ac57565b610078565b346101e1576101c13660046101a2565b6101dd6101cc610692565b6101d4610072565b9182918261015a565b0390f35b61019e565b608081830312610227576101fc825f83016100a7565b9261022461020d84602085016100cf565b9361021b81604086016100f5565b936060016100f5565b90565b610078565b61025761024661023d3660046101e6565b929190916106a7565b61024e610072565b9182918261015a565b0390f35b6102648161014a565b0361026b57565b5f80fd5b9050359061027c8261025b565b565b91906040838203126102a6578061029a6102a3925f860161026f565b936020016100f5565b90565b610078565b5f0190565b346102df576102c96102c336600461027e565b90610881565b6102d1610072565b806102db816102ab565b0390f35b61019e565b906020828203126102fd576102fa915f0161026f565b90565b610078565b61030b9061014a565b9052565b61031890610087565b9052565b610325906100b6565b9052565b610332906100de565b9052565b9060a0806103a09361034e5f8201515f860190610302565b6103606020820151602086019061030f565b6103726040820151604086019061031c565b61038460608201516060860190610329565b61039660808201516080860190610329565b0151910190610329565b565b91906103b5905f60c08501940190610336565b565b346103e7576103e36103d26103cd3660046102e4565b610ccd565b6103da610072565b918291826103a2565b0390f35b61019e565b5f80fd5b5f90565b90565b61040b6104066104109261007c565b6103f4565b61007c565b90565b61041c906103f7565b90565b61042890610413565b90565b610434906103f7565b90565b6104409061042b565b90565b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061046b90610443565b810190811067ffffffffffffffff82111761048557604052565b61044d565b60e01b90565b9050519061049d826100e1565b565b906020828203126104b8576104b5915f01610490565b90565b610078565b6104c690610087565b9052565b6104d3906100b6565b9052565b9160206104f89294936104f160408201965f8301906104bd565b01906104ca565b565b610502610072565b3d5f823e3d90fd5b90565b61052161051c6105269261050a565b6103f4565b61014a565b90565b6105325f61050d565b90565b5f1b90565b61054e6105496105539261014a565b610535565b6100de565b90565b906020906105626103f0565b5061059461058f7f00000000000000000000000080493d07ddfce7a8b507c407459935a88c62ad8e61041f565b610437565b6105b6638492c30b9492946105c16105aa610072565b9687958694859461048a565b8452600484016104d7565b03915afa908115610664575f91610636575b50806105f66105f06105eb6105e6610529565b61053a565b6100de565b916100de565b146106135761061092610607610e08565b92909192610f3d565b90565b61061b610072565b6321f9f13f60e11b815280610632600482016102ab565b0390fd5b610657915060203d811161065d575b61064f8183610461565b81019061049f565b5f6105d3565b503d610645565b6104fa565b5f1c90565b90565b61067d61068291610669565b61066e565b90565b61068f9054610671565b90565b61069a6103f0565b506106a45f610685565b90565b916106c09391926106b66103f0565b5092909192610f3d565b90565b6106d76106d26106dc9261014a565b6103f4565b61014a565b90565b906106e9906106c3565b5f5260205260405f2090565b90565b61070461070991610669565b6106f5565b90565b61071690546106f8565b90565b610722906100de565b90565b9061072f90610719565b5f5260205260405f2090565b5f80fd5b9061075261074b610072565b9283610461565b565b905051906107618261025b565b565b919060408382031261079d576107969061077d604061073f565b9361078a825f8301610754565b5f860152602001610490565b6020830152565b61073b565b906040828203126107bb576107b8915f01610763565b90565b610078565b6107c9906100de565b9052565b91906107e0905f602085019401906107c0565b565b6107ec905161014a565b90565b905051906107fc826100bb565b565b9060208282031261081757610814915f016107ef565b90565b610078565b906108285f1991610535565b9181191691161790565b61083b90610669565b90565b9061085361084e61085a92610719565b610832565b825461081c565b9055565b91602061087f92949361087860408201965f83019061014d565b01906107c0565b565b6108a86108a3600161089d610898600486906106df565b61070c565b90610725565b61070c565b6108c96108c36108be6108b9610529565b61053a565b6100de565b916100de565b03610af85761093f60406108e76108e2600585906106df565b61070c565b6109186109137f00000000000000000000000080493d07ddfce7a8b507c407459935a88c62ad8e61041f565b610437565b610934630cf9dff7610928610072565b9586948593849361048a565b8352600483016107cd565b03915afa908115610af3575f91610ac5575b5061095b83611152565b906109c6602061099261098d7f00000000000000000000000080493d07ddfce7a8b507c407459935a88c62ad8e61041f565b610437565b63ba065e1f906109bb6109a65f87016107e2565b926109af610072565b9586948593849361048a565b83526004830161015a565b03915afa908115610ac0575f91610a92575b50610a7e575b5080610a056109ff6109fa6109f5600487906106df565b61070c565b6100de565b916100de565b03610a5b57610a1f90610a1a84916001610725565b61083e565b907f517252ac860052b1823fd92961e2f6d30a8d2bb826f16e4a6f982160e21928cb91610a56610a4d610072565b9283928361085e565b0390a1565b610a63610072565b63162c5b6560e01b815280610a7a600482016102ab565b0390fd5b610a8c908390839091611185565b5f6109de565b610ab3915060203d8111610ab9575b610aab8183610461565b8101906107fe565b5f6109d8565b503d610aa1565b6104fa565b610ae6915060403d8111610aec575b610ade8183610461565b8101906107a2565b5f610951565b503d610ad4565b6104fa565b5050565b610b0660c061073f565b90565b5f90565b5f90565b5f90565b5f90565b610b21610afc565b906020808080808087610b32610b09565b815201610b3d610b0d565b815201610b48610b11565b815201610b53610b15565b815201610b5e610b15565b815201610b69610b15565b81525050565b610b77610b19565b90565b90565b610b91610b8c610b9692610b7a565b6103f4565b61014a565b90565b610ba36060610b7d565b90565b1b90565b610bc990610bc3610bbd610bce9461014a565b916100de565b90610ba6565b6100de565b90565b6bffffffffffffffffffffffff191690565b610bec90610bd1565b90565b60601c90565b610c01610c0691610bef565b6103f7565b90565b610c1290610bf5565b90565b90565b610c2c610c27610c3192610c15565b6103f4565b61014a565b90565b610c3e60a0610c18565b90565b1c90565b610c6490610c5e610c58610c699461014a565b916100de565b90610c41565b6100de565b90565b610c80610c7b610c859261050a565b610535565b6100de565b90565b610c9260c061073f565b90565b90610c9f9061014a565b9052565b90610cad90610087565b9052565b90610cbb906100b6565b9052565b90610cc9906100de565b9052565b610cd5610b6f565b90610cea610ce5600583906106df565b61070c565b9182610d0d610d07610d02610cfd610529565b61053a565b6100de565b916100de565b14610dfe5750610df190610de8610d2e610d29600484906106df565b61070c565b610ddf610d45610d40600386906106df565b61070c565b9395610d7b610d6c610d67610d6288610d5c610b99565b90610baa565b610be3565b610c09565b95610d75610c34565b90610c45565b610d8d610d875f610c6c565b916100de565b145f14610df457610dd65f5b610dcd610daf610daa876001610725565b61070c565b97610dc4610dbb610c88565b9b5f8d01610c95565b60208b01610ca3565b60408901610cb1565b60608701610cbf565b60808501610cbf565b60a08301610cbf565b90565b610dd66001610d99565b91505090565b5f90565b610e10610e04565b50335f526e2fd5aeb385d324b580fca7c83823a0803314610e62575b506dd9ecebf3c23529de49815dac1c4c803314610e4a575b505f5190565b5f8060209238905afa15610e5e575f610e44565b3838fd5b5f8060209238905afa15610e76575f610e2c565b3838fd5b90610e8490610719565b5f5260205260405f2090565b90565b610ea7610ea2610eac92610e90565b6103f4565b61014a565b90565b610eb96001610e93565b90565b610edb90610ed5610ecf610ee09461014a565b9161014a565b90610ba6565b61014a565b90565b610eec906103f7565b90565b610f03610efe610f089261007c565b6103f4565b61014a565b90565b6001610f17910161014a565b90565b90565b90610f32610f2d610f39926106c3565b610f1a565b825461081c565b9055565b93929193610f496103f0565b5084610f6c610f66610f61610f5c610529565b61053a565b6100de565b916100de565b148015611114575b6110f157610fc890610f90610f8b60028890610e7a565b610685565b925f146110de57610fc2610fbd610fb6610fa8610eaf565b610fb0610c34565b90610ebc565b5b92610ee3565b610eef565b1761053a565b90610fdd610fd8600483906106df565b61070c565b610fef610fe9876100de565b916100de565b146110ab575b5061106561100a6110055f610685565b610f0b565b611014815f610f1d565b9461102a83611025600389906106df565b61083e565b61103f8161103a600489906106df565b61083e565b6110548461104f600589906106df565b61083e565b61106086916002610e7a565b610f1d565b83916110917f7e0786ff457ce0bc5e3f599bcc220605e18c56cd9ebed35182b29397697ea46c92610719565b926110a661109d610072565b9283928361085e565b0390a2565b6110bf6110ba600383906106df565b61070c565b6110d16110cb846100de565b916100de565b03610ff557929350505090565b610fc2610fbd6110ec610529565b610fb7565b6110f9610072565b6321f9f13f60e11b815280611110600482016102ab565b0390fd5b50846111486111427f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5636100de565b916100de565b14610f74565b5f90565b61115a61114e565b505f5260205f2090565b61116e90516100de565b90565b61117d61118291610669565b6106c3565b90565b909160206111939101611164565b6111b46111ae6111a96111a4610529565b61053a565b6100de565b916100de565b146112a757816111df6111d96111d46111cf600486906106df565b61070c565b6100de565b916100de565b146112a35761121161120c6111fe6111f9600385906106df565b61070c565b611206610c34565b90610c45565b611171565b61122a61122461121f610529565b61014a565b9161014a565b146112805761127961127e9282817fbe48847c637d143d69ac15740d39544624cdfa8d4f6ce738ecf3e35085c1f4d69161126e611265610072565b9283928361085e565b0390a19160046106df565b61083e565b565b611288610072565b6321f9f13f60e11b81528061129f600482016102ab565b0390fd5b5050565b505056fea2646970667358221220a6869c4056bb23e25f4131c65282fce5515f77a57e87fe753a4745a011e1b6b064736f6c63430008190033