ETH Price: $1,979.13 (+0.13%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Complete Ownersh...239563382025-12-06 20:55:3577 days ago1765054535IN
0xd27c8dF4...60a9C0E9A
0 ETH0.000000690.02405668
Grant Roles239563362025-12-06 20:55:1177 days ago1765054511IN
0xd27c8dF4...60a9C0E9A
0 ETH0.000000790.02613747
Grant Roles239563352025-12-06 20:54:5977 days ago1765054499IN
0xd27c8dF4...60a9C0E9A
0 ETH0.000001220.02574405
Create Machine239464772025-12-05 11:33:1179 days ago1764934391IN
0xd27c8dF4...60a9C0E9A
0 ETH0.000073710.02446501

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MachineZap

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {IWatermarkFeeManager} from "@makina-periphery/interfaces/IWatermarkFeeManager.sol";
import {IHubPeripheryFactory} from "@makina-periphery/interfaces/IHubPeripheryFactory.sol";
import {IHubCoreFactory} from "@makina-core/interfaces/IHubCoreFactory.sol";
import {IMachine} from "@makina-core/interfaces/IMachine.sol";
import {ICaliber} from "@makina-core/interfaces/ICaliber.sol";
import {IMakinaGovernable} from "@makina-core/interfaces/IMakinaGovernable.sol";
import {OwnableRoles} from "@solady/auth/OwnableRoles.sol";
import {IMakinaGovernable} from "@makina-core/interfaces/IMakinaGovernable.sol";

import {IMachineZap} from "./interfaces/IMachineZap.sol";

contract MachineZap is IMachineZap, OwnableRoles {
    IHubPeripheryFactory public hubPeripheryFactory;
    IHubCoreFactory public hubCoreFactory;

    uint256 public constant DEPLOYER_ROLE = _ROLE_1;
    uint256 public constant CONFIG_ROLE = _ROLE_2;

    constructor(address _hubPeripheryFactory, address _hubCoreFactory) {
        hubPeripheryFactory = IHubPeripheryFactory(_hubPeripheryFactory);
        hubCoreFactory = IHubCoreFactory(_hubCoreFactory);

        _initializeOwner(msg.sender);
    }

    function createMachine(
        string calldata shareTokenName,
        string calldata shareTokenSymbol,
        address accountingToken,
        address[] calldata baseTokens,
        bytes32 salt,
        uint16 depositorImplemId,
        bool depositorWhitelistStatus,
        uint16 redeemerImplemId,
        bool redeemerWhitelistStatus,
        uint256 redeemerFinalizationDelay,
        uint256 redeemerMinRedeemAmount,
        uint16 feeManagerImplemId,
        IWatermarkFeeManager.WatermarkFeeManagerInitParams calldata feeManagerInitParams,
        MachineInitParams calldata machineInitParams,
        ICaliber.CaliberInitParams calldata caliberInitParams,
        IMakinaGovernable.MakinaGovernableInitParams memory mgInitParams
    ) public onlyRolesOrOwner(DEPLOYER_ROLE) returns (address machine) {
        address depositor = hubPeripheryFactory.createDepositor(depositorImplemId, abi.encode(depositorWhitelistStatus));
        address redeemer = hubPeripheryFactory.createRedeemer(
            redeemerImplemId, abi.encode(redeemerFinalizationDelay, redeemerMinRedeemAmount, redeemerWhitelistStatus)
        );
        address feeManager = hubPeripheryFactory.createFeeManager(feeManagerImplemId, abi.encode(feeManagerInitParams));

        address finalRiskManager = mgInitParams.initialRiskManager;
        address finalRiskManagerTimelock = mgInitParams.initialRiskManagerTimelock;

        mgInitParams.initialRiskManager = address(this);
        mgInitParams.initialRiskManagerTimelock = address(this);

        machine = hubCoreFactory.createMachine(
            IMachine.MachineInitParams({
                initialDepositor: depositor,
                initialRedeemer: redeemer,
                initialFeeManager: feeManager,
                initialCaliberStaleThreshold: machineInitParams.initialCaliberStaleThreshold,
                initialMaxFixedFeeAccrualRate: machineInitParams.initialMaxFixedFeeAccrualRate,
                initialMaxPerfFeeAccrualRate: machineInitParams.initialMaxPerfFeeAccrualRate,
                initialFeeMintCooldown: machineInitParams.initialFeeMintCooldown,
                initialShareLimit: machineInitParams.initialShareLimit
            }),
            caliberInitParams,
            mgInitParams,
            accountingToken,
            shareTokenName,
            shareTokenSymbol,
            salt
        );

        ICaliber caliber = ICaliber(IMachine(machine).hubCaliber());

        for (uint256 i = 0; i < baseTokens.length; i++) {
            caliber.addBaseToken(baseTokens[i]);
        }

        IMachine(machine).setRiskManager(finalRiskManager);
        IMachine(machine).setRiskManagerTimelock(finalRiskManagerTimelock);
    }

    function setHubPeripheryFactory(address _hubPeripheryFactory) public onlyRolesOrOwner(CONFIG_ROLE) {
        hubPeripheryFactory = IHubPeripheryFactory(_hubPeripheryFactory);
    }

    function setHubCoreFactory(address _hubCoreFactory) public onlyRolesOrOwner(CONFIG_ROLE) {
        hubCoreFactory = IHubCoreFactory(_hubCoreFactory);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IFeeManager} from "@makina-core/interfaces/IFeeManager.sol";

import {IMachinePeriphery} from "./IMachinePeriphery.sol";
import {ISecurityModuleReference} from "./ISecurityModuleReference.sol";

interface IWatermarkFeeManager is IFeeManager, ISecurityModuleReference, IMachinePeriphery {
    event MgmtFeeSplitChanged();
    event MgmtFeeRatePerSecondChanged(uint256 oldRate, uint256 newRate);
    event PerfFeeRateChanged(uint256 oldRate, uint256 newRate);
    event PerfFeeSplitChanged();
    event SmFeeRatePerSecondChanged(uint256 oldRate, uint256 newRate);
    event SecurityModuleSet(address indexed securityModule);
    event WatermarkReset(uint256 indexed newWatermark);

    /// @notice Initialization parameters.
    /// @param initialMgmtFeeRatePerSecond Management fee rate per second, in 18 decimals precision.
    /// @param initialSmFeeRatePerSecond Security module fee rate per second, in 18 decimals precision.
    /// @param initialPerfFeeRate Performance fee rate on profit, in 18 decimals precision.
    /// @param initialMgmtFeeSplitBps Fixed fee split between receivers in basis points. Values must sum to 10_000.
    /// @param initialMgmtFeeReceivers Fixed fee receivers.
    /// @param initialPerfFeeSplitBps Performance fee split between receivers in basis points. Values must sum to 10_000.
    /// @param initialPerfFeeReceivers Performance fee receivers.
    struct WatermarkFeeManagerInitParams {
        uint256 initialMgmtFeeRatePerSecond;
        uint256 initialSmFeeRatePerSecond;
        uint256 initialPerfFeeRate;
        uint256[] initialMgmtFeeSplitBps;
        address[] initialMgmtFeeReceivers;
        uint256[] initialPerfFeeSplitBps;
        address[] initialPerfFeeReceivers;
    }

    /// @notice Management fee rate per second, 1e18 = 100%.
    function mgmtFeeRatePerSecond() external view returns (uint256);

    /// @notice Security module fee rate per second, 1e18 = 100%.
    function smFeeRatePerSecond() external view returns (uint256);

    /// @notice Performance fee rate on profit, 1e18 = 100%.
    function perfFeeRate() external view returns (uint256);

    /// @notice Fixed fee receivers.
    function mgmtFeeReceivers() external view returns (address[] memory);

    /// @notice Fixed fee split between receivers in basis points. Values must sum to 10_000.
    function mgmtFeeSplitBps() external view returns (uint256[] memory);

    /// @notice Performance fee receivers.
    function perfFeeReceivers() external view returns (address[] memory);

    /// @notice Performance fee split between receivers in basis points. Values must sum to 10_000.
    function perfFeeSplitBps() external view returns (uint256[] memory);

    /// @notice Current share price high watermark for the associated Machine.
    function sharePriceWatermark() external view returns (uint256);

    /// @notice Resets the share price high watermark.
    function resetSharePriceWatermark(uint256 sharePrice) external;

    /// @notice Sets the management fee rate per second.
    /// @param newMgmtFeeRatePerSecond The new management fee rate per second. 1e18 = 100%.
    function setMgmtFeeRatePerSecond(uint256 newMgmtFeeRatePerSecond) external;

    /// @notice Sets the security module fee rate per second.
    /// @param newSmFeeRatePerSecond The new security module fee rate per second. 1e18 = 100%.
    function setSmFeeRatePerSecond(uint256 newSmFeeRatePerSecond) external;

    /// @notice Sets the performance fee rate.
    /// @param newPerfFeeRate The new performance fee rate on profit. 1e18 = 100%.
    function setPerfFeeRate(uint256 newPerfFeeRate) external;

    /// @notice Sets the fixed fee split and receivers.
    /// @param newMgmtFeeReceivers The new fixed fee receivers.
    /// @param newMgmtFeeSplitBps The new fixed fee split between receivers in basis points. Values must sum to 10_000.
    function setMgmtFeeSplit(address[] calldata newMgmtFeeReceivers, uint256[] calldata newMgmtFeeSplitBps) external;

    /// @notice Sets the performance fee split and receivers.
    /// @param newPerfFeeReceivers The new performance fee receivers.
    /// @param newPerfFeeSplitBps The new performance fee split between receivers in basis points. Values must sum to 10_000.
    function setPerfFeeSplit(address[] calldata newPerfFeeReceivers, uint256[] calldata newPerfFeeSplitBps) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {ISecurityModule} from "../interfaces/ISecurityModule.sol";

interface IHubPeripheryFactory {
    event DepositorCreated(address indexed depositor, uint16 indexed implemId);
    event RedeemerCreated(address indexed redeemer, uint16 indexed implemId);
    event FeeManagerCreated(address indexed feeManager, uint16 indexed implemId);
    event SecurityModuleCreated(address indexed securityModule);

    /// @notice Address => Whether this is a depositor deployed by this factory
    function isDepositor(address depositor) external view returns (bool);

    /// @notice Address => Whether this is a redeemer deployed by this factory
    function isRedeemer(address redeemer) external view returns (bool);

    /// @notice Address => Whether this is a fee manager deployed by this factory
    function isFeeManager(address feeManager) external view returns (bool);

    /// @notice Address => Whether this is a security module deployed by this factory
    function isSecurityModule(address securityModule) external view returns (bool);

    /// @notice Depositor => Implementation ID
    function depositorImplemId(address depositor) external view returns (uint16);

    /// @notice Redeemer => Implementation ID
    function redeemerImplemId(address redeemer) external view returns (uint16);

    /// @notice Fee manager => Implementation ID
    function feeManagerImplemId(address feeManager) external view returns (uint16);

    /// @notice Sets the machine address in the machine periphery contract.
    /// @param machinePeriphery The address of the machine periphery contract.
    /// @param machine The address of the machine to be set.
    function setMachine(address machinePeriphery, address machine) external;

    /// @notice Sets the security module address in the fee manager contract.
    /// @param feeManager The address of the fee manager contract.
    /// @param securityModule The address of the security module to be set.
    function setSecurityModule(address feeManager, address securityModule) external;

    /// @notice Creates a new machine depositor using the specified implementation ID.
    /// @param implemId The ID of the depositor implementation to be used.
    /// @param initializationData Additional initialization data.
    /// @return depositor The address of the newly created depositor.
    function createDepositor(uint16 implemId, bytes calldata initializationData) external returns (address depositor);

    /// @notice Creates a new machine redeemer using the specified implementation ID.
    /// @param implemId The ID of the redeemer implementation to be used.
    /// @param initializationData Additional initialization data.
    /// @return redeemer The address of the newly created redeemer.
    function createRedeemer(uint16 implemId, bytes calldata initializationData) external returns (address redeemer);

    /// @notice Creates a new machine fee manager using the specified implementation ID.
    /// @param implemId The ID of the fee manager implementation to be used.
    /// @param initializationData Additional initialization data.
    /// @return feeManager The address of the newly created fee manager.
    function createFeeManager(uint16 implemId, bytes calldata initializationData)
        external
        returns (address feeManager);

    /// @notice Creates a new security module.
    /// @param smParams The security module initialization parameters.
    /// @return securityModule The address of the newly created security module.
    function createSecurityModule(ISecurityModule.SecurityModuleInitParams calldata smParams)
        external
        returns (address securityModule);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {ICaliber} from "./ICaliber.sol";
import {IMachine} from "./IMachine.sol";
import {IPreDepositVault} from "./IPreDepositVault.sol";
import {IMakinaGovernable} from "./IMakinaGovernable.sol";
import {IBridgeAdapterFactory} from "./IBridgeAdapterFactory.sol";

interface IHubCoreFactory is IBridgeAdapterFactory {
    event MachineCreated(address indexed machine, address indexed shareToken);
    event PreDepositVaultCreated(address indexed preDepositVault, address indexed shareToken);
    event ShareTokenCreated(address indexed shareToken);

    /// @notice Address => Whether this is a PreDepositVault instance deployed by this factory.
    function isPreDepositVault(address preDepositVault) external view returns (bool);

    /// @notice Address => Whether this is a Machine instance deployed by this factory.
    function isMachine(address machine) external view returns (bool);

    /// @notice Deploys a new PreDepositVault instance.
    /// @param params The initialization parameters.
    /// @param depositToken The address of the deposit token.
    /// @param accountingToken The address of the accounting token.
    /// @param tokenName The name of the share token.
    /// @param tokenSymbol The symbol of the share token.
    /// @return preDepositVault The address of the deployed PreDepositVault instance.
    function createPreDepositVault(
        IPreDepositVault.PreDepositVaultInitParams calldata params,
        address depositToken,
        address accountingToken,
        string memory tokenName,
        string memory tokenSymbol
    ) external returns (address preDepositVault);

    /// @notice Deploys a new Machine instance and migrates an existing PreDepositVault instance to it.
    /// @param mParams The machine initialization parameters.
    /// @param cParams The caliber initialization parameters.
    /// @param mgParams The makina governable initialization parameters.
    /// @param preDepositVault The address of the PreDepositVault instance to migrate.
    /// @param salt The salt used to deploy the Hub Caliber deterministically.
    /// @return machine The address of the deployed Machine instance.
    function createMachineFromPreDeposit(
        IMachine.MachineInitParams calldata mParams,
        ICaliber.CaliberInitParams calldata cParams,
        IMakinaGovernable.MakinaGovernableInitParams calldata mgParams,
        address preDepositVault,
        bytes32 salt
    ) external returns (address machine);

    /// @notice Deploys a new Machine instance.
    /// @param mParams The machine initialization parameters.
    /// @param cParams The caliber initialization parameters.
    /// @param mgParams The makina governable initialization parameters.
    /// @param accountingToken The address of the accounting token.
    /// @param tokenName The name of the share token.
    /// @param tokenSymbol The symbol of the share token.
    /// @param salt The salt used to deploy the Hub Caliber deterministically.
    /// @return machine The address of the deployed Machine instance.
    function createMachine(
        IMachine.MachineInitParams calldata mParams,
        ICaliber.CaliberInitParams calldata cParams,
        IMakinaGovernable.MakinaGovernableInitParams calldata mgParams,
        address accountingToken,
        string memory tokenName,
        string memory tokenSymbol,
        bytes32 salt
    ) external returns (address machine);
}

File 5 of 42 : IMachine.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";

import {GuardianSignature} from "@wormhole/sdk/libraries/VaaLib.sol";

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

interface IMachine is IMachineEndpoint {
    event CaliberStaleThresholdChanged(uint256 indexed oldThreshold, uint256 indexed newThreshold);
    event Deposit(address indexed sender, address indexed receiver, uint256 assets, uint256 shares);
    event DepositorChanged(address indexed oldDepositor, address indexed newDepositor);
    event FeeManagerChanged(address indexed oldFeeManager, address indexed newFeeManager);
    event FeeMintCooldownChanged(uint256 indexed oldFeeMintCooldown, uint256 indexed newFeeMintCooldown);
    event FeesMinted(uint256 shares);
    event MaxFixedFeeAccrualRateChanged(uint256 indexed oldMaxAccrualRate, uint256 indexed newMaxAccrualRate);
    event MaxPerfFeeAccrualRateChanged(uint256 indexed oldMaxAccrualRate, uint256 indexed newMaxAccrualRate);
    event Redeem(address indexed owner, address indexed receiver, uint256 assets, uint256 shares);
    event RedeemerChanged(address indexed oldRedeemer, address indexed newRedeemer);
    event ShareLimitChanged(uint256 indexed oldShareLimit, uint256 indexed newShareLimit);
    event SpokeBridgeAdapterSet(uint256 indexed chainId, uint256 indexed bridgeId, address indexed adapter);
    event SpokeCaliberMailboxSet(uint256 indexed chainId, address indexed caliberMailbox);
    event TotalAumUpdated(uint256 totalAum);
    event TransferToCaliber(uint256 indexed chainId, address indexed token, uint256 amount);

    /// @notice Initialization parameters.
    /// @param initialDepositor The address of the initial depositor.
    /// @param initialRedeemer The address of the initial redeemer.
    /// @param initialFeeManager The address of the initial fee manager.
    /// @param initialCaliberStaleThreshold The caliber accounting staleness threshold in seconds.
    /// @param initialMaxFixedFeeAccrualRate The maximum fixed fee accrual rate per second, 1e18 = 100%.
    /// @param initialMaxPerfFeeAccrualRate The maximum performance fee accrual rate per second, 1e18 = 100%.
    /// @param initialFeeMintCooldown The minimum time to be elapsed between two fee minting events in seconds.
    /// @param initialShareLimit The share cap value.
    struct MachineInitParams {
        address initialDepositor;
        address initialRedeemer;
        address initialFeeManager;
        uint256 initialCaliberStaleThreshold;
        uint256 initialMaxFixedFeeAccrualRate;
        uint256 initialMaxPerfFeeAccrualRate;
        uint256 initialFeeMintCooldown;
        uint256 initialShareLimit;
    }

    /// @dev Internal state structure for a spoke caliber data.
    /// @param mailbox The foreign address of the spoke caliber mailbox.
    /// @param bridgeAdapters The mapping of bridge IDs to their corresponding adapters.
    /// @param timestamp The timestamp of the last accounting.
    /// @param netAum The net AUM of the spoke caliber.
    /// @param positions The list of positions of the spoke caliber, each encoded as abi.encode(positionId, value).
    /// @param baseTokens The list of base tokens of the spoke caliber, each encoded as abi.encode(token, value).
    /// @param caliberBridgesIn The mapping of spoke caliber incoming bridge amounts.
    /// @param caliberBridgesOut The mapping of spoke caliber outgoing bridge amounts.
    /// @param machineBridgesIn The mapping of machine incoming bridge amounts.
    /// @param machineBridgesOut The mapping of machine outgoing bridge amounts.
    struct SpokeCaliberData {
        address mailbox;
        mapping(uint16 bridgeId => address adapter) bridgeAdapters;
        uint256 timestamp;
        uint256 netAum;
        bytes[] positions;
        bytes[] baseTokens;
        EnumerableMap.AddressToUintMap caliberBridgesIn;
        EnumerableMap.AddressToUintMap caliberBridgesOut;
        EnumerableMap.AddressToUintMap machineBridgesIn;
        EnumerableMap.AddressToUintMap machineBridgesOut;
    }

    /// @notice Initializer of the contract.
    /// @param mParams The machine initialization parameters.
    /// @param mgParams The makina governable initialization parameters.
    /// @param _preDepositVault The address of the pre-deposit vault.
    /// @param _shareToken The address of the share token.
    /// @param _accountingToken The address of the accounting token.
    /// @param _hubCaliber The address of the hub caliber.
    function initialize(
        MachineInitParams calldata mParams,
        MakinaGovernableInitParams calldata mgParams,
        address _preDepositVault,
        address _shareToken,
        address _accountingToken,
        address _hubCaliber
    ) external;

    /// @notice Address of the Wormhole Core Bridge.
    function wormhole() external view returns (address);

    /// @notice Address of the depositor.
    function depositor() external view returns (address);

    /// @notice Address of the redeemer.
    function redeemer() external view returns (address);

    /// @notice Address of the share token.
    function shareToken() external view returns (address);

    /// @notice Address of the accounting token.
    function accountingToken() external view returns (address);

    /// @notice Address of the hub caliber.
    function hubCaliber() external view returns (address);

    /// @notice Address of the fee manager.
    function feeManager() external view returns (address);

    /// @notice Maximum duration a caliber can remain unaccounted for before it is considered stale.
    function caliberStaleThreshold() external view returns (uint256);

    /// @notice Maximum fixed fee accrual rate per second used to compute an upper bound on shares to be minted, 1e18 = 100%.
    function maxFixedFeeAccrualRate() external view returns (uint256);

    /// @notice Maximum performance fee accrual rate per second used to compute an upper bound on shares to be minted, 1e18 = 100%.
    function maxPerfFeeAccrualRate() external view returns (uint256);

    /// @notice Minimum time to be elapsed between two fee minting events.
    function feeMintCooldown() external view returns (uint256);

    /// @notice Share token supply limit that cannot be exceeded by new deposits.
    function shareLimit() external view returns (uint256);

    /// @notice Maximum amount of shares that can currently be minted through asset deposits.
    function maxMint() external view returns (uint256);

    /// @notice Maximum amount of accounting tokens that can currently be withdrawn through share redemptions.
    function maxWithdraw() external view returns (uint256);

    /// @notice Last total machine AUM.
    function lastTotalAum() external view returns (uint256);

    /// @notice Timestamp of the last global machine accounting.
    function lastGlobalAccountingTime() external view returns (uint256);

    /// @notice Token => Is the token an idle token.
    function isIdleToken(address token) external view returns (bool);

    /// @notice Number of calibers associated with the machine.
    function getSpokeCalibersLength() external view returns (uint256);

    /// @notice Spoke caliber index => Spoke Chain ID.
    function getSpokeChainId(uint256 idx) external view returns (uint256);

    /// @notice Spoke Chain ID => Spoke caliber's AUM, individual positions values and accounting timestamp.
    function getSpokeCaliberDetailedAum(uint256 chainId)
        external
        view
        returns (uint256 aum, bytes[] memory positions, bytes[] memory baseTokens, uint256 timestamp);

    /// @notice Spoke Chain ID => Spoke Caliber Mailbox Address.
    function getSpokeCaliberMailbox(uint256 chainId) external view returns (address);

    /// @notice Spoke Chain ID => Spoke Bridge ID => Spoke Bridge Adapter.
    function getSpokeBridgeAdapter(uint256 chainId, uint16 bridgeId) external view returns (address);

    /// @notice Returns the amount of shares that the Machine would exchange for the amount of accounting tokens provided.
    /// @param assets The amount of accounting tokens.
    /// @return shares The amount of shares.
    function convertToShares(uint256 assets) external view returns (uint256);

    /// @notice Returns the amount of accounting tokens that the Machine would exchange for the amount of shares provided.
    /// @param shares The amount of shares.
    /// @return assets The amount of accounting tokens.
    function convertToAssets(uint256 shares) external view returns (uint256);

    /// @notice Initiates a token transfers to the hub caliber.
    /// @param token The address of the token to transfer.
    /// @param amount The amount of token to transfer.
    function transferToHubCaliber(address token, uint256 amount) external;

    /// @notice Initiates a token transfers to the spoke caliber.
    /// @param bridgeId The ID of the bridge to use for the transfer.
    /// @param chainId The foreign EVM chain ID of the spoke caliber.
    /// @param token The address of the token to transfer.
    /// @param amount The amount of token to transfer.
    /// @param minOutputAmount The minimum output amount expected from the transfer.
    function transferToSpokeCaliber(
        uint16 bridgeId,
        uint256 chainId,
        address token,
        uint256 amount,
        uint256 minOutputAmount
    ) external;

    /// @notice Updates the total AUM of the machine.
    /// @return totalAum The updated total AUM.
    function updateTotalAum() external returns (uint256);

    /// @notice Deposits accounting tokens into the machine and mints shares to the receiver.
    /// @param assets The amount of accounting tokens to deposit.
    /// @param receiver The receiver of minted shares.
    /// @param minShares The minimum amount of shares to be minted.
    /// @return shares The amount of shares minted.
    function deposit(uint256 assets, address receiver, uint256 minShares) external returns (uint256);

    /// @notice Redeems shares from the machine and transfers accounting tokens to the receiver.
    /// @param shares The amount of shares to redeem.
    /// @param receiver The receiver of the accounting tokens.
    /// @param minAssets The minimum amount of accounting tokens to be transferred.
    /// @return assets The amount of accounting tokens transferred.
    function redeem(uint256 shares, address receiver, uint256 minAssets) external returns (uint256);

    /// @notice Updates spoke caliber accounting data using Wormhole Cross-Chain Queries (CCQ).
    /// @dev Validates the Wormhole CCQ response and guardian signatures before updating state.
    /// @param response The Wormhole CCQ response payload containing the accounting data.
    /// @param signatures The array of Wormhole guardians signatures attesting to the validity of the response.
    function updateSpokeCaliberAccountingData(bytes memory response, GuardianSignature[] memory signatures) external;

    /// @notice Registers a spoke caliber mailbox and related bridge adapters.
    /// @param chainId The foreign EVM chain ID of the spoke caliber.
    /// @param spokeCaliberMailbox The address of the spoke caliber mailbox.
    /// @param bridges The list of bridges supported with the spoke caliber.
    /// @param adapters The list of corresponding adapters for each bridge. Must be the same length as `bridges`.
    function setSpokeCaliber(
        uint256 chainId,
        address spokeCaliberMailbox,
        uint16[] calldata bridges,
        address[] calldata adapters
    ) external;

    /// @notice Registers a spoke bridge adapter.
    /// @param chainId The foreign EVM chain ID of the adapter.
    /// @param bridgeId The ID of the bridge.
    /// @param adapter The foreign address of the bridge adapter.
    function setSpokeBridgeAdapter(uint256 chainId, uint16 bridgeId, address adapter) external;

    /// @notice Sets the depositor address.
    /// @param newDepositor The address of the new depositor.
    function setDepositor(address newDepositor) external;

    /// @notice Sets the redeemer address.
    /// @param newRedeemer The address of the new redeemer.
    function setRedeemer(address newRedeemer) external;

    /// @notice Sets the fee manager address.
    /// @param newFeeManager The address of the new fee manager.
    function setFeeManager(address newFeeManager) external;

    /// @notice Sets the caliber accounting staleness threshold.
    /// @param newCaliberStaleThreshold The new threshold in seconds.
    function setCaliberStaleThreshold(uint256 newCaliberStaleThreshold) external;

    /// @notice Sets the maximum fixed fee accrual rate.
    /// @param newMaxAccrualRate The new maximum fixed fee accrual rate per second, 1e18 = 100%.
    function setMaxFixedFeeAccrualRate(uint256 newMaxAccrualRate) external;

    /// @notice Sets the maximum performance fee accrual rate.
    /// @param newMaxAccrualRate The new maximum performance fee accrual rate per second, 1e18 = 100%.
    function setMaxPerfFeeAccrualRate(uint256 newMaxAccrualRate) external;

    /// @notice Sets the minimum time to be elapsed between two fee minting events.
    /// @param newFeeMintCooldown The new cooldown in seconds.
    function setFeeMintCooldown(uint256 newFeeMintCooldown) external;

    /// @notice Sets the new share token supply limit that cannot be exceeded by new deposits.
    /// @param newShareLimit The new share limit
    function setShareLimit(uint256 newShareLimit) external;
}

File 6 of 42 : ICaliber.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

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

interface ICaliber {
    event BaseTokenAdded(address indexed token);
    event BaseTokenRemoved(address indexed token);
    event CooldownDurationChanged(uint256 indexed oldDuration, uint256 indexed newDuration);
    event IncomingTransfer(address indexed token, uint256 amount);
    event InstrRootGuardianAdded(address indexed newGuardian);
    event InstrRootGuardianRemoved(address indexed guardian);
    event MaxPositionDecreaseLossBpsChanged(
        uint256 indexed oldMaxPositionDecreaseLossBps, uint256 indexed newMaxPositionDecreaseLossBps
    );
    event MaxPositionIncreaseLossBpsChanged(
        uint256 indexed oldMaxPositionIncreaseLossBps, uint256 indexed newMaxPositionIncreaseLossBps
    );
    event MaxSwapLossBpsChanged(uint256 indexed oldMaxSwapLossBps, uint256 indexed newMaxSwapLossBps);
    event NewAllowedInstrRootCancelled(bytes32 indexed cancelledMerkleRoot);
    event NewAllowedInstrRootScheduled(bytes32 indexed newMerkleRoot, uint256 indexed effectiveTime);
    event PositionClosed(uint256 indexed id);
    event PositionCreated(uint256 indexed id, uint256 value);
    event PositionUpdated(uint256 indexed id, uint256 value);
    event PositionStaleThresholdChanged(uint256 indexed oldThreshold, uint256 indexed newThreshold);
    event TimelockDurationChanged(uint256 indexed oldDuration, uint256 indexed newDuration);
    event TransferToHubMachine(address indexed token, uint256 amount);

    enum InstructionType {
        MANAGEMENT,
        ACCOUNTING,
        HARVEST,
        FLASHLOAN_MANAGEMENT
    }

    /// @notice Initialization parameters.
    /// @param initialPositionStaleThreshold The position accounting staleness threshold in seconds.
    /// @param initialAllowedInstrRoot The root of the Merkle tree containing allowed instructions.
    /// @param initialTimelockDuration The duration of the allowedInstrRoot update timelock.
    /// @param initialMaxPositionIncreaseLossBps The max allowed value loss (in basis point) for position increases.
    /// @param initialMaxPositionDecreaseLossBps The max allowed value loss (in basis point) for position decreases.
    /// @param initialMaxSwapLossBps The max allowed value loss (in basis point) for base token swaps.
    /// @param initialCooldownDuration The duration of the cooldown period for swaps and position management.
    struct CaliberInitParams {
        uint256 initialPositionStaleThreshold;
        bytes32 initialAllowedInstrRoot;
        uint256 initialTimelockDuration;
        uint256 initialMaxPositionIncreaseLossBps;
        uint256 initialMaxPositionDecreaseLossBps;
        uint256 initialMaxSwapLossBps;
        uint256 initialCooldownDuration;
    }

    /// @notice Instruction parameters.
    /// @param positionId The ID of the involved position.
    /// @param isDebt Whether the position is a debt.
    /// @param groupId The ID of the position accounting group.
    ///        Set to 0 if the instruction is not of type ACCOUNTING, or if the involved position is ungrouped.
    /// @param instructionType The type of the instruction.
    /// @param affectedTokens The array of affected tokens.
    /// @param commands The array of commands.
    /// @param state The array of state.
    /// @param stateBitmap The state bitmap.
    /// @param merkleProof The array of Merkle proof elements.
    struct Instruction {
        uint256 positionId;
        bool isDebt;
        uint256 groupId;
        InstructionType instructionType;
        address[] affectedTokens;
        bytes32[] commands;
        bytes[] state;
        uint128 stateBitmap;
        bytes32[] merkleProof;
    }

    /// @notice Position data.
    /// @param lastAccountingTime The last block timestamp when the position was accounted for.
    /// @param value The value of the position expressed in accounting token.
    /// @param isDebt Whether the position is a debt.
    struct Position {
        uint256 lastAccountingTime;
        uint256 value;
        bool isDebt;
    }

    /// @notice Initializer of the contract.
    /// @param cParams The caliber initialization parameters.
    /// @param _accountingToken The address of the accounting token.
    /// @param _hubMachineEndpoint The address of the hub machine endpoints.
    function initialize(CaliberInitParams calldata cParams, address _accountingToken, address _hubMachineEndpoint)
        external;

    /// @notice Address of the Weiroll VM.
    function weirollVm() external view returns (address);

    /// @notice Address of the hub machine endpoint.
    function hubMachineEndpoint() external view returns (address);

    /// @notice Address of the accounting token.
    function accountingToken() external view returns (address);

    /// @notice Maximum duration a position can remain unaccounted for before it is considered stale.
    function positionStaleThreshold() external view returns (uint256);

    /// @notice Root of the Merkle tree containing allowed instructions.
    function allowedInstrRoot() external view returns (bytes32);

    /// @notice Duration of the allowedInstrRoot update timelock.
    function timelockDuration() external view returns (uint256);

    /// @notice Value of the pending allowedInstrRoot, if any.
    function pendingAllowedInstrRoot() external view returns (bytes32);

    /// @notice Effective time of the last scheduled allowedInstrRoot update.
    function pendingTimelockExpiry() external view returns (uint256);

    /// @notice Max allowed value loss (in basis point) when increasing a position.
    function maxPositionIncreaseLossBps() external view returns (uint256);

    /// @notice Max allowed value loss (in basis point) when decreasing a position.
    function maxPositionDecreaseLossBps() external view returns (uint256);

    /// @notice Max allowed value loss (in basis point) for base token swaps.
    function maxSwapLossBps() external view returns (uint256);

    /// @notice Duration of the cooldown period for swaps and position management.
    function cooldownDuration() external view returns (uint256);

    /// @notice Length of the position IDs list.
    function getPositionsLength() external view returns (uint256);

    /// @notice Position index => Position ID
    /// @dev There are no guarantees on the ordering of values inside the Position ID list,
    ///      and it may change when values are added or removed.
    function getPositionId(uint256 idx) external view returns (uint256);

    /// @notice Position ID => Position data
    function getPosition(uint256 id) external view returns (Position memory);

    /// @notice Token => Registered as base token in this caliber
    function isBaseToken(address token) external view returns (bool);

    /// @notice Length of the base tokens list.
    function getBaseTokensLength() external view returns (uint256);

    /// @notice Base token index => Base token address
    /// @dev There are no guarantees on the ordering of values inside the base tokens list,
    ///      and it may change when values are added or removed.
    function getBaseToken(uint256 idx) external view returns (address);

    /// @notice User => Whether the user is a root guardian
    ///      Guardians have veto power over updates of the Merkle root.
    function isInstrRootGuardian(address user) external view returns (bool);

    /// @notice Checks if the accounting age of each position is below the position staleness threshold.
    function isAccountingFresh() external view returns (bool);

    /// @notice Returns the caliber's net AUM along with detailed position and base token breakdowns.
    /// @return netAum The total value of all base token balances and positive positions, minus total debts.
    /// @return positions The array of encoded tuples of the form (positionId, value, isDebt).
    /// @return baseTokens The array of encoded tuples of the form (token, value).
    function getDetailedAum()
        external
        view
        returns (uint256 netAum, bytes[] memory positions, bytes[] memory baseTokens);

    /// @notice Adds a new base token.
    /// @param token The address of the base token.
    function addBaseToken(address token) external;

    /// @notice Removes a base token.
    /// @param token The address of the base token.
    function removeBaseToken(address token) external;

    /// @notice Accounts for a position.
    /// @dev If the position value goes to zero, it is closed.
    /// @param instruction The accounting instruction.
    /// @return value The new position value.
    /// @return change The change in the position value.
    function accountForPosition(Instruction calldata instruction) external returns (uint256 value, int256 change);

    /// @notice Accounts for a batch of positions.
    /// @param instructions The array of accounting instructions.
    /// @param groupIds The array of position group IDs.
    ///        An accounting instruction must be provided for every open position in each specified group.
    ///        If an instruction's groupId corresponds to a group of open positions of size greater than 1,
    ///        the group ID must be included in this array.
    /// @return values The new position values.
    /// @return changes The changes in the position values.
    function accountForPositionBatch(Instruction[] calldata instructions, uint256[] calldata groupIds)
        external
        returns (uint256[] memory values, int256[] memory changes);

    /// @notice Manages a position's state through paired management and accounting instructions
    /// @dev Performs accounting updates and modifies contract storage by:
    /// - Adding new positions to storage when created.
    /// - Removing positions from storage when value reaches zero.
    /// @dev Applies value preservation checks using a validation matrix to prevent
    /// economic inconsistencies between position changes and token flows.
    ///
    /// The matrix evaluates three factors to determine required validations:
    /// - Base Token Inflow - Whether the contract's base token balance increases during operation
    /// - Debt Position - Whether position represents protocol liability (true) vs asset (false)
    /// - Position Δ direction - Direction of position value change (increase/decrease)
    ///
    /// ┌───────────────────┬───────────────┬──────────────────────┬───────────────────────────┐
    /// │ Base Token Inflow │ Debt Position │ Position Δ direction │ Action                    │
    /// ├───────────────────┼───────────────┼──────────────────────┼───────────────────────────┤
    /// │ No                │ No            │ Decrease             │ Revert: Invalid direction │
    /// │ No                │ Yes           │ Increase             │ Revert: Invalid direction │
    /// │ No                │ No            │ Increase             │ Minimum Δ Check           │
    /// │ No                │ Yes           │ Decrease             │ Minimum Δ Check           │
    /// │ Yes               │ No            │ Decrease             │ Maximum Δ Check           │
    /// │ Yes               │ Yes           │ Increase             │ Maximum Δ Check           │
    /// │ Yes               │ No            │ Increase             │ No check (favorable move) │
    /// │ Yes               │ Yes           │ Decrease             │ No check (favorable move) │
    /// └───────────────────┴───────────────┴──────────────────────┴───────────────────────────┘
    /// @param mgmtInstruction The management instruction.
    /// @param acctInstruction The accounting instruction.
    /// @return value The new position value.
    /// @return change The signed position value delta.
    function managePosition(Instruction calldata mgmtInstruction, Instruction calldata acctInstruction)
        external
        returns (uint256 value, int256 change);

    /// @notice Manages a batch of positions.
    /// @dev Convenience function to manage multiple positions in a single transaction.
    /// @param mgmtInstructions The array of management instructions.
    /// @param acctInstructions The array of accounting instructions.
    /// @return values The new position values.
    /// @return changes The changes in the position values.
    function managePositionBatch(Instruction[] calldata mgmtInstructions, Instruction[] calldata acctInstructions)
        external
        returns (uint256[] memory values, int256[] memory changes);

    /// @notice Manages flashLoan funds.
    /// @param instruction The flashLoan management instruction.
    /// @param token The loan token.
    /// @param amount The loan amount.
    function manageFlashLoan(Instruction calldata instruction, address token, uint256 amount) external;

    /// @notice Harvests one or multiple positions.
    /// @param instruction The harvest instruction.
    /// @param swapOrders The array of swap orders to be executed after the harvest.
    function harvest(Instruction calldata instruction, ISwapModule.SwapOrder[] calldata swapOrders) external;

    /// @notice Performs a swap via the swapModule module.
    /// @param order The swap order parameters.
    function swap(ISwapModule.SwapOrder calldata order) external;

    /// @notice Initiates a token transfer to the hub machine.
    /// @param token The address of the token to transfer.
    /// @param amount The amount of tokens to transfer.
    /// @param data ABI-encoded parameters required for bridge-related transfers. Ignored when called from a hub caliber.
    function transferToHubMachine(address token, uint256 amount, bytes calldata data) external;

    /// @notice Instructs the Caliber to pull the specified token amount from the calling hub machine endpoint.
    /// @param token The address of the token being transferred.
    /// @param amount The amount of tokens being transferred.
    function notifyIncomingTransfer(address token, uint256 amount) external;

    /// @notice Sets the position accounting staleness threshold.
    /// @param newPositionStaleThreshold The new threshold in seconds.
    function setPositionStaleThreshold(uint256 newPositionStaleThreshold) external;

    /// @notice Sets the duration of the allowedInstrRoot update timelock.
    /// @param newTimelockDuration The new duration in seconds.
    function setTimelockDuration(uint256 newTimelockDuration) external;

    /// @notice Schedules an update of the root of the Merkle tree containing allowed instructions.
    /// @dev The update will take effect after the timelock duration stored in the contract
    /// at the time of the call.
    /// @param newMerkleRoot The new Merkle root.
    function scheduleAllowedInstrRootUpdate(bytes32 newMerkleRoot) external;

    /// @notice Cancels a scheduled update of the root of the Merkle tree containing allowed instructions.
    /// @dev Reverts if no pending update exists or if the timelock has expired.
    function cancelAllowedInstrRootUpdate() external;

    /// @notice Sets the max allowed value loss for position increases.
    /// @param newMaxPositionIncreaseLossBps The new max value loss in basis points.
    function setMaxPositionIncreaseLossBps(uint256 newMaxPositionIncreaseLossBps) external;

    /// @notice Sets the max allowed value loss for position decreases.
    /// @param newMaxPositionDecreaseLossBps The new max value loss in basis points.
    function setMaxPositionDecreaseLossBps(uint256 newMaxPositionDecreaseLossBps) external;

    /// @notice Sets the max allowed value loss for base token swaps.
    /// @param newMaxSwapLossBps The new max value loss in basis points.
    function setMaxSwapLossBps(uint256 newMaxSwapLossBps) external;

    /// @notice Sets the duration of the cooldown period for swaps and position management.
    /// @param newCooldownDuration The new duration in seconds.
    function setCooldownDuration(uint256 newCooldownDuration) external;

    /// @notice Adds a new guardian for the Merkle tree containing allowed instructions.
    /// @param newGuardian The address of the new guardian.
    function addInstrRootGuardian(address newGuardian) external;

    /// @notice Removes a guardian for the Merkle tree containing allowed instructions.
    /// @param guardian The address of the guardian to remove.
    function removeInstrRootGuardian(address guardian) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IMakinaGovernable {
    event MechanicChanged(address indexed oldMechanic, address indexed newMechanic);
    event RecoveryModeChanged(bool recoveryMode);
    event RiskManagerChanged(address indexed oldRiskManager, address indexed newRiskManager);
    event RiskManagerTimelockChanged(address indexed oldRiskManagerTimelock, address indexed newRiskManagerTimelock);
    event SecurityCouncilChanged(address indexed oldSecurityCouncil, address indexed newSecurityCouncil);

    /// @notice Initialization parameters.
    /// @param initialMechanic The address of the initial mechanic.
    /// @param initialSecurityCouncil The address of the initial security council.
    /// @param initialRiskManager The address of the initial risk manager.
    /// @param initialRiskManagerTimelock The address of the initial risk manager timelock.
    /// @param initialAuthority The address of the initial authority.
    struct MakinaGovernableInitParams {
        address initialMechanic;
        address initialSecurityCouncil;
        address initialRiskManager;
        address initialRiskManagerTimelock;
        address initialAuthority;
    }

    /// @notice Address of the mechanic.
    function mechanic() external view returns (address);

    /// @notice Address of the security council.
    function securityCouncil() external view returns (address);

    /// @notice Address of the risk manager.
    function riskManager() external view returns (address);

    /// @notice Address of the risk manager timelock.
    function riskManagerTimelock() external view returns (address);

    /// @notice True if the contract is in recovery mode, false otherwise.
    function recoveryMode() external view returns (bool);

    /// @notice Sets a new mechanic.
    /// @param newMechanic The address of new mechanic.
    function setMechanic(address newMechanic) external;

    /// @notice Sets a new security council.
    /// @param newSecurityCouncil The address of the new security council.
    function setSecurityCouncil(address newSecurityCouncil) external;

    /// @notice Sets a new risk manager.
    /// @param newRiskManager The address of the new risk manager.
    function setRiskManager(address newRiskManager) external;

    /// @notice Sets a new risk manager timelock.
    /// @param newRiskManagerTimelock The address of the new risk manager timelock.
    function setRiskManagerTimelock(address newRiskManagerTimelock) external;

    /// @notice Sets the recovery mode.
    /// @param enabled True to enable recovery mode, false to disable it.
    function setRecoveryMode(bool enabled) external;
}

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

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

/// @notice Simple single owner and multiroles authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/OwnableRoles.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract OwnableRoles is Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The `user`'s roles is updated to `roles`.
    /// Each bit of `roles` represents whether the role is set.
    event RolesUpdated(address indexed user, uint256 indexed roles);

    /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
    uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
        0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;

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

    /// @dev The role slot of `user` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED))
    ///     let roleSlot := keccak256(0x00, 0x20)
    /// ```
    /// This automatically ignores the upper bits of the `user` in case
    /// they are not clean, as well as keep the `keccak256` under 32-bytes.
    ///
    /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`.
    uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;

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

    /// @dev Overwrite the roles directly without authorization guard.
    function _setRoles(address user, uint256 roles) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            // Store the new value.
            sstore(keccak256(0x0c, 0x20), roles)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
        }
    }

    /// @dev Updates the roles directly without authorization guard.
    /// If `on` is true, each set bit of `roles` will be turned on,
    /// otherwise, each set bit of `roles` will be turned off.
    function _updateRoles(address user, uint256 roles, bool on) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            let roleSlot := keccak256(0x0c, 0x20)
            // Load the current value.
            let current := sload(roleSlot)
            // Compute the updated roles if `on` is true.
            let updated := or(current, roles)
            // Compute the updated roles if `on` is false.
            // Use `and` to compute the intersection of `current` and `roles`,
            // `xor` it with `current` to flip the bits in the intersection.
            if iszero(on) { updated := xor(current, and(current, roles)) }
            // Then, store the new value.
            sstore(roleSlot, updated)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated)
        }
    }

    /// @dev Grants the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn on.
    function _grantRoles(address user, uint256 roles) internal virtual {
        _updateRoles(user, roles, true);
    }

    /// @dev Removes the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn off.
    function _removeRoles(address user, uint256 roles) internal virtual {
        _updateRoles(user, roles, false);
    }

    /// @dev Throws if the sender does not have any of the `roles`.
    function _checkRoles(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, caller())
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Throws if the sender is not the owner,
    /// and does not have any of the `roles`.
    /// Checks for ownership first, then lazily checks for roles.
    function _checkOwnerOrRoles(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner.
            // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
            if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                // Compute the role slot.
                mstore(0x0c, _ROLE_SLOT_SEED)
                mstore(0x00, caller())
                // Load the stored value, and if the `and` intersection
                // of the value and `roles` is zero, revert.
                if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Throws if the sender does not have any of the `roles`,
    /// and is not the owner.
    /// Checks for roles first, then lazily checks for ownership.
    function _checkRolesOrOwner(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, caller())
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                // If the caller is not the stored owner.
                // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
                if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
                // We don't need to mask the values of `ordinals`, as Solidity
                // cleans dirty upper bits when storing variables into memory.
                roles := or(shl(mload(add(ordinals, i)), 1), roles)
            }
        }
    }

    /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the pointer to the free memory.
            ordinals := mload(0x40)
            let ptr := add(ordinals, 0x20)
            let o := 0
            // The absence of lookup tables, De Bruijn, etc., here is intentional for
            // smaller bytecode, as this function is not meant to be called on-chain.
            for { let t := roles } 1 {} {
                mstore(ptr, o)
                // `shr` 5 is equivalent to multiplying by 0x20.
                // Push back into the ordinals array if the bit is set.
                ptr := add(ptr, shl(5, and(t, 1)))
                o := add(o, 1)
                t := shr(o, roles)
                if iszero(t) { break }
            }
            // Store the length of `ordinals`.
            mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
            // Allocate the memory.
            mstore(0x40, ptr)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to grant `user` `roles`.
    /// If the `user` already has a role, then it will be an no-op for the role.
    function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _grantRoles(user, roles);
    }

    /// @dev Allows the owner to remove `user` `roles`.
    /// If the `user` does not have a role, then it will be an no-op for the role.
    function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _removeRoles(user, roles);
    }

    /// @dev Allow the caller to remove their own roles.
    /// If the caller does not have a role, then it will be an no-op for the role.
    function renounceRoles(uint256 roles) public payable virtual {
        _removeRoles(msg.sender, roles);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the roles of `user`.
    function rolesOf(address user) public view virtual returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            // Load the stored value.
            roles := sload(keccak256(0x0c, 0x20))
        }
    }

    /// @dev Returns whether `user` has any of `roles`.
    function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) {
        return rolesOf(user) & roles != 0;
    }

    /// @dev Returns whether `user` has all of `roles`.
    function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) {
        return rolesOf(user) & roles == roles;
    }

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

    /// @dev Marks a function as only callable by an account with `roles`.
    modifier onlyRoles(uint256 roles) virtual {
        _checkRoles(roles);
        _;
    }

    /// @dev Marks a function as only callable by the owner or by an account
    /// with `roles`. Checks for ownership first, then lazily checks for roles.
    modifier onlyOwnerOrRoles(uint256 roles) virtual {
        _checkOwnerOrRoles(roles);
        _;
    }

    /// @dev Marks a function as only callable by an account with `roles`
    /// or the owner. Checks for roles first, then lazily checks for ownership.
    modifier onlyRolesOrOwner(uint256 roles) virtual {
        _checkRolesOrOwner(roles);
        _;
    }

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

    // IYKYK

    uint256 internal constant _ROLE_0 = 1 << 0;
    uint256 internal constant _ROLE_1 = 1 << 1;
    uint256 internal constant _ROLE_2 = 1 << 2;
    uint256 internal constant _ROLE_3 = 1 << 3;
    uint256 internal constant _ROLE_4 = 1 << 4;
    uint256 internal constant _ROLE_5 = 1 << 5;
    uint256 internal constant _ROLE_6 = 1 << 6;
    uint256 internal constant _ROLE_7 = 1 << 7;
    uint256 internal constant _ROLE_8 = 1 << 8;
    uint256 internal constant _ROLE_9 = 1 << 9;
    uint256 internal constant _ROLE_10 = 1 << 10;
    uint256 internal constant _ROLE_11 = 1 << 11;
    uint256 internal constant _ROLE_12 = 1 << 12;
    uint256 internal constant _ROLE_13 = 1 << 13;
    uint256 internal constant _ROLE_14 = 1 << 14;
    uint256 internal constant _ROLE_15 = 1 << 15;
    uint256 internal constant _ROLE_16 = 1 << 16;
    uint256 internal constant _ROLE_17 = 1 << 17;
    uint256 internal constant _ROLE_18 = 1 << 18;
    uint256 internal constant _ROLE_19 = 1 << 19;
    uint256 internal constant _ROLE_20 = 1 << 20;
    uint256 internal constant _ROLE_21 = 1 << 21;
    uint256 internal constant _ROLE_22 = 1 << 22;
    uint256 internal constant _ROLE_23 = 1 << 23;
    uint256 internal constant _ROLE_24 = 1 << 24;
    uint256 internal constant _ROLE_25 = 1 << 25;
    uint256 internal constant _ROLE_26 = 1 << 26;
    uint256 internal constant _ROLE_27 = 1 << 27;
    uint256 internal constant _ROLE_28 = 1 << 28;
    uint256 internal constant _ROLE_29 = 1 << 29;
    uint256 internal constant _ROLE_30 = 1 << 30;
    uint256 internal constant _ROLE_31 = 1 << 31;
    uint256 internal constant _ROLE_32 = 1 << 32;
    uint256 internal constant _ROLE_33 = 1 << 33;
    uint256 internal constant _ROLE_34 = 1 << 34;
    uint256 internal constant _ROLE_35 = 1 << 35;
    uint256 internal constant _ROLE_36 = 1 << 36;
    uint256 internal constant _ROLE_37 = 1 << 37;
    uint256 internal constant _ROLE_38 = 1 << 38;
    uint256 internal constant _ROLE_39 = 1 << 39;
    uint256 internal constant _ROLE_40 = 1 << 40;
    uint256 internal constant _ROLE_41 = 1 << 41;
    uint256 internal constant _ROLE_42 = 1 << 42;
    uint256 internal constant _ROLE_43 = 1 << 43;
    uint256 internal constant _ROLE_44 = 1 << 44;
    uint256 internal constant _ROLE_45 = 1 << 45;
    uint256 internal constant _ROLE_46 = 1 << 46;
    uint256 internal constant _ROLE_47 = 1 << 47;
    uint256 internal constant _ROLE_48 = 1 << 48;
    uint256 internal constant _ROLE_49 = 1 << 49;
    uint256 internal constant _ROLE_50 = 1 << 50;
    uint256 internal constant _ROLE_51 = 1 << 51;
    uint256 internal constant _ROLE_52 = 1 << 52;
    uint256 internal constant _ROLE_53 = 1 << 53;
    uint256 internal constant _ROLE_54 = 1 << 54;
    uint256 internal constant _ROLE_55 = 1 << 55;
    uint256 internal constant _ROLE_56 = 1 << 56;
    uint256 internal constant _ROLE_57 = 1 << 57;
    uint256 internal constant _ROLE_58 = 1 << 58;
    uint256 internal constant _ROLE_59 = 1 << 59;
    uint256 internal constant _ROLE_60 = 1 << 60;
    uint256 internal constant _ROLE_61 = 1 << 61;
    uint256 internal constant _ROLE_62 = 1 << 62;
    uint256 internal constant _ROLE_63 = 1 << 63;
    uint256 internal constant _ROLE_64 = 1 << 64;
    uint256 internal constant _ROLE_65 = 1 << 65;
    uint256 internal constant _ROLE_66 = 1 << 66;
    uint256 internal constant _ROLE_67 = 1 << 67;
    uint256 internal constant _ROLE_68 = 1 << 68;
    uint256 internal constant _ROLE_69 = 1 << 69;
    uint256 internal constant _ROLE_70 = 1 << 70;
    uint256 internal constant _ROLE_71 = 1 << 71;
    uint256 internal constant _ROLE_72 = 1 << 72;
    uint256 internal constant _ROLE_73 = 1 << 73;
    uint256 internal constant _ROLE_74 = 1 << 74;
    uint256 internal constant _ROLE_75 = 1 << 75;
    uint256 internal constant _ROLE_76 = 1 << 76;
    uint256 internal constant _ROLE_77 = 1 << 77;
    uint256 internal constant _ROLE_78 = 1 << 78;
    uint256 internal constant _ROLE_79 = 1 << 79;
    uint256 internal constant _ROLE_80 = 1 << 80;
    uint256 internal constant _ROLE_81 = 1 << 81;
    uint256 internal constant _ROLE_82 = 1 << 82;
    uint256 internal constant _ROLE_83 = 1 << 83;
    uint256 internal constant _ROLE_84 = 1 << 84;
    uint256 internal constant _ROLE_85 = 1 << 85;
    uint256 internal constant _ROLE_86 = 1 << 86;
    uint256 internal constant _ROLE_87 = 1 << 87;
    uint256 internal constant _ROLE_88 = 1 << 88;
    uint256 internal constant _ROLE_89 = 1 << 89;
    uint256 internal constant _ROLE_90 = 1 << 90;
    uint256 internal constant _ROLE_91 = 1 << 91;
    uint256 internal constant _ROLE_92 = 1 << 92;
    uint256 internal constant _ROLE_93 = 1 << 93;
    uint256 internal constant _ROLE_94 = 1 << 94;
    uint256 internal constant _ROLE_95 = 1 << 95;
    uint256 internal constant _ROLE_96 = 1 << 96;
    uint256 internal constant _ROLE_97 = 1 << 97;
    uint256 internal constant _ROLE_98 = 1 << 98;
    uint256 internal constant _ROLE_99 = 1 << 99;
    uint256 internal constant _ROLE_100 = 1 << 100;
    uint256 internal constant _ROLE_101 = 1 << 101;
    uint256 internal constant _ROLE_102 = 1 << 102;
    uint256 internal constant _ROLE_103 = 1 << 103;
    uint256 internal constant _ROLE_104 = 1 << 104;
    uint256 internal constant _ROLE_105 = 1 << 105;
    uint256 internal constant _ROLE_106 = 1 << 106;
    uint256 internal constant _ROLE_107 = 1 << 107;
    uint256 internal constant _ROLE_108 = 1 << 108;
    uint256 internal constant _ROLE_109 = 1 << 109;
    uint256 internal constant _ROLE_110 = 1 << 110;
    uint256 internal constant _ROLE_111 = 1 << 111;
    uint256 internal constant _ROLE_112 = 1 << 112;
    uint256 internal constant _ROLE_113 = 1 << 113;
    uint256 internal constant _ROLE_114 = 1 << 114;
    uint256 internal constant _ROLE_115 = 1 << 115;
    uint256 internal constant _ROLE_116 = 1 << 116;
    uint256 internal constant _ROLE_117 = 1 << 117;
    uint256 internal constant _ROLE_118 = 1 << 118;
    uint256 internal constant _ROLE_119 = 1 << 119;
    uint256 internal constant _ROLE_120 = 1 << 120;
    uint256 internal constant _ROLE_121 = 1 << 121;
    uint256 internal constant _ROLE_122 = 1 << 122;
    uint256 internal constant _ROLE_123 = 1 << 123;
    uint256 internal constant _ROLE_124 = 1 << 124;
    uint256 internal constant _ROLE_125 = 1 << 125;
    uint256 internal constant _ROLE_126 = 1 << 126;
    uint256 internal constant _ROLE_127 = 1 << 127;
    uint256 internal constant _ROLE_128 = 1 << 128;
    uint256 internal constant _ROLE_129 = 1 << 129;
    uint256 internal constant _ROLE_130 = 1 << 130;
    uint256 internal constant _ROLE_131 = 1 << 131;
    uint256 internal constant _ROLE_132 = 1 << 132;
    uint256 internal constant _ROLE_133 = 1 << 133;
    uint256 internal constant _ROLE_134 = 1 << 134;
    uint256 internal constant _ROLE_135 = 1 << 135;
    uint256 internal constant _ROLE_136 = 1 << 136;
    uint256 internal constant _ROLE_137 = 1 << 137;
    uint256 internal constant _ROLE_138 = 1 << 138;
    uint256 internal constant _ROLE_139 = 1 << 139;
    uint256 internal constant _ROLE_140 = 1 << 140;
    uint256 internal constant _ROLE_141 = 1 << 141;
    uint256 internal constant _ROLE_142 = 1 << 142;
    uint256 internal constant _ROLE_143 = 1 << 143;
    uint256 internal constant _ROLE_144 = 1 << 144;
    uint256 internal constant _ROLE_145 = 1 << 145;
    uint256 internal constant _ROLE_146 = 1 << 146;
    uint256 internal constant _ROLE_147 = 1 << 147;
    uint256 internal constant _ROLE_148 = 1 << 148;
    uint256 internal constant _ROLE_149 = 1 << 149;
    uint256 internal constant _ROLE_150 = 1 << 150;
    uint256 internal constant _ROLE_151 = 1 << 151;
    uint256 internal constant _ROLE_152 = 1 << 152;
    uint256 internal constant _ROLE_153 = 1 << 153;
    uint256 internal constant _ROLE_154 = 1 << 154;
    uint256 internal constant _ROLE_155 = 1 << 155;
    uint256 internal constant _ROLE_156 = 1 << 156;
    uint256 internal constant _ROLE_157 = 1 << 157;
    uint256 internal constant _ROLE_158 = 1 << 158;
    uint256 internal constant _ROLE_159 = 1 << 159;
    uint256 internal constant _ROLE_160 = 1 << 160;
    uint256 internal constant _ROLE_161 = 1 << 161;
    uint256 internal constant _ROLE_162 = 1 << 162;
    uint256 internal constant _ROLE_163 = 1 << 163;
    uint256 internal constant _ROLE_164 = 1 << 164;
    uint256 internal constant _ROLE_165 = 1 << 165;
    uint256 internal constant _ROLE_166 = 1 << 166;
    uint256 internal constant _ROLE_167 = 1 << 167;
    uint256 internal constant _ROLE_168 = 1 << 168;
    uint256 internal constant _ROLE_169 = 1 << 169;
    uint256 internal constant _ROLE_170 = 1 << 170;
    uint256 internal constant _ROLE_171 = 1 << 171;
    uint256 internal constant _ROLE_172 = 1 << 172;
    uint256 internal constant _ROLE_173 = 1 << 173;
    uint256 internal constant _ROLE_174 = 1 << 174;
    uint256 internal constant _ROLE_175 = 1 << 175;
    uint256 internal constant _ROLE_176 = 1 << 176;
    uint256 internal constant _ROLE_177 = 1 << 177;
    uint256 internal constant _ROLE_178 = 1 << 178;
    uint256 internal constant _ROLE_179 = 1 << 179;
    uint256 internal constant _ROLE_180 = 1 << 180;
    uint256 internal constant _ROLE_181 = 1 << 181;
    uint256 internal constant _ROLE_182 = 1 << 182;
    uint256 internal constant _ROLE_183 = 1 << 183;
    uint256 internal constant _ROLE_184 = 1 << 184;
    uint256 internal constant _ROLE_185 = 1 << 185;
    uint256 internal constant _ROLE_186 = 1 << 186;
    uint256 internal constant _ROLE_187 = 1 << 187;
    uint256 internal constant _ROLE_188 = 1 << 188;
    uint256 internal constant _ROLE_189 = 1 << 189;
    uint256 internal constant _ROLE_190 = 1 << 190;
    uint256 internal constant _ROLE_191 = 1 << 191;
    uint256 internal constant _ROLE_192 = 1 << 192;
    uint256 internal constant _ROLE_193 = 1 << 193;
    uint256 internal constant _ROLE_194 = 1 << 194;
    uint256 internal constant _ROLE_195 = 1 << 195;
    uint256 internal constant _ROLE_196 = 1 << 196;
    uint256 internal constant _ROLE_197 = 1 << 197;
    uint256 internal constant _ROLE_198 = 1 << 198;
    uint256 internal constant _ROLE_199 = 1 << 199;
    uint256 internal constant _ROLE_200 = 1 << 200;
    uint256 internal constant _ROLE_201 = 1 << 201;
    uint256 internal constant _ROLE_202 = 1 << 202;
    uint256 internal constant _ROLE_203 = 1 << 203;
    uint256 internal constant _ROLE_204 = 1 << 204;
    uint256 internal constant _ROLE_205 = 1 << 205;
    uint256 internal constant _ROLE_206 = 1 << 206;
    uint256 internal constant _ROLE_207 = 1 << 207;
    uint256 internal constant _ROLE_208 = 1 << 208;
    uint256 internal constant _ROLE_209 = 1 << 209;
    uint256 internal constant _ROLE_210 = 1 << 210;
    uint256 internal constant _ROLE_211 = 1 << 211;
    uint256 internal constant _ROLE_212 = 1 << 212;
    uint256 internal constant _ROLE_213 = 1 << 213;
    uint256 internal constant _ROLE_214 = 1 << 214;
    uint256 internal constant _ROLE_215 = 1 << 215;
    uint256 internal constant _ROLE_216 = 1 << 216;
    uint256 internal constant _ROLE_217 = 1 << 217;
    uint256 internal constant _ROLE_218 = 1 << 218;
    uint256 internal constant _ROLE_219 = 1 << 219;
    uint256 internal constant _ROLE_220 = 1 << 220;
    uint256 internal constant _ROLE_221 = 1 << 221;
    uint256 internal constant _ROLE_222 = 1 << 222;
    uint256 internal constant _ROLE_223 = 1 << 223;
    uint256 internal constant _ROLE_224 = 1 << 224;
    uint256 internal constant _ROLE_225 = 1 << 225;
    uint256 internal constant _ROLE_226 = 1 << 226;
    uint256 internal constant _ROLE_227 = 1 << 227;
    uint256 internal constant _ROLE_228 = 1 << 228;
    uint256 internal constant _ROLE_229 = 1 << 229;
    uint256 internal constant _ROLE_230 = 1 << 230;
    uint256 internal constant _ROLE_231 = 1 << 231;
    uint256 internal constant _ROLE_232 = 1 << 232;
    uint256 internal constant _ROLE_233 = 1 << 233;
    uint256 internal constant _ROLE_234 = 1 << 234;
    uint256 internal constant _ROLE_235 = 1 << 235;
    uint256 internal constant _ROLE_236 = 1 << 236;
    uint256 internal constant _ROLE_237 = 1 << 237;
    uint256 internal constant _ROLE_238 = 1 << 238;
    uint256 internal constant _ROLE_239 = 1 << 239;
    uint256 internal constant _ROLE_240 = 1 << 240;
    uint256 internal constant _ROLE_241 = 1 << 241;
    uint256 internal constant _ROLE_242 = 1 << 242;
    uint256 internal constant _ROLE_243 = 1 << 243;
    uint256 internal constant _ROLE_244 = 1 << 244;
    uint256 internal constant _ROLE_245 = 1 << 245;
    uint256 internal constant _ROLE_246 = 1 << 246;
    uint256 internal constant _ROLE_247 = 1 << 247;
    uint256 internal constant _ROLE_248 = 1 << 248;
    uint256 internal constant _ROLE_249 = 1 << 249;
    uint256 internal constant _ROLE_250 = 1 << 250;
    uint256 internal constant _ROLE_251 = 1 << 251;
    uint256 internal constant _ROLE_252 = 1 << 252;
    uint256 internal constant _ROLE_253 = 1 << 253;
    uint256 internal constant _ROLE_254 = 1 << 254;
    uint256 internal constant _ROLE_255 = 1 << 255;
}

File 9 of 42 : IMachineZap.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {IWatermarkFeeManager} from "@makina-periphery/interfaces/IWatermarkFeeManager.sol";
import {ICaliber} from "@makina-core/interfaces/ICaliber.sol";
import {IMakinaGovernable} from "@makina-core/interfaces/IMakinaGovernable.sol";

interface IMachineZap {
    function createMachine(
        string calldata shareTokenName,
        string calldata shareTokenSymbol,
        address accountingToken,
        address[] calldata baseTokens,
        bytes32 salt,
        uint16 depositorImplemId,
        bool depositorWhitelistStatus,
        uint16 redeemerImplemId,
        bool redeemerWhitelistStatus,
        uint256 redeemerFinalizationDelay,
        uint256 redeemerMinRedeemAmount,
        uint16 feeManagerImplemId,
        IWatermarkFeeManager.WatermarkFeeManagerInitParams calldata feeManagerInitParams,
        MachineInitParams calldata machineInitParams,
        ICaliber.CaliberInitParams calldata caliberInitParams,
        IMakinaGovernable.MakinaGovernableInitParams calldata mgInitParams
    ) external returns (address machine);

    struct MachineInitParams {
        uint256 initialCaliberStaleThreshold;
        uint256 initialMaxFixedFeeAccrualRate;
        uint256 initialMaxPerfFeeAccrualRate;
        uint256 initialFeeMintCooldown;
        uint256 initialShareLimit;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IFeeManager {
    /// @notice Calculates the fixed fee for a given share supply and elapsed time.
    /// @dev May update internal state related to fee accrual or realization.
    /// @param shareSupply The total supply of shares.
    /// @param elapsedTime The elapsed time since the last fee realization.
    /// @return fee The calculated fixed fee.
    function calculateFixedFee(uint256 shareSupply, uint256 elapsedTime) external returns (uint256);

    /// @notice Calculates the performance fee based on the share supply, share price performance and elapsed time.
    /// @dev May update internal state related to fee accrual or realization.
    /// @param currentShareSupply The current total supply of shares.
    /// @param oldSharePrice The previous share price of reference.
    /// @param newSharePrice The new share price of reference.
    /// @param elapsedTime The elapsed time since the last fee realization.
    /// @return fee The calculated performance fee.
    function calculatePerformanceFee(
        uint256 currentShareSupply,
        uint256 oldSharePrice,
        uint256 newSharePrice,
        uint256 elapsedTime
    ) external returns (uint256);

    /// @notice Distributes the fees to relevant recipients.
    /// @param fixedFee The fixed fee amount to be distributed.
    /// @param perfFee The performance fee amount to be distributed.
    function distributeFees(uint256 fixedFee, uint256 perfFee) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IMachinePeriphery {
    event MachineSet(address indexed machine);

    /// @notice Initializer of the contract.
    /// @param _data The initialization data, if any.
    function initialize(bytes calldata _data) external;

    /// @notice Address of the associated machine.
    function machine() external view returns (address);

    /// @notice Sets the machine address.
    function setMachine(address _machine) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface ISecurityModuleReference {
    /// @notice Security module address.
    function securityModule() external view returns (address);

    /// @notice Sets the security module address.
    /// @param securityModule The address of the security module.
    function setSecurityModule(address securityModule) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

import {IMachinePeriphery} from "../interfaces/IMachinePeriphery.sol";

interface ISecurityModule is IERC20Metadata, IMachinePeriphery {
    event Cooldown(
        uint256 indexed cooldownId, address indexed account, address indexed receiver, uint256 shares, uint256 maturity
    );
    event CooldownCancelled(uint256 indexed cooldownId, address indexed receiver, uint256 shares);
    event CooldownDurationChanged(uint256 oldCooldownDuration, uint256 newCooldownDuration);
    event MaxSlashableBpsChanged(uint256 oldMaxSlashableBps, uint256 newMaxSlashableBps);
    event MinBalanceAfterSlashChanged(uint256 oldMinBalanceAfterSlash, uint256 newMinBalanceAfterSlash);
    event Lock(address indexed account, address indexed receiver, uint256 assets, uint256 shares);
    event Redeem(uint256 indexed cooldownId, address indexed receiver, uint256 assets, uint256 shares);
    event Slash(uint256 amount);
    event SlashingSettled();

    /// @notice Initialization parameters.
    /// @param machineShare Address of the machine share token locked in this contract.
    /// @param initialCooldownDuration Cooldown duration in seconds for unlocking.
    /// @param initialMaxSlashableBps Maximum slashable proportion of the vault balance in basis points.
    /// @param minBalanceAfterSlash Minimum balance that must remain in the vault after a slash.
    struct SecurityModuleInitParams {
        address machineShare;
        uint256 initialCooldownDuration;
        uint256 initialMaxSlashableBps;
        uint256 initialMinBalanceAfterSlash;
    }

    /// @notice Pending cooldown parameters.
    /// @param shares Amount of security shares to be redeemed.
    /// @param maxAssets Maximum amount of machine shares that can be redeemed.
    /// @param maturity Timestamp at which the cooldown period will end and the shares can be redeemed.
    struct PendingCooldown {
        uint256 shares;
        uint256 maxAssets;
        uint256 maturity;
    }

    /// @notice Address of the machine share token locked in this contract.
    function machineShare() external view returns (address);

    /// @notice Address of the cooldown receipt NFT.
    function cooldownReceipt() external view returns (address);

    /// @notice Cooldown duration in seconds for unlocking.
    function cooldownDuration() external view returns (uint256);

    /// @notice Maximum slashable proportion of the vault balance in basis points.
    function maxSlashableBps() external view returns (uint256);

    /// @notice Minimum balance that must remain in the vault after a slash.
    function minBalanceAfterSlash() external view returns (uint256);

    /// @notice Returns data of a pending cooldown.
    /// @param cooldownId ID of the cooldown receipt NFT representing the pending cooldown.
    /// @return shares Amount of security shares to be redeemed.
    /// @return currentExpectedAssets Current expected amount of machine shares that can be redeemed.
    /// @return maturity Timestamp at which the cooldown period will end and the shares can be redeemed.
    function pendingCooldown(uint256 cooldownId)
        external
        view
        returns (uint256 shares, uint256 currentExpectedAssets, uint256 maturity);

    /// @notice Whether the security module is in slashing mode.
    function slashingMode() external view returns (bool);

    /// @notice Total amount of machine shares locked in the module.
    function totalLockedAmount() external view returns (uint256);

    /// @notice Total amount of machine shares currently slashable in the module.
    function maxSlashable() external view returns (uint256);

    /// @notice Converts machine shares to security shares.
    /// @param assets Amount of machine shares to convert.
    /// @return shares Amount of security shares corresponding to the input machine shares.
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /// @notice Converts security shares to machine shares.
    /// @param shares Amount of security shares to convert.
    /// @return assets Amount of machine shares corresponding to the input security shares.
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /// @notice Estimates the amount of security shares that would be received for a given amount of machine shares.
    /// @param assets Amount of machine shares to convert.
    /// @return shares Estimated amount of security shares corresponding to the input machine shares.
    function previewLock(uint256 assets) external view returns (uint256 shares);

    /// @notice Locks machine shares in the module and mints security shares.
    /// @param assets Amount of machine shares to lock.
    /// @param receiver Address that will receive the security shares.
    /// @param minShares Minimum amount of security shares to receive.
    /// @return shares Amount of security shares minted.
    function lock(uint256 assets, address receiver, uint256 minShares) external returns (uint256 shares);

    /// @notice Requests a cooldown for redeeming security shares.
    ///         Shares are locked in the contract until the cooldown is cancelled or expires.
    ///         A cooldown receipt NFT is minted to the specified receiver address.
    /// @param shares Amount of security shares to redeem.
    /// @param receiver Address that will receive the cooldown receipt.
    /// @return cooldownId ID of the minted cooldown receipt NFT representing the pending cooldown.
    /// @return maxAssets Maximum amount of machine shares that can be redeemed.
    /// @return maturity Timestamp at which the cooldown period will end and the shares can be redeemed.
    function startCooldown(uint256 shares, address receiver)
        external
        returns (uint256 cooldownId, uint256 maxAssets, uint256 maturity);

    /// @notice Cancels a pending cooldown.
    ///         Shares for which the cooldown was cancelled are transferred back to caller.
    ///         The associated cooldown receipt NFT is burned.
    /// @param cooldownId ID of the cooldown receipt NFT representing the pending cooldown.
    /// @return shares Amount of security shares for which the cooldown was cancelled.
    function cancelCooldown(uint256 cooldownId) external returns (uint256 shares);

    /// @notice Redeems security shares and transfers machine shares to caller.
    /// @param cooldownId ID of the cooldown receipt NFT representing the pending cooldown.
    /// @param minAssets Minimum amount of machine shares to receive.
    /// @return assets Amount of machine shares transferred to the receiver.
    function redeem(uint256 cooldownId, uint256 minAssets) external returns (uint256 assets);

    /// @notice Slashes a specified amount from the total locked amount and triggers the slashing mode.
    /// @param amount Amount to slash from the total locked amount.
    function slash(uint256 amount) external;

    /// @notice Settles the current slashing, allowing the contract to exit slashing mode and resume normal operations.
    function settleSlashing() external;

    /// @notice Sets the cooldown duration for unlocking.
    /// @param cooldownDuration New cooldown duration in seconds.
    function setCooldownDuration(uint256 cooldownDuration) external;

    /// @notice Sets the maximum slashable proportion of the vault balance in basis points.
    /// @param maxSlashableBps New maximum slashable proportion in basis points.
    function setMaxSlashableBps(uint256 maxSlashableBps) external;

    /// @notice Sets the minimum balance that must remain in the vault after a slash.
    /// @param minBalanceAfterSlash New minimum balance after slash.
    function setMinBalanceAfterSlash(uint256 minBalanceAfterSlash) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IPreDepositVault {
    event Deposit(address indexed sender, address indexed receiver, uint256 assets, uint256 shares);
    event MigrateToMachine(address indexed machine);
    event Redeem(address indexed owner, address indexed receiver, uint256 assets, uint256 shares);
    event RiskManagerChanged(address indexed oldRiskManager, address indexed newRiskManager);
    event ShareLimitChanged(uint256 indexed oldShareLimit, uint256 indexed newShareLimit);
    event UserWhitelistingChanged(address indexed user, bool indexed whitelisted);
    event WhitelistModeChanged(bool indexed enabled);

    struct PreDepositVaultInitParams {
        uint256 initialShareLimit;
        bool initialWhitelistMode;
        address initialRiskManager;
        address initialAuthority;
    }

    /// @notice Initializer of the contract.
    /// @param params The initialization parameters.
    /// @param shareToken The address of the share token.
    /// @param depositToken The address of the deposit token.
    /// @param accountingToken The address of the accounting token.
    function initialize(
        PreDepositVaultInitParams calldata params,
        address shareToken,
        address depositToken,
        address accountingToken
    ) external;

    /// @notice True if the vault has migrated to a machine instance, false otherwise.
    function migrated() external view returns (bool);

    /// @notice Address of the machine, set during migration.
    function machine() external view returns (address);

    /// @notice Address of the risk manager.
    function riskManager() external view returns (address);

    /// @notice True if the vault is in whitelist mode, false otherwise.
    function whitelistMode() external view returns (bool);

    /// @notice User => Whitelisting status.
    function isWhitelistedUser(address user) external view returns (bool);

    /// @notice Address of the deposit token.
    function depositToken() external view returns (address);

    /// @notice Address of the accounting token.
    function accountingToken() external view returns (address);

    /// @notice Address of the share token.
    function shareToken() external view returns (address);

    /// @notice Share token supply limit that cannot be exceeded by new deposits.
    function shareLimit() external view returns (uint256);

    /// @notice Maximum amount of deposit tokens that can currently be deposited in the vault.
    function maxDeposit() external view returns (uint256);

    /// @notice Total amount of deposit tokens managed by the vault.
    function totalAssets() external view returns (uint256);

    /// @notice Amount of shares minted against a given amount of deposit tokens.
    /// @param assets The amount of deposit tokens to be deposited.
    function previewDeposit(uint256 assets) external view returns (uint256);

    /// @notice Amount of deposit tokens that can be withdrawn against a given amount of shares.
    /// @param assets The amount of shares to be redeemed.
    function previewRedeem(uint256 assets) external view returns (uint256);

    /// @notice Deposits a given amount of deposit tokens and mints shares to the receiver.
    /// @param assets The amount of deposit tokens to be deposited.
    /// @param receiver The receiver of the shares.
    /// @param minShares The minimum amount of shares to be minted.
    /// @return shares The amount of shares minted.
    function deposit(uint256 assets, address receiver, uint256 minShares) external returns (uint256);

    /// @notice Burns exactly shares from caller and transfers the corresponding amount of deposit tokens to the receiver.
    /// @param shares The amount of shares to be redeemed.
    /// @param receiver The receiver of withdrawn deposit tokens.
    /// @param minAssets The minimum amount of deposit tokens to be transferred.
    /// @return assets The amount of deposit tokens transferred.
    function redeem(uint256 shares, address receiver, uint256 minAssets) external returns (uint256);

    /// @notice Migrates the pre-deposit vault to the machine.
    function migrateToMachine() external;

    /// @notice Sets the machine address to migrate to.
    /// @param machine The address of the machine.
    function setPendingMachine(address machine) external;

    /// @notice Sets the risk manager address.
    /// @param newRiskManager The address of the new risk manager.
    function setRiskManager(address newRiskManager) external;

    /// @notice Sets the new share token supply limit that cannot be exceeded by new deposits.
    /// @param newShareLimit The new share limit
    function setShareLimit(uint256 newShareLimit) external;

    /// @notice Whitelist or unwhitelist a list of users.
    /// @param users The addresses of the users to update.
    /// @param whitelisted True to whitelist the users, false to unwhitelist.
    function setWhitelistedUsers(address[] calldata users, bool whitelisted) external;

    /// @notice Sets the whitelist mode for the vault.
    /// @dev In whitelist mode, only whitelisted users can deposit.
    /// @param enabled True to enable whitelist mode, false to disable.
    function setWhitelistMode(bool enabled) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IBridgeAdapterFactory {
    event BridgeAdapterCreated(address indexed controller, uint256 indexed bridgeId, address indexed adapter);

    /// @notice Address => Whether this is a BridgeAdapter instance deployed by this factory.
    function isBridgeAdapter(address adapter) external view returns (bool);

    /// @notice Deploys a bridge adapter instance.
    /// @param bridgeId The ID of the bridge for which the adapter is being created.
    /// @param initData The optional initialization data for the bridge adapter.
    /// @return adapter The address of the deployed bridge adapter.
    function createBridgeAdapter(uint16 bridgeId, bytes calldata initData) external returns (address adapter);
}

File 16 of 42 : EnumerableMap.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.

pragma solidity ^0.8.20;

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

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 * - Map can be cleared (all entries removed) in O(n).
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableMap for EnumerableMap.UintToAddressMap;
 *
 *     // Declare a set state variable
 *     EnumerableMap.UintToAddressMap private myMap;
 * }
 * ```
 *
 * The following map types are supported:
 *
 * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0
 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
 * - `uint256 -> bytes32` (`UintToBytes32Map`) since v5.1.0
 * - `address -> address` (`AddressToAddressMap`) since v5.1.0
 * - `address -> bytes32` (`AddressToBytes32Map`) since v5.1.0
 * - `bytes32 -> address` (`Bytes32ToAddressMap`) since v5.1.0
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableMap.
 * ====
 */
library EnumerableMap {
    using EnumerableSet for EnumerableSet.Bytes32Set;

    // To implement this library for multiple types with as little code repetition as possible, we write it in
    // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,
    // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.
    // This means that we can only create new EnumerableMaps for types that fit in bytes32.

    /**
     * @dev Query for a nonexistent map key.
     */
    error EnumerableMapNonexistentKey(bytes32 key);

    struct Bytes32ToBytes32Map {
        // Storage of keys
        EnumerableSet.Bytes32Set _keys;
        mapping(bytes32 key => bytes32) _values;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
        map._values[key] = value;
        return map._keys.add(key);
    }

    /**
     * @dev Removes a key-value pair from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
        delete map._values[key];
        return map._keys.remove(key);
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(Bytes32ToBytes32Map storage map) internal {
        uint256 len = length(map);
        for (uint256 i = 0; i < len; ++i) {
            delete map._values[map._keys.at(i)];
        }
        map._keys.clear();
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
        return map._keys.contains(key);
    }

    /**
     * @dev Returns the number of key-value pairs in the map. O(1).
     */
    function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
        return map._keys.length();
    }

    /**
     * @dev Returns the key-value pair stored at position `index` in the map. O(1).
     *
     * Note that there are no guarantees on the ordering of entries inside the
     * array, and it may change when more entries are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32 key, bytes32 value) {
        bytes32 atKey = map._keys.at(index);
        return (atKey, map._values[atKey]);
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) {
        bytes32 val = map._values[key];
        if (val == bytes32(0)) {
            return (contains(map, key), bytes32(0));
        } else {
            return (true, val);
        }
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
        bytes32 value = map._values[key];
        if (value == 0 && !contains(map, key)) {
            revert EnumerableMapNonexistentKey(key);
        }
        return value;
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
        return map._keys.values();
    }

    // UintToUintMap

    struct UintToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
        return set(map._inner, bytes32(key), bytes32(value));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
        return remove(map._inner, bytes32(key));
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(UintToUintMap storage map) internal {
        clear(map._inner);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
        return contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. O(1).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintToUintMap storage map, uint256 index) internal view returns (uint256 key, uint256 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (uint256(atKey), uint256(val));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool exists, uint256 value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
        return (success, uint256(val));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
        return uint256(get(map._inner, bytes32(key)));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
        bytes32[] memory store = keys(map._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // UintToAddressMap

    struct UintToAddressMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
        return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
        return remove(map._inner, bytes32(key));
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(UintToAddressMap storage map) internal {
        clear(map._inner);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
        return contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToAddressMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. O(1).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256 key, address value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (uint256(atKey), address(uint160(uint256(val))));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool exists, address value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
        return (success, address(uint160(uint256(val))));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
        return address(uint160(uint256(get(map._inner, bytes32(key)))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
        bytes32[] memory store = keys(map._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // UintToBytes32Map

    struct UintToBytes32Map {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToBytes32Map storage map, uint256 key, bytes32 value) internal returns (bool) {
        return set(map._inner, bytes32(key), value);
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToBytes32Map storage map, uint256 key) internal returns (bool) {
        return remove(map._inner, bytes32(key));
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(UintToBytes32Map storage map) internal {
        clear(map._inner);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToBytes32Map storage map, uint256 key) internal view returns (bool) {
        return contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToBytes32Map storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. O(1).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintToBytes32Map storage map, uint256 index) internal view returns (uint256 key, bytes32 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (uint256(atKey), val);
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool exists, bytes32 value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
        return (success, val);
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToBytes32Map storage map, uint256 key) internal view returns (bytes32) {
        return get(map._inner, bytes32(key));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(UintToBytes32Map storage map) internal view returns (uint256[] memory) {
        bytes32[] memory store = keys(map._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressToUintMap

    struct AddressToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
        return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(AddressToUintMap storage map, address key) internal returns (bool) {
        return remove(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(AddressToUintMap storage map) internal {
        clear(map._inner);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
        return contains(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(AddressToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. O(1).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressToUintMap storage map, uint256 index) internal view returns (address key, uint256 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (address(uint160(uint256(atKey))), uint256(val));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(AddressToUintMap storage map, address key) internal view returns (bool exists, uint256 value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
        return (success, uint256(val));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
        return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
        bytes32[] memory store = keys(map._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressToAddressMap

    struct AddressToAddressMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(AddressToAddressMap storage map, address key, address value) internal returns (bool) {
        return set(map._inner, bytes32(uint256(uint160(key))), bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(AddressToAddressMap storage map, address key) internal returns (bool) {
        return remove(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(AddressToAddressMap storage map) internal {
        clear(map._inner);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(AddressToAddressMap storage map, address key) internal view returns (bool) {
        return contains(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(AddressToAddressMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. O(1).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressToAddressMap storage map, uint256 index) internal view returns (address key, address value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (address(uint160(uint256(atKey))), address(uint160(uint256(val))));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool exists, address value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
        return (success, address(uint160(uint256(val))));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(AddressToAddressMap storage map, address key) internal view returns (address) {
        return address(uint160(uint256(get(map._inner, bytes32(uint256(uint160(key)))))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(AddressToAddressMap storage map) internal view returns (address[] memory) {
        bytes32[] memory store = keys(map._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressToBytes32Map

    struct AddressToBytes32Map {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) {
        return set(map._inner, bytes32(uint256(uint160(key))), value);
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(AddressToBytes32Map storage map, address key) internal returns (bool) {
        return remove(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(AddressToBytes32Map storage map) internal {
        clear(map._inner);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(AddressToBytes32Map storage map, address key) internal view returns (bool) {
        return contains(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(AddressToBytes32Map storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. O(1).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressToBytes32Map storage map, uint256 index) internal view returns (address key, bytes32 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (address(uint160(uint256(atKey))), val);
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool exists, bytes32 value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
        return (success, val);
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) {
        return get(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(AddressToBytes32Map storage map) internal view returns (address[] memory) {
        bytes32[] memory store = keys(map._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // Bytes32ToUintMap

    struct Bytes32ToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
        return set(map._inner, key, bytes32(value));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
        return remove(map._inner, key);
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(Bytes32ToUintMap storage map) internal {
        clear(map._inner);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
        return contains(map._inner, key);
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. O(1).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32 key, uint256 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (atKey, uint256(val));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool exists, uint256 value) {
        (bool success, bytes32 val) = tryGet(map._inner, key);
        return (success, uint256(val));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
        return uint256(get(map._inner, key));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
        bytes32[] memory store = keys(map._inner);
        bytes32[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // Bytes32ToAddressMap

    struct Bytes32ToAddressMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(Bytes32ToAddressMap storage map, bytes32 key, address value) internal returns (bool) {
        return set(map._inner, key, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(Bytes32ToAddressMap storage map, bytes32 key) internal returns (bool) {
        return remove(map._inner, key);
    }

    /**
     * @dev Removes all the entries from a map. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(Bytes32ToAddressMap storage map) internal {
        clear(map._inner);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool) {
        return contains(map._inner, key);
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(Bytes32ToAddressMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. O(1).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32ToAddressMap storage map, uint256 index) internal view returns (bytes32 key, address value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (atKey, address(uint160(uint256(val))));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool exists, address value) {
        (bool success, bytes32 val) = tryGet(map._inner, key);
        return (success, address(uint160(uint256(val))));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (address) {
        return address(uint160(uint256(get(map._inner, key))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(Bytes32ToAddressMap storage map) internal view returns (bytes32[] memory) {
        bytes32[] memory store = keys(map._inner);
        bytes32[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }
}

File 17 of 42 : VaaLib.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.14; //for (bugfixed) support of `using ... global;` syntax for libraries

import {IWormhole} from "wormhole-sdk/interfaces/IWormhole.sol";
import {BytesParsing} from "wormhole-sdk/libraries/BytesParsing.sol";
import {
  toUniversalAddress,
  keccak256Cd,
  keccak256Word,
  keccak256SliceUnchecked
} from "wormhole-sdk/Utils.sol";

// ╭─────────────────────────────────────────────────╮
// │ Library for encoding and decoding Wormhole VAAs │
// ╰─────────────────────────────────────────────────╯

// # VAA Format
//
// see:
//  * ../interfaces/IWormhole.sol VM struct (VM = Verified Message)
//  * [CoreBridge](https://github.com/wormhole-foundation/wormhole/blob/c35940ae9689f6df9e983d51425763509b74a80f/ethereum/contracts/Messages.sol#L147)
//  * [Typescript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/3cd10030b5e924f0621c7231e24410b8a0946a07/core/definitions/src/vaa/vaa.ts#L32-L51)
//
// ╭──────────┬──────────────────────────────────────────────────────────────────────────────╮
// │ Section  │ Description                                                                  │
// ├──────────┼──────────────────────────────────────────────────────────────────────────────┤
// │ Header   │ version, guardian signature info required to verify the VAA                  │
// │ Envelope │ contains metadata of the emitted message, such as emitter or timestamp       │
// │ Payload  │ the emitted message, raw bytes, no length prefix, consumes remainder of data │
// ╰──────────┴──────────────────────────────────────────────────────────────────────────────╯
// Body = Envelope + Payload
// The VAA body is exactly the information that goes into a published message of the CoreBridge
//   and is what gets keccak256-hashed when calculating the VAA hash (i.e. the header is excluded).
//
// Note:
//   Guardians do _not_ sign the body directly, but rather the hash of the body, i.e. from the PoV
//     of a guardian, the message itself is already only a hash.
//   But [the first step of the ECDSA signature scheme](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_generation_algorithm)
//     is to hash the message, leading to the hash being hashed a second time when signing.
//   Likewise, ecrecover also operates on the hash of the message, rather than the message itself.
//   This means that when verifying guardian signatures of a VAA, the hash that must be passed to
//     ecrecover is the doubly-hashed body.
//
// ╭─────────────────────────────────────── WARNING ───────────────────────────────────────╮
// │ There is an unfortunate inconsistency between the implementation of the CoreBridge on │
// │   EVM, where IWormhole.VM.hash is the *doubly* hashed body [1], while everything else │
// │   only uses the singly-hashed body (see Solana CoreBridge [2] and Typescript SDK [3]) │
// ╰───────────────────────────────────────────────────────────────────────────────────────╯
// [1] https://github.com/wormhole-foundation/wormhole/blob/1dbe8459b96e182932d0dd5ae4b6bbce6f48cb09/ethereum/contracts/Messages.sol#L178-L186
// [2] https://github.com/wormhole-foundation/wormhole/blob/1dbe8459b96e182932d0dd5ae4b6bbce6f48cb09/solana/bridge/program/src/api/post_vaa.rs#L214C4-L244
// [3] https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/3cd10030b5e924f0621c7231e24410b8a0946a07/core/definitions/src/vaa/functions.ts#L189
//
// ## Format in Detail
//
// ╭─────────────┬──────────────────┬──────────────────────────────────────────────────────────────╮
// │    Type     │       Name       │     Description                                              │
// ┝━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥
// │           Header                                                                              │
// ├─────────────┬──────────────────┬──────────────────────────────────────────────────────────────┤
// │    uint8    │ version          │ fixed value of 1 (see HEADER_VERSION below)                  │
// │    uint32   │ guardianSetIndex │ the guardian set that signed the VAA                         │
// │    uint8    │ signatureCount   │ must be greater than guardian set size * 2 / 3 for quorum    │
// │ Signature[] │ signatures       │ signatures of the guardians that signed the VAA              │
// ┝━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥
// │          Signature                                                                            │
// ├─────────────┬──────────────────┬──────────────────────────────────────────────────────────────┤
// │    uint8    │ guardianIndex    │ position of the signing guardian in the guardian set         │
// │   bytes32   │ r                │ ECDSA r value                                                │
// │   bytes32   │ s                │ ECDSA s value                                                │
// │    uint8    │ v                │ encoded: 0/1, decoded: 27/28, see SIGNATURE_RECOVERY_MAGIC   │
// ┝━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥
// │          Envelope                                                                             │
// ├─────────────┬──────────────────┬──────────────────────────────────────────────────────────────┤
// │    uint32   │ timestamp        │ unix timestamp of block containing the emitted message       │
// │    uint32   │ nonce            │ user-defined nonce                                           │
// │    uint16   │ emitterChainId   │ Wormhole (not EVM) chain id of the emitter                   │
// │   bytes32   │ emitterAddress   │ universal address of the emitter                             │
// │    uint64   │ sequence         │ sequence number of the message (counter per emitter)         │
// │    uint8    │ consistencyLevel │ https://wormhole.com/docs/build/reference/consistency-levels │
// ┝━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥
// │          Payload                                                                              │
// ├─────────────┬──────────────────┬──────────────────────────────────────────────────────────────┤
// │    bytes    │ payload          │ emitted message, consumes rest of VAA (no length prefix)     │
// ╰─────────────┴──────────────────┴──────────────────────────────────────────────────────────────╯
//
// # Library
//
// This library is built on top of BytesParsing which is a lot more gas efficient than BytesLib,
//   which is used in the CoreBridge.
//
// It also provides decoding functions for parsing the individual components of the VAA separately
//   and returning them on the stack, rather than as a struct which requires memory allocation.
//
// ## Library Functions & Naming Conventions
//
// All library functions come in 2 flavors:
//   1. Calldata (using the Cd tag)
//   2. Memory (using the Mem tag)
//
// Additionally, most functions also have an additional struct flavor that returns the decoded
//   values in the associated struct (in memory), rather than as individual values (on the stack).
//
// The parameter name `encodedVaa` is used for functions where the bytes are expected to contain
//   a single, full VAA. Otherwise, i.e. for partials or multiple VAAs, the name `encoded` is used.
//
// Like in BytesParsing, the Unchecked function name suffix does not refer to Solidity's `unchecked`
//   keyword, but rather to the fact that no bounds checking is performed. All math is done using
//   unchecked arithmetic because overflows are impossible due to the nature of the VAA format,
//   while we explicitly check for underflows where necessary.
//
// Function names, somewhat redundantly, contain the tag "Vaa" to add clarity and avoid potential
//   name collisions when using the library with a `using ... for bytes` directive.
//
//   Function Base Name  │     Description
//  ─────────────────────┼────────────────────────────────────────────────────────────────────────
//   decodeVmStruct      │ decodes a legacy VM struct (no non-struct flavor available)
//   decodeVaaEssentials │ decodes the emitter, sequence, and payload
//   decodeVaaBody       │ decodes the envelope and payload
//   checkVaaVersion     │
//   skipVaaHeader       │ returns the offset to the envelope
//   calcVaaSingleHash   │ see explanation/WARNING box at the top
//   calcVaaDoubleHash   │ see explanation/WARNING box at the top
//   decodeVaaEnvelope   │
//   decodeVaaPayload    │
//
// encode functions (for testing, converts back into serialized byte array format):
//   * encode (overloaded for each struct)
//   * encodeVaaHeader
//   * encodeVaaEnvelope
//   * encodeVaaBody
//   * encodeVaa
//
// other functions:
//   * asIWormholeSignatures (casting between GuardianSignature and IWormhole.Signature)
//   * asGuardianSignatures (casting between GuardianSignature and IWormhole.Signature)

//Annoyingly, Solidity only allows aliasing of types that are exported on the file level, but not
//  of nested types, see [language grammar](https://docs.soliditylang.org/en/v0.8.28/grammar.html#a4.SolidityParser.importDirective)
//So we (re)define GuardianSignature identically to IWormhole.Signature to avoid the explicit
//  dependency and to provide a better name and do the necessary casts manually using assembly.
//Without the alias, users who want to reference the GuardianSignature type would have to import
//  IWormhole themselves, which breaks the intended encapsulation of this library.
struct GuardianSignature {
  bytes32 r;
  bytes32 s;
  uint8 v;
  uint8 guardianIndex;
}

struct VaaHeader {
  //uint8 version;
  uint32 guardianSetIndex;
  GuardianSignature[] signatures;
}

struct VaaEnvelope {
  uint32 timestamp;
  uint32 nonce;
  uint16 emitterChainId;
  bytes32 emitterAddress;
  uint64 sequence;
  uint8 consistencyLevel;
}

struct VaaBody {
  VaaEnvelope envelope;
  bytes payload;
}

struct Vaa {
  VaaHeader header;
  VaaEnvelope envelope;
  bytes payload;
}

struct VaaEssentials {
  uint16 emitterChainId;
  bytes32 emitterAddress;
  uint64 sequence;
  bytes payload;
}

library VaaLib {
  using BytesParsing for bytes;
  using {BytesParsing.checkBound} for uint;

  error InvalidVersion(uint8 version);

  uint8 internal constant HEADER_VERSION = 1;
  //see https://github.com/wormhole-foundation/wormhole/blob/c35940ae9689f6df9e983d51425763509b74a80f/ethereum/contracts/Messages.sol#L174
  //origin: https://bitcoin.stackexchange.com/a/102382
  uint8 internal constant SIGNATURE_RECOVERY_MAGIC = 27;

  //the following offsets are provided for more eclectic, manual parsing
  uint internal constant HEADER_VERSION_OFFSET = 0;
  uint internal constant HEADER_VERSION_SIZE = 1;

  uint internal constant HEADER_GUARDIAN_SET_INDEX_OFFSET =
    HEADER_VERSION_OFFSET + HEADER_VERSION_SIZE;
  uint internal constant HEADER_GUARDIAN_SET_INDEX_SIZE = 4;

  uint internal constant HEADER_SIGNATURE_COUNT_OFFSET =
    HEADER_GUARDIAN_SET_INDEX_OFFSET + HEADER_GUARDIAN_SET_INDEX_SIZE;
  uint internal constant HEADER_SIGNATURE_COUNT_SIZE = 1;

  uint internal constant HEADER_SIGNATURE_ARRAY_OFFSET =
    HEADER_SIGNATURE_COUNT_OFFSET + HEADER_SIGNATURE_COUNT_SIZE;

  uint internal constant GUARDIAN_SIGNATURE_GUARDIAN_INDEX_OFFSET = 0;
  uint internal constant GUARDIAN_SIGNATURE_GUARDIAN_INDEX_SIZE = 1;

  uint internal constant GUARDIAN_SIGNATURE_R_OFFSET =
    GUARDIAN_SIGNATURE_GUARDIAN_INDEX_OFFSET + GUARDIAN_SIGNATURE_GUARDIAN_INDEX_SIZE;
  uint internal constant GUARDIAN_SIGNATURE_R_SIZE = 32;

  uint internal constant GUARDIAN_SIGNATURE_S_OFFSET =
    GUARDIAN_SIGNATURE_R_OFFSET + GUARDIAN_SIGNATURE_R_SIZE;
  uint internal constant GUARDIAN_SIGNATURE_S_SIZE = 32;

  uint internal constant GUARDIAN_SIGNATURE_V_OFFSET =
    GUARDIAN_SIGNATURE_S_OFFSET + GUARDIAN_SIGNATURE_S_SIZE;
  uint internal constant GUARDIAN_SIGNATURE_V_SIZE = 1;

  uint internal constant GUARDIAN_SIGNATURE_SIZE =
    GUARDIAN_SIGNATURE_V_OFFSET + GUARDIAN_SIGNATURE_V_SIZE;

  uint internal constant ENVELOPE_TIMESTAMP_OFFSET = 0;
  uint internal constant ENVELOPE_TIMESTAMP_SIZE = 4;

  uint internal constant ENVELOPE_NONCE_OFFSET =
    ENVELOPE_TIMESTAMP_OFFSET + ENVELOPE_TIMESTAMP_SIZE;
  uint internal constant ENVELOPE_NONCE_SIZE = 4;

  uint internal constant ENVELOPE_EMITTER_CHAIN_ID_OFFSET =
    ENVELOPE_NONCE_OFFSET + ENVELOPE_NONCE_SIZE;
  uint internal constant ENVELOPE_EMITTER_CHAIN_ID_SIZE = 2;

  uint internal constant ENVELOPE_EMITTER_ADDRESS_OFFSET =
    ENVELOPE_EMITTER_CHAIN_ID_OFFSET + ENVELOPE_EMITTER_CHAIN_ID_SIZE;
  uint internal constant ENVELOPE_EMITTER_ADDRESS_SIZE = 32;

  uint internal constant ENVELOPE_SEQUENCE_OFFSET =
    ENVELOPE_EMITTER_ADDRESS_OFFSET + ENVELOPE_EMITTER_ADDRESS_SIZE;
  uint internal constant ENVELOPE_SEQUENCE_SIZE = 8;

  uint internal constant ENVELOPE_CONSISTENCY_LEVEL_OFFSET =
    ENVELOPE_SEQUENCE_OFFSET + ENVELOPE_SEQUENCE_SIZE;
  uint internal constant ENVELOPE_CONSISTENCY_LEVEL_SIZE = 1;

  uint internal constant ENVELOPE_SIZE =
    ENVELOPE_CONSISTENCY_LEVEL_OFFSET + ENVELOPE_CONSISTENCY_LEVEL_SIZE;

  // ------------ Convenience Decoding Functions ------------

  //legacy decoder for IWormhole.VM
  function decodeVmStructCd(
    bytes calldata encodedVaa
  ) internal pure returns (IWormhole.VM memory vm) {
    vm.version = HEADER_VERSION;
    uint envelopeOffset;
    GuardianSignature[] memory signatures;
    (vm.guardianSetIndex, signatures, envelopeOffset) = decodeVaaHeaderCdUnchecked(encodedVaa);
    vm.signatures = asIWormholeSignatures(signatures);
    vm.hash = calcVaaDoubleHashCd(encodedVaa, envelopeOffset);
    ( vm.timestamp,
      vm.nonce,
      vm.emitterChainId,
      vm.emitterAddress,
      vm.sequence,
      vm.consistencyLevel,
      vm.payload
    ) = decodeVaaBodyCd(encodedVaa, envelopeOffset);
  }

  function decodeVmStructMem(
    bytes memory encodedVaa
  ) internal pure returns (IWormhole.VM memory vm) {
    (vm, ) = decodeVmStructMemUnchecked(encodedVaa, 0, encodedVaa.length);
  }

  function decodeVaaStructCd(
    bytes calldata encodedVaa
  ) internal pure returns (Vaa memory vaa) {
    uint envelopeOffset;
    (vaa.header, envelopeOffset) = decodeVaaHeaderStructCdUnchecked(encodedVaa);

    uint payloadOffset;
    (vaa.envelope, payloadOffset) = decodeVaaEnvelopeStructCdUnchecked(encodedVaa, envelopeOffset);
    vaa.payload = decodeVaaPayloadCd(encodedVaa, payloadOffset);
  }

  function decodeVaaStructMem(
    bytes memory encodedVaa
  ) internal pure returns (Vaa memory vaa) {
    (vaa, ) = decodeVaaStructMemUnchecked(encodedVaa, 0, encodedVaa.length);
  }

  function decodeVaaEssentialsCd(
    bytes calldata encodedVaa
  ) internal pure returns (
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    bytes calldata payload
  ) { unchecked {
    checkVaaVersionCd(encodedVaa);

    uint envelopeOffset = skipVaaHeaderCd(encodedVaa);
    uint offset = envelopeOffset + ENVELOPE_EMITTER_CHAIN_ID_OFFSET;
    (emitterChainId, offset) = encodedVaa.asUint16CdUnchecked(offset);
    (emitterAddress, offset) = encodedVaa.asBytes32CdUnchecked(offset);
    (sequence,             ) = encodedVaa.asUint64CdUnchecked(offset);

    uint payloadOffset = envelopeOffset + ENVELOPE_SIZE;
    payload = decodeVaaPayloadCd(encodedVaa, payloadOffset);
  }}

  function decodeVaaEssentialsStructCd(
    bytes calldata encodedVaa
  ) internal pure returns (VaaEssentials memory ret) {
    (ret.emitterChainId, ret.emitterAddress, ret.sequence, ret.payload) =
      decodeVaaEssentialsCd(encodedVaa);
  }

  //The returned values are considered the essentials because it's important to check the emitter
  //  to avoid spoofing. Also, VAAs that use finalized consistency levels should leverage the
  //  sequence number (on a per emitter basis!) and a bitmap for replay protection rather than the
  //  hashed body because it is more gas efficient (storage slot is likely already dirty).
  function decodeVaaEssentialsMem(
    bytes memory encodedVaa
  ) internal pure returns (
    uint16 emitterChainId,
    bytes32 emitterAddress,
    uint64 sequence,
    bytes memory payload
  ) {
    (emitterChainId, emitterAddress, sequence, payload, ) =
      decodeVaaEssentialsMem(encodedVaa, 0, encodedVaa.length);
  }

  function decodeVaaEssentialsStructMem(
    bytes memory encodedVaa
  ) internal pure returns (VaaEssentials memory ret) {
    (ret.emitterChainId, ret.emitterAddress, ret.sequence, ret.payload, ) =
      decodeVaaEssentialsMem(encodedVaa, 0, encodedVaa.length);
  }

  function decodeVaaEssentialsMem(
    bytes memory encoded,
    uint headerOffset,
    uint vaaLength
  ) internal pure returns (
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    bytes memory payload,
    uint    newOffset
  ) { unchecked {
    uint offset = checkVaaVersionMemUnchecked(encoded, headerOffset);

    uint envelopeOffset = skipVaaHeaderMemUnchecked(encoded, offset);
    offset = envelopeOffset + ENVELOPE_EMITTER_CHAIN_ID_OFFSET;
    (emitterChainId, offset) = encoded.asUint16MemUnchecked(offset);
    (emitterAddress, offset) = encoded.asBytes32MemUnchecked(offset);
    (sequence,             ) = encoded.asUint64MemUnchecked(offset);

    uint payloadOffset = envelopeOffset + ENVELOPE_SIZE;
    (payload, newOffset) = decodeVaaPayloadMemUnchecked(encoded, payloadOffset, vaaLength);
  }}

  function decodeVaaEssentialsStructMem(
    bytes memory encodedVaa,
    uint headerOffset,
    uint vaaLength
  ) internal pure returns (VaaEssentials memory ret, uint newOffset) {
    (ret.emitterChainId, ret.emitterAddress, ret.sequence, ret.payload, newOffset) =
      decodeVaaEssentialsMem(encodedVaa, headerOffset, vaaLength);
  }

  function decodeVaaBodyCd(
    bytes calldata encodedVaa
  ) internal pure returns (
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel,
    bytes calldata payload
  ) {
    checkVaaVersionCd(encodedVaa);
    (timestamp, nonce, emitterChainId, emitterAddress, sequence, consistencyLevel, payload) =
      decodeVaaBodyCd(encodedVaa, skipVaaHeaderCd(encodedVaa));
  }

  function decodeVaaBodyStructCd(
    bytes calldata encodedVaa
  ) internal pure returns (VaaBody memory body) {
    ( body.envelope.timestamp,
      body.envelope.nonce,
      body.envelope.emitterChainId,
      body.envelope.emitterAddress,
      body.envelope.sequence,
      body.envelope.consistencyLevel,
      body.payload
    ) = decodeVaaBodyCd(encodedVaa);
  }

  function decodeVaaBodyMem(
    bytes memory encodedVaa
  ) internal pure returns (
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel,
    bytes memory payload
  ) {
    checkVaaVersionMemUnchecked(encodedVaa, 0);
    uint envelopeOffset = skipVaaHeaderMemUnchecked(encodedVaa, 0);
    (timestamp, nonce, emitterChainId, emitterAddress, sequence, consistencyLevel, payload, ) =
      decodeVaaBodyMemUnchecked(encodedVaa, envelopeOffset, encodedVaa.length);
  }

  function decodeVaaBodyStructMem(
    bytes memory encodedVaa
  ) internal pure returns (VaaBody memory body) {
    ( body.envelope.timestamp,
      body.envelope.nonce,
      body.envelope.emitterChainId,
      body.envelope.emitterAddress,
      body.envelope.sequence,
      body.envelope.consistencyLevel,
      body.payload,
    ) = decodeVaaBodyMemUnchecked(encodedVaa, 0, encodedVaa.length);
  }

  // Convinience decoding function for token bridge Vaas
  function decodeEmitterChainAndPayloadCdUnchecked(
    bytes calldata encodedVaa
  ) internal pure returns (uint16 emitterChainId, bytes calldata payload) { unchecked {
    checkVaaVersionCd(encodedVaa);
    uint envelopeOffset = skipVaaHeaderCd(encodedVaa);
    uint offset = envelopeOffset + ENVELOPE_EMITTER_CHAIN_ID_OFFSET;
    (emitterChainId, offset) = encodedVaa.asUint16CdUnchecked(offset);
    offset += ENVELOPE_EMITTER_ADDRESS_SIZE + ENVELOPE_SEQUENCE_SIZE + ENVELOPE_CONSISTENCY_LEVEL_SIZE;
    payload = decodeVaaPayloadCd(encodedVaa, offset);
  }}

  function decodeEmitterChainAndPayloadMemUnchecked(
    bytes memory encodedVaa
  ) internal pure returns (uint16 emitterChainId, bytes memory payload) { unchecked {
    checkVaaVersionMemUnchecked(encodedVaa, 0);
    uint envelopeOffset = skipVaaHeaderMemUnchecked(encodedVaa, 0);
    uint offset = envelopeOffset + ENVELOPE_EMITTER_CHAIN_ID_OFFSET;
    (emitterChainId, offset) = encodedVaa.asUint16MemUnchecked(offset);
    offset += ENVELOPE_EMITTER_ADDRESS_SIZE + ENVELOPE_SEQUENCE_SIZE + ENVELOPE_CONSISTENCY_LEVEL_SIZE;
    (payload, ) = decodeVaaPayloadMemUnchecked(encodedVaa, offset, encodedVaa.length);
  }}

  // ------------ Advanced Decoding Functions ------------

  function asIWormholeSignatures(
    GuardianSignature[] memory signatures
  ) internal pure returns (IWormhole.Signature[] memory vmSignatures) {
    assembly ("memory-safe") {
      vmSignatures := signatures
    }
  }

  function asGuardianSignatures(
    IWormhole.Signature[] memory vmSignatures
  ) internal pure returns (GuardianSignature[] memory signatures) {
    assembly ("memory-safe") {
      signatures := vmSignatures
    }
  }

  function checkVaaVersionCd(bytes calldata encodedVaa) internal pure returns (uint newOffset) {
    uint8 version;
    (version, newOffset) = encodedVaa.asUint8CdUnchecked(0);
    checkVaaVersion(version);
  }

  function checkVaaVersionMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint newOffset) {
    uint8 version;
    (version, newOffset) = encoded.asUint8MemUnchecked(offset);
    checkVaaVersion(version);
  }

  function checkVaaVersion(uint8 version) internal pure {
    if (version != HEADER_VERSION)
      revert InvalidVersion(version);
  }

  //return the offset to the start of the envelope/body
  function skipVaaHeaderCd(
    bytes calldata encodedVaa
  ) internal pure returns (uint envelopeOffset) { unchecked {
    (uint sigCount, uint offset) = encodedVaa.asUint8CdUnchecked(HEADER_SIGNATURE_COUNT_OFFSET);
    envelopeOffset = offset + sigCount * GUARDIAN_SIGNATURE_SIZE;
  }}

  function skipVaaHeaderMemUnchecked(
    bytes memory encoded,
    uint headerOffset
  ) internal pure returns (uint envelopeOffset) { unchecked {
    uint offset = headerOffset + HEADER_SIGNATURE_COUNT_OFFSET;
    uint sigCount;
    (sigCount, offset) = encoded.asUint8MemUnchecked(offset);
    envelopeOffset = offset + sigCount * GUARDIAN_SIGNATURE_SIZE;
  }}

  //see WARNING box at the top
  function calcVaaSingleHashCd(
    bytes calldata encodedVaa,
    uint envelopeOffset
  ) internal pure returns (bytes32) {
    return keccak256Cd(_decodeRemainderCd(encodedVaa, envelopeOffset));
  }

  //see WARNING box at the top
  function calcVaaSingleHashMem(
    bytes memory encoded,
    uint envelopeOffset,
    uint vaaLength
  ) internal pure returns (bytes32) { unchecked {
    envelopeOffset.checkBound(vaaLength);
    return keccak256SliceUnchecked(encoded, envelopeOffset, vaaLength - envelopeOffset);
  }}

  //see WARNING box at the top
  function calcSingleHash(Vaa memory vaa) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked(encode(vaa.envelope), vaa.payload));
  }

  //see WARNING box at the top
  function calcSingleHash(VaaBody memory body) internal pure returns (bytes32) {
    return keccak256(encode(body));
  }

  //see WARNING box at the top
  //this function matches IWormhole.VM.hash and is what's been used for (legacy) replay protection
  function calcVaaDoubleHashCd(
    bytes calldata encodedVaa,
    uint envelopeOffset
  ) internal pure returns (bytes32) {
    return keccak256Word(calcVaaSingleHashCd(encodedVaa, envelopeOffset));
  }

  //see WARNING box at the top
  function calcVaaDoubleHashMem(
    bytes memory encoded,
    uint envelopeOffset,
    uint vaaLength
  ) internal pure returns (bytes32) {
    return keccak256Word(calcVaaSingleHashMem(encoded, envelopeOffset, vaaLength));
  }

  //see WARNING box at the top
  function calcDoubleHash(Vaa memory vaa) internal pure returns (bytes32) {
    return keccak256Word(calcSingleHash(vaa));
  }

  //see WARNING box at the top
  function calcDoubleHash(VaaBody memory body) internal pure returns (bytes32) {
    return keccak256Word(calcSingleHash(body));
  }

  function decodeVmStructMemUnchecked(
    bytes memory encoded,
    uint headerOffset,
    uint vaaLength
  ) internal pure returns (IWormhole.VM memory vm, uint newOffset) {
    vm.version = HEADER_VERSION;
    uint envelopeOffset;
    GuardianSignature[] memory signatures;
    (vm.guardianSetIndex, signatures, envelopeOffset) =
      decodeVaaHeaderMemUnchecked(encoded, headerOffset);
    vm.signatures = asIWormholeSignatures(signatures);
    vm.hash = calcVaaDoubleHashMem(encoded, envelopeOffset, vaaLength);
    ( vm.timestamp,
      vm.nonce,
      vm.emitterChainId,
      vm.emitterAddress,
      vm.sequence,
      vm.consistencyLevel,
      vm.payload,
      newOffset
    ) = decodeVaaBodyMemUnchecked(encoded, envelopeOffset, vaaLength);
  }

  function decodeVaaStructMemUnchecked(
    bytes memory encoded,
    uint headerOffset,
    uint vaaLength
  ) internal pure returns (Vaa memory vaa, uint newOffset) {
    uint envelopeOffset;
    (vaa.header.guardianSetIndex, vaa.header.signatures, envelopeOffset) =
      decodeVaaHeaderMemUnchecked(encoded, headerOffset);

    uint payloadOffset;
    (vaa.envelope, payloadOffset) = decodeVaaEnvelopeStructMemUnchecked(encoded, envelopeOffset);

    (vaa.payload, newOffset) = decodeVaaPayloadMemUnchecked(encoded, payloadOffset, vaaLength);
  }

  function decodeVaaBodyCd(
    bytes calldata encodedVaa,
    uint envelopeOffset
  ) internal pure returns (
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel,
    bytes calldata payload
  ) {
    uint payloadOffset;
    (timestamp, nonce, emitterChainId, emitterAddress, sequence, consistencyLevel, payloadOffset) =
      decodeVaaEnvelopeCdUnchecked(encodedVaa, envelopeOffset);
    payload = decodeVaaPayloadCd(encodedVaa, payloadOffset);
  }

  function decodeVaaBodyStructCd(
    bytes calldata encodedVaa,
    uint envelopeOffset
  ) internal pure returns (VaaBody memory body) {
    ( body.envelope.timestamp,
      body.envelope.nonce,
      body.envelope.emitterChainId,
      body.envelope.emitterAddress,
      body.envelope.sequence,
      body.envelope.consistencyLevel,
      body.payload
    ) = decodeVaaBodyCd(encodedVaa, envelopeOffset);
  }

  function decodeVaaBodyMemUnchecked(
    bytes memory encoded,
    uint envelopeOffset,
    uint vaaLength
  ) internal pure returns (
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel,
    bytes memory payload,
    uint    newOffset
  ) {
    uint payloadOffset;
    (timestamp, nonce, emitterChainId, emitterAddress, sequence, consistencyLevel, payloadOffset) =
      decodeVaaEnvelopeMemUnchecked(encoded, envelopeOffset);
    (payload, newOffset) = decodeVaaPayloadMemUnchecked(encoded, payloadOffset, vaaLength);
  }

  function decodeVaaBodyStructMemUnchecked(
    bytes memory encoded,
    uint envelopeOffset,
    uint vaaLength
  ) internal pure returns (VaaBody memory body, uint newOffset) {
    ( body.envelope.timestamp,
      body.envelope.nonce,
      body.envelope.emitterChainId,
      body.envelope.emitterAddress,
      body.envelope.sequence,
      body.envelope.consistencyLevel,
      body.payload,
      newOffset
    ) = decodeVaaBodyMemUnchecked(encoded, envelopeOffset, vaaLength);
  }

  function decodeVaaEnvelopeCdUnchecked(
    bytes calldata encodedVaa,
    uint envelopeOffset
  ) internal pure returns (
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel,
    uint    payloadOffset
  ) {
    uint offset = envelopeOffset;
    (timestamp,        offset) = encodedVaa.asUint32CdUnchecked(offset);
    (nonce,            offset) = encodedVaa.asUint32CdUnchecked(offset);
    (emitterChainId,   offset) = encodedVaa.asUint16CdUnchecked(offset);
    (emitterAddress,   offset) = encodedVaa.asBytes32CdUnchecked(offset);
    (sequence,         offset) = encodedVaa.asUint64CdUnchecked(offset);
    (consistencyLevel, offset) = encodedVaa.asUint8CdUnchecked(offset);
    payloadOffset = offset;
  }

  function decodeVaaEnvelopeStructCdUnchecked(
    bytes calldata encodedVaa,
    uint envelopeOffset
  ) internal pure returns (VaaEnvelope memory envelope, uint payloadOffset) {
    ( envelope.timestamp,
      envelope.nonce,
      envelope.emitterChainId,
      envelope.emitterAddress,
      envelope.sequence,
      envelope.consistencyLevel,
      payloadOffset
    ) = decodeVaaEnvelopeCdUnchecked(encodedVaa, envelopeOffset);
  }

  function decodeVaaEnvelopeMemUnchecked(
    bytes memory encoded,
    uint envelopeOffset
  ) internal pure returns (
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel,
    uint    payloadOffset
  ) {
    uint offset = envelopeOffset;
    (timestamp,        offset) = encoded.asUint32MemUnchecked(offset);
    (nonce,            offset) = encoded.asUint32MemUnchecked(offset);
    (emitterChainId,   offset) = encoded.asUint16MemUnchecked(offset);
    (emitterAddress,   offset) = encoded.asBytes32MemUnchecked(offset);
    (sequence,         offset) = encoded.asUint64MemUnchecked(offset);
    (consistencyLevel, offset) = encoded.asUint8MemUnchecked(offset);
    payloadOffset = offset;
  }

  function decodeVaaEnvelopeStructMemUnchecked(
    bytes memory encoded,
    uint envelopeOffset
  ) internal pure returns (VaaEnvelope memory envelope, uint payloadOffset) {
    ( envelope.timestamp,
      envelope.nonce,
      envelope.emitterChainId,
      envelope.emitterAddress,
      envelope.sequence,
      envelope.consistencyLevel,
      payloadOffset
    ) = decodeVaaEnvelopeMemUnchecked(encoded, envelopeOffset);
  }

  function decodeVaaHeaderCdUnchecked(
    bytes calldata encodedVaa
  ) internal pure returns (
    uint32 guardianSetIndex,
    GuardianSignature[] memory signatures,
    uint envelopeOffset
  ) { unchecked {
    checkVaaVersionCd(encodedVaa);
    uint offset = HEADER_GUARDIAN_SET_INDEX_OFFSET;
    (guardianSetIndex, offset) = encodedVaa.asUint32CdUnchecked(offset);

    uint signersLen;
    (signersLen, offset) = encodedVaa.asUint8CdUnchecked(offset);

    signatures = new GuardianSignature[](signersLen);
    for (uint i = 0; i < signersLen; ++i)
      (signatures[i], offset) = decodeGuardianSignatureStructCdUnchecked(encodedVaa, offset);

    envelopeOffset = offset;
  }}

  function decodeVaaHeaderStructCdUnchecked(
    bytes calldata encodedVaa
  ) internal pure returns (VaaHeader memory header, uint envelopeOffset) {
    ( header.guardianSetIndex,
      header.signatures,
      envelopeOffset
    ) = decodeVaaHeaderCdUnchecked(encodedVaa);
  }

  function decodeVaaHeaderMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (
    uint32 guardianSetIndex,
    GuardianSignature[] memory signatures,
    uint envelopeOffset
  ) { unchecked {
    offset = checkVaaVersionMemUnchecked(encoded, offset);
    (guardianSetIndex, offset) = encoded.asUint32MemUnchecked(offset);

    uint signersLen;
    (signersLen, offset) = encoded.asUint8MemUnchecked(offset);

    signatures = new GuardianSignature[](signersLen);
    for (uint i = 0; i < signersLen; ++i)
      (signatures[i], offset) = decodeGuardianSignatureStructMemUnchecked(encoded, offset);

    envelopeOffset = offset;
  }}

  function decodeVaaHeaderStructMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (VaaHeader memory header, uint envelopeOffset) {
    ( header.guardianSetIndex,
      header.signatures,
      envelopeOffset
    ) = decodeVaaHeaderMemUnchecked(encoded, offset);
  }

  function decodeGuardianSignatureCdUnchecked(
    bytes calldata encodedVaa,
    uint offset
  ) internal pure returns (
    uint8 guardianIndex,
    bytes32 r,
    bytes32 s,
    uint8 v,
    uint newOffset
  ) { unchecked {
    (guardianIndex, offset) = encodedVaa.asUint8CdUnchecked(offset);
    (r,             offset) = encodedVaa.asBytes32CdUnchecked(offset);
    (s,             offset) = encodedVaa.asBytes32CdUnchecked(offset);
    (v,             offset) = encodedVaa.asUint8CdUnchecked(offset);
    v += SIGNATURE_RECOVERY_MAGIC;
    newOffset = offset;
  }}

  function decodeGuardianSignatureStructCdUnchecked(
    bytes calldata encodedVaa,
    uint offset
  ) internal pure returns (GuardianSignature memory ret, uint newOffset) {
    (ret.guardianIndex, ret.r, ret.s, ret.v, newOffset) =
      decodeGuardianSignatureCdUnchecked(encodedVaa, offset);
  }

  function decodeGuardianSignatureMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (
    uint8 guardianIndex,
    bytes32 r,
    bytes32 s,
    uint8 v,
    uint newOffset
  ) { unchecked {
    (guardianIndex, offset) = encoded.asUint8MemUnchecked(offset);
    (r,             offset) = encoded.asBytes32MemUnchecked(offset);
    (s,             offset) = encoded.asBytes32MemUnchecked(offset);
    (v,             offset) = encoded.asUint8MemUnchecked(offset);
    v += SIGNATURE_RECOVERY_MAGIC;
    newOffset = offset;
  }}

  function decodeGuardianSignatureStructMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (GuardianSignature memory ret, uint newOffset) {
    (ret.guardianIndex, ret.r, ret.s, ret.v, newOffset) =
      decodeGuardianSignatureMemUnchecked(encoded, offset);
  }

  function decodeVaaPayloadCd(
    bytes calldata encodedVaa,
    uint payloadOffset
  ) internal pure returns (bytes calldata payload) {
    payload = _decodeRemainderCd(encodedVaa, payloadOffset);
  }

  function decodeVaaPayloadMemUnchecked(
    bytes memory encoded,
    uint payloadOffset,
    uint vaaLength
  ) internal pure returns (bytes memory payload, uint newOffset) { unchecked {
    //check to avoid underflow in following subtraction
    payloadOffset.checkBound(vaaLength);
    (payload, newOffset) = encoded.sliceMemUnchecked(payloadOffset, vaaLength - payloadOffset);
  }}

  // ------------ Encoding ------------

  function encode(IWormhole.VM memory vm) internal pure returns (bytes memory) { unchecked {
    require(vm.version == HEADER_VERSION, "Invalid version");
    return abi.encodePacked(
      encodeVaaHeader(vm.guardianSetIndex, asGuardianSignatures(vm.signatures)),
      vm.timestamp,
      vm.nonce,
      vm.emitterChainId,
      vm.emitterAddress,
      vm.sequence,
      vm.consistencyLevel,
      vm.payload
    );
  }}

  function encodeVaaHeader(
    uint32 guardianSetIndex,
    GuardianSignature[] memory signatures
  ) internal pure returns (bytes memory) {
    bytes memory sigs;
    for (uint i = 0; i < signatures.length; ++i) {
      GuardianSignature memory sig = signatures[i];
      uint8 v = sig.v - SIGNATURE_RECOVERY_MAGIC; //deliberately checked
      sigs = bytes.concat(sigs, abi.encodePacked(sig.guardianIndex, sig.r, sig.s, v));
    }

    return abi.encodePacked(
      HEADER_VERSION,
      guardianSetIndex,
      uint8(signatures.length),
      sigs
    );
  }

  function encode(VaaHeader memory header) internal pure returns (bytes memory) {
    return encodeVaaHeader(header.guardianSetIndex, header.signatures);
  }

  function encodeVaaEnvelope(
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel
  ) internal pure returns (bytes memory) {
    return abi.encodePacked(
      timestamp,
      nonce,
      emitterChainId,
      emitterAddress,
      sequence,
      consistencyLevel
    );
  }

  function encode(VaaEnvelope memory envelope) internal pure returns (bytes memory) {
    return encodeVaaEnvelope(
      envelope.timestamp,
      envelope.nonce,
      envelope.emitterChainId,
      envelope.emitterAddress,
      envelope.sequence,
      envelope.consistencyLevel
    );
  }

  function encodeVaaBody(
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel,
    bytes memory payload
  ) internal pure returns (bytes memory) {
    return abi.encodePacked(
      encodeVaaEnvelope(
        timestamp,
        nonce,
        emitterChainId,
        emitterAddress,
        sequence,
        consistencyLevel
      ),
      payload
    );
  }

  function encode(VaaBody memory body) internal pure returns (bytes memory) {
    return abi.encodePacked(encode(body.envelope), body.payload);
  }

  function encodeVaa(
    uint32 guardianSetIndex,
    GuardianSignature[] memory signatures,
    uint32  timestamp,
    uint32  nonce,
    uint16  emitterChainId,
    bytes32 emitterAddress,
    uint64  sequence,
    uint8   consistencyLevel,
    bytes memory payload
  ) internal pure returns (bytes memory) {
    return abi.encodePacked(
      encodeVaaHeader(guardianSetIndex, signatures),
      encodeVaaBody(
        timestamp,
        nonce,
        emitterChainId,
        emitterAddress,
        sequence,
        consistencyLevel,
        payload
      )
    );
  }

  function encode(Vaa memory vaa) internal pure returns (bytes memory) {
    return encodeVaa(
      vaa.header.guardianSetIndex,
      vaa.header.signatures,
      vaa.envelope.timestamp,
      vaa.envelope.nonce,
      vaa.envelope.emitterChainId,
      vaa.envelope.emitterAddress,
      vaa.envelope.sequence,
      vaa.envelope.consistencyLevel,
      vaa.payload
    );
  }

  // ------------ Private ------------

  //we use this function over encodedVaa[offset:] to consistently get BytesParsing errors
  function _decodeRemainderCd(
    bytes calldata encodedVaa,
    uint offset
  ) private pure returns (bytes calldata remainder) { unchecked {
    //check to avoid underflow in following subtraction
    offset.checkBound(encodedVaa.length);
    (remainder, ) = encodedVaa.sliceCdUnchecked(offset, encodedVaa.length - offset);
  }}
}

using VaaLib for VaaHeader global;
using VaaLib for VaaEnvelope global;
using VaaLib for VaaBody global;
using VaaLib for Vaa global;

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IBridgeController} from "./IBridgeController.sol";
import {IMakinaGovernable} from "./IMakinaGovernable.sol";

interface IMachineEndpoint is IBridgeController, IMakinaGovernable {
    /// @notice Manages the transfer of tokens between a machine and a caliber. The transfer direction depends on the caller.
    /// @param token The address of the token.
    /// @param amount The amount of tokens to transfer.
    /// @param data ABI-encoded parameters required for bridge-related transfers. Ignored for transfers between a machine and its hub caliber.
    function manageTransfer(address token, uint256 amount, bytes calldata data) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface ISwapModule {
    event Swap(
        address indexed sender,
        uint16 swapperId,
        address indexed inputToken,
        address indexed outputToken,
        uint256 inputAmount,
        uint256 outputAmount
    );
    event SwapperTargetsSet(uint16 indexed swapper, address approvalTarget, address executionTarget);

    struct SwapperTargets {
        address approvalTarget;
        address executionTarget;
    }

    /// @notice Swap order object.
    /// @param swapperId The ID of the external swap protocol.
    /// @param data The swap calldata to pass to the swapper's execution target.
    /// @param inputToken The input token.
    /// @param outputToken The output token.
    /// @param inputAmount The input amount.
    /// @param minOutputAmount The minimum expected output amount.
    struct SwapOrder {
        uint16 swapperId;
        bytes data;
        address inputToken;
        address outputToken;
        uint256 inputAmount;
        uint256 minOutputAmount;
    }

    /// @notice Returns approval and execution targets for a given swapper ID.
    /// @param swapperId The swapper ID.
    /// @return approvalTarget The approval target.
    /// @return executionTarget The execution target.
    function getSwapperTargets(uint16 swapperId)
        external
        view
        returns (address approvalTarget, address executionTarget);

    /// @notice Swaps tokens using a given swapper.
    /// @param order The swap order object.
    function swap(SwapOrder calldata order) external returns (uint256);

    /// @notice Sets approval and execution targets for a given swapper ID.
    /// @param swapperId The swapper ID.
    /// @param approvalTarget The approval target.
    function setSwapperTargets(uint16 swapperId, address approvalTarget, address executionTarget) external;
}

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

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

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

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

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

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

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

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

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

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

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

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 * - Set can be cleared (all elements removed) in O(n).
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function _clear(Set storage set) private {
        uint256 len = _length(set);
        for (uint256 i = 0; i < len; ++i) {
            delete set._positions[set._values[i]];
        }
        Arrays.unsafeSetLength(set._values, 0);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(Bytes32Set storage set) internal {
        _clear(set._inner);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(AddressSet storage set) internal {
        _clear(set._inner);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(UintSet storage set) internal {
        _clear(set._inner);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }
}

// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

interface IWormhole {
  struct GuardianSet {
    address[] keys;
    uint32 expirationTime;
  }

  struct Signature {
    bytes32 r;
    bytes32 s;
    uint8 v;
    uint8 guardianIndex;
  }

  struct VM {
    uint8 version;
    uint32 timestamp;
    uint32 nonce;
    uint16 emitterChainId;
    bytes32 emitterAddress;
    uint64 sequence;
    uint8 consistencyLevel;
    bytes payload;
    uint32 guardianSetIndex;
    Signature[] signatures;
    bytes32 hash;
  }

  struct ContractUpgrade {
    bytes32 module;
    uint8 action;
    uint16 chain;
    address newContract;
  }

  struct GuardianSetUpgrade {
    bytes32 module;
    uint8 action;
    uint16 chain;
    GuardianSet newGuardianSet;
    uint32 newGuardianSetIndex;
  }

  struct SetMessageFee {
    bytes32 module;
    uint8 action;
    uint16 chain;
    uint256 messageFee;
  }

  struct TransferFees {
    bytes32 module;
    uint8 action;
    uint16 chain;
    uint256 amount;
    bytes32 recipient;
  }

  struct RecoverChainId {
    bytes32 module;
    uint8 action;
    uint256 evmChainId;
    uint16 newChainId;
  }

  event LogMessagePublished(
    address indexed sender,
    uint64 sequence,
    uint32 nonce,
    bytes payload,
    uint8 consistencyLevel
  );

  event ContractUpgraded(address indexed oldContract, address indexed newContract);

  event GuardianSetAdded(uint32 indexed index);

  function publishMessage(uint32 nonce, bytes memory payload, uint8 consistencyLevel)
    external
    payable
    returns (uint64 sequence);

  function initialize() external;

  function parseAndVerifyVM(bytes calldata encodedVM)
    external
    view
    returns (VM memory vm, bool valid, string memory reason);

  function verifyVM(VM memory vm) external view returns (bool valid, string memory reason);

  function verifySignatures(
    bytes32 hash,
    Signature[] memory signatures,
    GuardianSet memory guardianSet
  ) external pure returns (bool valid, string memory reason);

  function parseVM(bytes memory encodedVM) external pure returns (VM memory vm);

  function quorum(
    uint256 numGuardians
  ) external pure returns (uint256 numSignaturesRequiredForQuorum);

  function getGuardianSet(uint32 index) external view returns (GuardianSet memory);

  function getCurrentGuardianSetIndex() external view returns (uint32);

  function getGuardianSetExpiry() external view returns (uint32);

  function governanceActionIsConsumed(bytes32 hash) external view returns (bool);

  function isInitialized(address impl) external view returns (bool);

  function chainId() external view returns (uint16);

  function isFork() external view returns (bool);

  function governanceChainId() external view returns (uint16);

  function governanceContract() external view returns (bytes32);

  function messageFee() external view returns (uint256);

  function evmChainId() external view returns (uint256);

  function nextSequence(address emitter) external view returns (uint64);

  function parseContractUpgrade(
    bytes memory encodedUpgrade
  ) external pure returns (ContractUpgrade memory cu);

  function parseGuardianSetUpgrade(
    bytes memory encodedUpgrade
  ) external pure returns (GuardianSetUpgrade memory gsu);

  function parseSetMessageFee(
    bytes memory encodedSetMessageFee
  ) external pure returns (SetMessageFee memory smf);

  function parseTransferFees(
    bytes memory encodedTransferFees
  ) external pure returns (TransferFees memory tf);

  function parseRecoverChainId(
    bytes memory encodedRecoverChainId
  ) external pure returns (RecoverChainId memory rci);

  function submitContractUpgrade(bytes memory _vm) external;

  function submitSetMessageFee(bytes memory _vm) external;

  function submitNewGuardianSet(bytes memory _vm) external;

  function submitTransferFees(bytes memory _vm) external;

  function submitRecoverChainId(bytes memory _vm) external;
}

File 24 of 42 : BytesParsing.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;

import "wormhole-sdk/constants/Common.sol";

//This file appears comically large, but all unused functions are removed by the compiler.
library BytesParsing {
  error OutOfBounds(uint256 offset, uint256 length);
  error LengthMismatch(uint256 encodedLength, uint256 expectedLength);
  error InvalidBoolVal(uint8 val);

  /**
   * Implements runtime check of logic that accesses memory.
   * @param pastTheEndOffset The offset past the end relative to the accessed memory fragment.
   * @param length The length of the memory fragment accessed.
   */
  function checkBound(uint pastTheEndOffset, uint length) internal pure {
    if (pastTheEndOffset > length)
      revert OutOfBounds(pastTheEndOffset, length);
  }

  function checkLength(uint encodedLength, uint expectedLength) internal pure {
    if (encodedLength != expectedLength)
      revert LengthMismatch(encodedLength, expectedLength);
  }

  //Summary of all remaining functions:
  //
  //Each function has 2*2=4 versions:
  //  1. unchecked - no bounds checking (uses suffix `Unchecked`)
  //  2. checked (no suffix)
  //and (since Solidity does not allow overloading based on data location)
  //  1. calldata input (uses tag `Cd` )
  //  2. memory input (uses tag `Mem`)
  //
  //The canoncial/recommended way of parsing data to be maximally gas efficient is to prefer the
  //  calldata variants over the memory variants and to use the unchecked variants with a manual
  //  length check at the end using `checkLength` to ensure that encoded data was consumed exactly.
  //
  //WARNING: Neither variant uses safe math! It is up to the dev to ensure that offset and length
  //  values are sensible. In other words, verify user inputs before passing them on. Preferably,
  //  the format that's being parsed does not allow for such overflows in the first place by e.g.
  //  encoding lengths using at most 4 bytes, etc.
  //
  //Functions:
  //  Unless stated otherwise, all functions take an `encoded` bytes calldata/memory and an `offset`
  //    as input and return the parsed value and the next offset (i.e. the offset pointing to the
  //    next, unparsed byte).
  //
  // * slice(encoded, offset, length)
  // * sliceUint<n>Prefixed - n in {8, 16, 32} - parses n bytes of length prefix followed by data
  // * asAddress
  // * asBool
  // * asUint<8*n> - n in {1, ..., 32}, i.e. asUint8, asUint16, ..., asUint256
  // * asBytes<n>  - n in {1, ..., 32}, i.e. asBytes1, asBytes2, ..., asBytes32

  function sliceCdUnchecked(
    bytes calldata encoded,
    uint offset,
    uint length
  ) internal pure returns (bytes calldata ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret.offset := add(encoded.offset, offset)
      ret.length := length
      nextOffset := add(offset, length)
    }
  }

  function sliceMemUnchecked(
    bytes memory encoded,
    uint offset,
    uint length
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, length)
      ret := mload(FREE_MEMORY_PTR)

      //Explanation on how we copy data here:
      //  The bytes type has the following layout in memory:
      //    [length: 32 bytes, data: length bytes]
      //  So if we allocate `bytes memory foo = new bytes(1);` then `foo` will be a pointer to 33
      //    bytes where the first 32 bytes contain the length and the last byte is the actual data.
      //  Since mload always loads 32 bytes of memory at once, we use our shift variable to align
      //    our reads so that our last read lines up exactly with the last 32 bytes of `encoded`.
      //  However this also means that if the length of `encoded` is not a multiple of 32 bytes, our
      //    first read will necessarily partly contain bytes from `encoded`'s 32 length bytes that
      //    will be written into the length part of our `ret` slice.
      //  We remedy this issue by writing the length of our `ret` slice at the end, thus
      //    overwritting those garbage bytes.

      //and(length, 31) is equivalent to `mod(length, 32)`, but 2 gas cheaper
      let shift := and(length, WORD_SIZE_MINUS_ONE)
      if iszero(shift) {
        shift := WORD_SIZE
      }

      let dest := add(ret, shift)
      let end := add(dest, length)
      for {
        let src := add(add(encoded, shift), offset)
      } lt(dest, end) {
        src := add(src, WORD_SIZE)
        dest := add(dest, WORD_SIZE)
      } {
        mstore(dest, mload(src))
      }

      mstore(ret, length)
      //When compiling with --via-ir then normally allocated memory (i.e. via new) will have 32 byte
      //  memory alignment and so we enforce the same memory alignment here.
      mstore(
        FREE_MEMORY_PTR,
        and(add(dest, WORD_SIZE_MINUS_ONE), not(WORD_SIZE_MINUS_ONE))
      )
    }
  }

/* -------------------------------------------------------------------------------------------------
Remaining library code below was auto-generated via the following js/node code:

const dlTag = dl => dl ? "Cd" : "Mem";
const dlType = dl =>dl ? "calldata" : "memory";

const funcs = [
  ...[8,16,32].map(n => [
    `sliceUint${n}Prefixed`,
    dl => [
      `uint${n} len;`,
      `(len, nextOffset) = asUint${n}${dlTag(dl)}Unchecked(encoded, offset);`,
      `(ret, nextOffset) = slice${dlTag(dl)}Unchecked(encoded, nextOffset, uint(len));`
    ],
    dl => `bytes ${dlType(dl)}`,
  ]), [
    `asAddress`,
    dl => [
      `uint160 tmp;`,
      `(tmp, nextOffset) = asUint160${dlTag(dl)}Unchecked(encoded, offset);`,
      `ret = address(tmp);`
    ],
    _ => `address`
  ], [
    `asBool`,
    dl => [
      `uint8 val;`,
      `(val, nextOffset) = asUint8${dlTag(dl)}Unchecked(encoded, offset);`,
      `if (val & 0xfe != 0)`,
      `  revert InvalidBoolVal(val);`,
      `uint cleanedVal = uint(val);`,
      `//skip 2x iszero opcode`,
      `/// @solidity memory-safe-assembly`,
      `assembly { ret := cleanedVal }`
    ],
    _ => `bool`
  ],
  ...Array.from({length: 32}, (_, i) => [
    `asUint${(i+1)*8}`,
    dl => [
      `/// @solidity memory-safe-assembly`,
      `assembly {`,
      `  nextOffset := add(offset, ${i+1})`,
      dl ? `  ret := shr(${256-(i+1)*8}, calldataload(add(encoded.offset, offset)))`
         : `  ret := mload(add(encoded, nextOffset))`,
      `}`
    ],
    _ => `uint${(i+1)*8}`
  ]),
  ...Array.from({length: 32}, (_, i) => [
    `asBytes${i+1}`,
    dl => [
      `/// @solidity memory-safe-assembly`,
      `assembly {`,
      `  ret := ${dl ? "calldataload" : "mload"}(add(encoded${dl ? ".offset" :""}, ${dl ? "offset" : "add(offset, WORD_SIZE)"}))`,
      `  nextOffset := add(offset, ${i+1})`,
      `}`
    ],
    _ => `bytes${i+1}`
  ]),
];

for (const dl of [true, false])
  console.log(
`function slice${dlTag(dl)}(
  bytes ${dlType(dl)} encoded,
  uint offset,
  uint length
) internal pure returns (bytes ${dlType(dl)} ret, uint nextOffset) {
  (ret, nextOffset) = slice${dlTag(dl)}Unchecked(encoded, offset, length);
  checkBound(nextOffset, encoded.length);
}
`);

for (const [name, code, ret] of funcs) {
  for (const dl of [true, false])
    console.log(
`function ${name}${dlTag(dl)}Unchecked(
  bytes ${dlType(dl)} encoded,
  uint offset
) internal pure returns (${ret(dl)} ret, uint nextOffset) {
  ${code(dl).join("\n  ")}
}

function ${name}${dlTag(dl)}(
  bytes ${dlType(dl)} encoded,
  uint offset
) internal pure returns (${ret(dl)} ret, uint nextOffset) {
  (ret, nextOffset) = ${name}${dlTag(dl)}Unchecked(encoded, offset);
  checkBound(nextOffset, encoded.length);
}
`);
}
------------------------------------------------------------------------------------------------- */

  function sliceCd(
    bytes calldata encoded,
    uint offset,
    uint length
  ) internal pure returns (bytes calldata ret, uint nextOffset) {
    (ret, nextOffset) = sliceCdUnchecked(encoded, offset, length);
    checkBound(nextOffset, encoded.length);
  }

  function sliceMem(
    bytes memory encoded,
    uint offset,
    uint length
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    (ret, nextOffset) = sliceMemUnchecked(encoded, offset, length);
    checkBound(nextOffset, encoded.length);
  }

  function sliceUint8PrefixedCdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes calldata ret, uint nextOffset) {
    uint8 len;
    (len, nextOffset) = asUint8CdUnchecked(encoded, offset);
    (ret, nextOffset) = sliceCdUnchecked(encoded, nextOffset, uint(len));
  }

  function sliceUint8PrefixedCd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes calldata ret, uint nextOffset) {
    (ret, nextOffset) = sliceUint8PrefixedCdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function sliceUint8PrefixedMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    uint8 len;
    (len, nextOffset) = asUint8MemUnchecked(encoded, offset);
    (ret, nextOffset) = sliceMemUnchecked(encoded, nextOffset, uint(len));
  }

  function sliceUint8PrefixedMem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    (ret, nextOffset) = sliceUint8PrefixedMemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function sliceUint16PrefixedCdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes calldata ret, uint nextOffset) {
    uint16 len;
    (len, nextOffset) = asUint16CdUnchecked(encoded, offset);
    (ret, nextOffset) = sliceCdUnchecked(encoded, nextOffset, uint(len));
  }

  function sliceUint16PrefixedCd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes calldata ret, uint nextOffset) {
    (ret, nextOffset) = sliceUint16PrefixedCdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function sliceUint16PrefixedMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    uint16 len;
    (len, nextOffset) = asUint16MemUnchecked(encoded, offset);
    (ret, nextOffset) = sliceMemUnchecked(encoded, nextOffset, uint(len));
  }

  function sliceUint16PrefixedMem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    (ret, nextOffset) = sliceUint16PrefixedMemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function sliceUint32PrefixedCdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes calldata ret, uint nextOffset) {
    uint32 len;
    (len, nextOffset) = asUint32CdUnchecked(encoded, offset);
    (ret, nextOffset) = sliceCdUnchecked(encoded, nextOffset, uint(len));
  }

  function sliceUint32PrefixedCd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes calldata ret, uint nextOffset) {
    (ret, nextOffset) = sliceUint32PrefixedCdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function sliceUint32PrefixedMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    uint32 len;
    (len, nextOffset) = asUint32MemUnchecked(encoded, offset);
    (ret, nextOffset) = sliceMemUnchecked(encoded, nextOffset, uint(len));
  }

  function sliceUint32PrefixedMem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    (ret, nextOffset) = sliceUint32PrefixedMemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asAddressCdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (address ret, uint nextOffset) {
    uint160 tmp;
    (tmp, nextOffset) = asUint160CdUnchecked(encoded, offset);
    ret = address(tmp);
  }

  function asAddressCd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (address ret, uint nextOffset) {
    (ret, nextOffset) = asAddressCdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asAddressMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (address ret, uint nextOffset) {
    uint160 tmp;
    (tmp, nextOffset) = asUint160MemUnchecked(encoded, offset);
    ret = address(tmp);
  }

  function asAddressMem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (address ret, uint nextOffset) {
    (ret, nextOffset) = asAddressMemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBoolCdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bool ret, uint nextOffset) {
    uint8 val;
    (val, nextOffset) = asUint8CdUnchecked(encoded, offset);
    if (val & 0xfe != 0)
      revert InvalidBoolVal(val);
    uint cleanedVal = uint(val);
    //skip 2x iszero opcode
    /// @solidity memory-safe-assembly
    assembly { ret := cleanedVal }
  }

  function asBoolCd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bool ret, uint nextOffset) {
    (ret, nextOffset) = asBoolCdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBoolMemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bool ret, uint nextOffset) {
    uint8 val;
    (val, nextOffset) = asUint8MemUnchecked(encoded, offset);
    if (val & 0xfe != 0)
      revert InvalidBoolVal(val);
    uint cleanedVal = uint(val);
    //skip 2x iszero opcode
    /// @solidity memory-safe-assembly
    assembly { ret := cleanedVal }
  }

  function asBoolMem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bool ret, uint nextOffset) {
    (ret, nextOffset) = asBoolMemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint8CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint8 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 1)
      ret := shr(248, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint8Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint8 ret, uint nextOffset) {
    (ret, nextOffset) = asUint8CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint8MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint8 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 1)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint8Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint8 ret, uint nextOffset) {
    (ret, nextOffset) = asUint8MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint16CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint16 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 2)
      ret := shr(240, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint16Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint16 ret, uint nextOffset) {
    (ret, nextOffset) = asUint16CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint16MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint16 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 2)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint16Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint16 ret, uint nextOffset) {
    (ret, nextOffset) = asUint16MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint24CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint24 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 3)
      ret := shr(232, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint24Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint24 ret, uint nextOffset) {
    (ret, nextOffset) = asUint24CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint24MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint24 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 3)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint24Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint24 ret, uint nextOffset) {
    (ret, nextOffset) = asUint24MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint32CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint32 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 4)
      ret := shr(224, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint32Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint32 ret, uint nextOffset) {
    (ret, nextOffset) = asUint32CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint32MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint32 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 4)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint32Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint32 ret, uint nextOffset) {
    (ret, nextOffset) = asUint32MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint40CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint40 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 5)
      ret := shr(216, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint40Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint40 ret, uint nextOffset) {
    (ret, nextOffset) = asUint40CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint40MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint40 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 5)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint40Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint40 ret, uint nextOffset) {
    (ret, nextOffset) = asUint40MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint48CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint48 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 6)
      ret := shr(208, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint48Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint48 ret, uint nextOffset) {
    (ret, nextOffset) = asUint48CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint48MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint48 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 6)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint48Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint48 ret, uint nextOffset) {
    (ret, nextOffset) = asUint48MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint56CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint56 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 7)
      ret := shr(200, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint56Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint56 ret, uint nextOffset) {
    (ret, nextOffset) = asUint56CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint56MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint56 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 7)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint56Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint56 ret, uint nextOffset) {
    (ret, nextOffset) = asUint56MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint64CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint64 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 8)
      ret := shr(192, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint64Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint64 ret, uint nextOffset) {
    (ret, nextOffset) = asUint64CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint64MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint64 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 8)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint64Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint64 ret, uint nextOffset) {
    (ret, nextOffset) = asUint64MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint72CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint72 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 9)
      ret := shr(184, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint72Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint72 ret, uint nextOffset) {
    (ret, nextOffset) = asUint72CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint72MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint72 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 9)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint72Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint72 ret, uint nextOffset) {
    (ret, nextOffset) = asUint72MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint80CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint80 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 10)
      ret := shr(176, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint80Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint80 ret, uint nextOffset) {
    (ret, nextOffset) = asUint80CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint80MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint80 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 10)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint80Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint80 ret, uint nextOffset) {
    (ret, nextOffset) = asUint80MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint88CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint88 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 11)
      ret := shr(168, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint88Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint88 ret, uint nextOffset) {
    (ret, nextOffset) = asUint88CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint88MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint88 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 11)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint88Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint88 ret, uint nextOffset) {
    (ret, nextOffset) = asUint88MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint96CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint96 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 12)
      ret := shr(160, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint96Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint96 ret, uint nextOffset) {
    (ret, nextOffset) = asUint96CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint96MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint96 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 12)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint96Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint96 ret, uint nextOffset) {
    (ret, nextOffset) = asUint96MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint104CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint104 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 13)
      ret := shr(152, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint104Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint104 ret, uint nextOffset) {
    (ret, nextOffset) = asUint104CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint104MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint104 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 13)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint104Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint104 ret, uint nextOffset) {
    (ret, nextOffset) = asUint104MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint112CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint112 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 14)
      ret := shr(144, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint112Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint112 ret, uint nextOffset) {
    (ret, nextOffset) = asUint112CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint112MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint112 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 14)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint112Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint112 ret, uint nextOffset) {
    (ret, nextOffset) = asUint112MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint120CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint120 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 15)
      ret := shr(136, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint120Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint120 ret, uint nextOffset) {
    (ret, nextOffset) = asUint120CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint120MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint120 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 15)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint120Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint120 ret, uint nextOffset) {
    (ret, nextOffset) = asUint120MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint128CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint128 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 16)
      ret := shr(128, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint128Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint128 ret, uint nextOffset) {
    (ret, nextOffset) = asUint128CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint128MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint128 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 16)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint128Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint128 ret, uint nextOffset) {
    (ret, nextOffset) = asUint128MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint136CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint136 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 17)
      ret := shr(120, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint136Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint136 ret, uint nextOffset) {
    (ret, nextOffset) = asUint136CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint136MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint136 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 17)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint136Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint136 ret, uint nextOffset) {
    (ret, nextOffset) = asUint136MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint144CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint144 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 18)
      ret := shr(112, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint144Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint144 ret, uint nextOffset) {
    (ret, nextOffset) = asUint144CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint144MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint144 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 18)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint144Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint144 ret, uint nextOffset) {
    (ret, nextOffset) = asUint144MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint152CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint152 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 19)
      ret := shr(104, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint152Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint152 ret, uint nextOffset) {
    (ret, nextOffset) = asUint152CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint152MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint152 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 19)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint152Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint152 ret, uint nextOffset) {
    (ret, nextOffset) = asUint152MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint160CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint160 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 20)
      ret := shr(96, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint160Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint160 ret, uint nextOffset) {
    (ret, nextOffset) = asUint160CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint160MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint160 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 20)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint160Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint160 ret, uint nextOffset) {
    (ret, nextOffset) = asUint160MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint168CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint168 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 21)
      ret := shr(88, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint168Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint168 ret, uint nextOffset) {
    (ret, nextOffset) = asUint168CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint168MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint168 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 21)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint168Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint168 ret, uint nextOffset) {
    (ret, nextOffset) = asUint168MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint176CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint176 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 22)
      ret := shr(80, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint176Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint176 ret, uint nextOffset) {
    (ret, nextOffset) = asUint176CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint176MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint176 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 22)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint176Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint176 ret, uint nextOffset) {
    (ret, nextOffset) = asUint176MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint184CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint184 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 23)
      ret := shr(72, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint184Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint184 ret, uint nextOffset) {
    (ret, nextOffset) = asUint184CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint184MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint184 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 23)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint184Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint184 ret, uint nextOffset) {
    (ret, nextOffset) = asUint184MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint192CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint192 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 24)
      ret := shr(64, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint192Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint192 ret, uint nextOffset) {
    (ret, nextOffset) = asUint192CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint192MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint192 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 24)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint192Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint192 ret, uint nextOffset) {
    (ret, nextOffset) = asUint192MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint200CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint200 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 25)
      ret := shr(56, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint200Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint200 ret, uint nextOffset) {
    (ret, nextOffset) = asUint200CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint200MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint200 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 25)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint200Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint200 ret, uint nextOffset) {
    (ret, nextOffset) = asUint200MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint208CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint208 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 26)
      ret := shr(48, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint208Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint208 ret, uint nextOffset) {
    (ret, nextOffset) = asUint208CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint208MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint208 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 26)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint208Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint208 ret, uint nextOffset) {
    (ret, nextOffset) = asUint208MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint216CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint216 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 27)
      ret := shr(40, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint216Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint216 ret, uint nextOffset) {
    (ret, nextOffset) = asUint216CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint216MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint216 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 27)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint216Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint216 ret, uint nextOffset) {
    (ret, nextOffset) = asUint216MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint224CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint224 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 28)
      ret := shr(32, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint224Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint224 ret, uint nextOffset) {
    (ret, nextOffset) = asUint224CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint224MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint224 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 28)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint224Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint224 ret, uint nextOffset) {
    (ret, nextOffset) = asUint224MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint232CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint232 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 29)
      ret := shr(24, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint232Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint232 ret, uint nextOffset) {
    (ret, nextOffset) = asUint232CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint232MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint232 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 29)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint232Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint232 ret, uint nextOffset) {
    (ret, nextOffset) = asUint232MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint240CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint240 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 30)
      ret := shr(16, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint240Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint240 ret, uint nextOffset) {
    (ret, nextOffset) = asUint240CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint240MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint240 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 30)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint240Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint240 ret, uint nextOffset) {
    (ret, nextOffset) = asUint240MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint248CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint248 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 31)
      ret := shr(8, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint248Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint248 ret, uint nextOffset) {
    (ret, nextOffset) = asUint248CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint248MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint248 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 31)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint248Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint248 ret, uint nextOffset) {
    (ret, nextOffset) = asUint248MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint256CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint256 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 32)
      ret := shr(0, calldataload(add(encoded.offset, offset)))
    }
  }

  function asUint256Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (uint256 ret, uint nextOffset) {
    (ret, nextOffset) = asUint256CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asUint256MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint256 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      nextOffset := add(offset, 32)
      ret := mload(add(encoded, nextOffset))
    }
  }

  function asUint256Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint256 ret, uint nextOffset) {
    (ret, nextOffset) = asUint256MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes1CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes1 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 1)
    }
  }

  function asBytes1Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes1 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes1CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes1MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes1 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 1)
    }
  }

  function asBytes1Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes1 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes1MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes2CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes2 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 2)
    }
  }

  function asBytes2Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes2 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes2CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes2MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes2 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 2)
    }
  }

  function asBytes2Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes2 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes2MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes3CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes3 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 3)
    }
  }

  function asBytes3Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes3 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes3CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes3MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes3 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 3)
    }
  }

  function asBytes3Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes3 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes3MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes4CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes4 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 4)
    }
  }

  function asBytes4Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes4 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes4CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes4MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes4 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 4)
    }
  }

  function asBytes4Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes4 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes4MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes5CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes5 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 5)
    }
  }

  function asBytes5Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes5 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes5CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes5MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes5 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 5)
    }
  }

  function asBytes5Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes5 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes5MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes6CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes6 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 6)
    }
  }

  function asBytes6Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes6 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes6CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes6MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes6 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 6)
    }
  }

  function asBytes6Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes6 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes6MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes7CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes7 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 7)
    }
  }

  function asBytes7Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes7 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes7CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes7MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes7 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 7)
    }
  }

  function asBytes7Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes7 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes7MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes8CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes8 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 8)
    }
  }

  function asBytes8Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes8 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes8CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes8MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes8 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 8)
    }
  }

  function asBytes8Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes8 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes8MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes9CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes9 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 9)
    }
  }

  function asBytes9Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes9 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes9CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes9MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes9 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 9)
    }
  }

  function asBytes9Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes9 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes9MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes10CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes10 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 10)
    }
  }

  function asBytes10Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes10 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes10CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes10MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes10 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 10)
    }
  }

  function asBytes10Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes10 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes10MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes11CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes11 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 11)
    }
  }

  function asBytes11Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes11 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes11CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes11MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes11 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 11)
    }
  }

  function asBytes11Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes11 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes11MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes12CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes12 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 12)
    }
  }

  function asBytes12Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes12 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes12CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes12MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes12 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 12)
    }
  }

  function asBytes12Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes12 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes12MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes13CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes13 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 13)
    }
  }

  function asBytes13Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes13 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes13CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes13MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes13 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 13)
    }
  }

  function asBytes13Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes13 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes13MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes14CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes14 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 14)
    }
  }

  function asBytes14Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes14 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes14CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes14MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes14 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 14)
    }
  }

  function asBytes14Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes14 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes14MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes15CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes15 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 15)
    }
  }

  function asBytes15Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes15 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes15CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes15MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes15 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 15)
    }
  }

  function asBytes15Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes15 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes15MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes16CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes16 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 16)
    }
  }

  function asBytes16Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes16 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes16CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes16MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes16 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 16)
    }
  }

  function asBytes16Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes16 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes16MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes17CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes17 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 17)
    }
  }

  function asBytes17Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes17 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes17CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes17MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes17 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 17)
    }
  }

  function asBytes17Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes17 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes17MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes18CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes18 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 18)
    }
  }

  function asBytes18Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes18 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes18CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes18MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes18 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 18)
    }
  }

  function asBytes18Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes18 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes18MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes19CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes19 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 19)
    }
  }

  function asBytes19Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes19 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes19CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes19MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes19 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 19)
    }
  }

  function asBytes19Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes19 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes19MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes20CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes20 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 20)
    }
  }

  function asBytes20Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes20 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes20CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes20MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes20 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 20)
    }
  }

  function asBytes20Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes20 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes20MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes21CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes21 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 21)
    }
  }

  function asBytes21Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes21 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes21CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes21MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes21 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 21)
    }
  }

  function asBytes21Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes21 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes21MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes22CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes22 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 22)
    }
  }

  function asBytes22Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes22 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes22CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes22MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes22 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 22)
    }
  }

  function asBytes22Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes22 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes22MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes23CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes23 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 23)
    }
  }

  function asBytes23Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes23 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes23CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes23MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes23 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 23)
    }
  }

  function asBytes23Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes23 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes23MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes24CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes24 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 24)
    }
  }

  function asBytes24Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes24 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes24CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes24MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes24 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 24)
    }
  }

  function asBytes24Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes24 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes24MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes25CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes25 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 25)
    }
  }

  function asBytes25Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes25 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes25CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes25MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes25 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 25)
    }
  }

  function asBytes25Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes25 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes25MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes26CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes26 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 26)
    }
  }

  function asBytes26Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes26 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes26CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes26MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes26 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 26)
    }
  }

  function asBytes26Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes26 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes26MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes27CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes27 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 27)
    }
  }

  function asBytes27Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes27 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes27CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes27MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes27 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 27)
    }
  }

  function asBytes27Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes27 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes27MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes28CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes28 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 28)
    }
  }

  function asBytes28Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes28 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes28CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes28MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes28 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 28)
    }
  }

  function asBytes28Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes28 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes28MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes29CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes29 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 29)
    }
  }

  function asBytes29Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes29 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes29CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes29MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes29 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 29)
    }
  }

  function asBytes29Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes29 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes29MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes30CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes30 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 30)
    }
  }

  function asBytes30Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes30 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes30CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes30MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes30 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 30)
    }
  }

  function asBytes30Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes30 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes30MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes31CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes31 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 31)
    }
  }

  function asBytes31Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes31 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes31CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes31MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes31 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 31)
    }
  }

  function asBytes31Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes31 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes31MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes32CdUnchecked(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes32 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := calldataload(add(encoded.offset, offset))
      nextOffset := add(offset, 32)
    }
  }

  function asBytes32Cd(
    bytes calldata encoded,
    uint offset
  ) internal pure returns (bytes32 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes32CdUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes32MemUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes32 ret, uint nextOffset) {
    /// @solidity memory-safe-assembly
    assembly {
      ret := mload(add(encoded, add(offset, WORD_SIZE)))
      nextOffset := add(offset, 32)
    }
  }

  function asBytes32Mem(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes32 ret, uint nextOffset) {
    (ret, nextOffset) = asBytes32MemUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }
}

File 25 of 42 : Utils.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;

import {
  tokenOrNativeTransfer
} from "wormhole-sdk/utils/Transfer.sol";
import {
  reRevert
} from "wormhole-sdk/utils/Revert.sol";
import {
  NotAnEvmAddress,
  toUniversalAddress,
  fromUniversalAddress
} from "wormhole-sdk/utils/UniversalAddress.sol";
import {
  keccak256Word,
  keccak256SliceUnchecked,
  keccak256Cd
} from "wormhole-sdk/utils/Keccak.sol";
import {
  eagerAnd,
  eagerOr
} from "wormhole-sdk/utils/EagerOps.sol";

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IBridgeController {
    event BridgeAdapterCreated(uint16 indexed bridgeId, address indexed adapter);
    event MaxBridgeLossBpsChanged(
        uint16 indexed bridgeId, uint256 indexed oldMaxBridgeLossBps, uint256 indexed newMaxBridgeLossBps
    );
    event BridgingStateReset(address indexed token);
    event OutTransferEnabledSet(uint256 indexed bridgeId, bool enabled);

    /// @notice Bridge ID => Is bridge adapter deployed.
    function isBridgeSupported(uint16 bridgeId) external view returns (bool);

    /// @notice Bridge ID => Is outgoing transfer enabled.
    function isOutTransferEnabled(uint16 bridgeId) external view returns (bool);

    /// @notice Bridge ID => Address of the associated bridge adapter.
    function getBridgeAdapter(uint16 bridgeId) external view returns (address);

    /// @notice Bridge ID => Max allowed value loss in basis points for transfers via this bridge.
    function getMaxBridgeLossBps(uint16 bridgeId) external view returns (uint256);

    /// @notice Deploys a new BridgeAdapter instance.
    /// @param bridgeId The ID of the bridge.
    /// @param initialMaxBridgeLossBps The initial maximum allowed value loss in basis points for transfers via this bridge.
    /// @param initData The optional initialization data for the bridge adapter.
    /// @return The address of the deployed BridgeAdapter.
    function createBridgeAdapter(uint16 bridgeId, uint256 initialMaxBridgeLossBps, bytes calldata initData)
        external
        returns (address);

    /// @notice Sets the maximum allowed value loss in basis points for transfers via this bridge.
    /// @param bridgeId The ID of the bridge.
    /// @param maxBridgeLossBps The maximum allowed value loss in basis points.
    function setMaxBridgeLossBps(uint16 bridgeId, uint256 maxBridgeLossBps) external;

    /// @notice Sets the outgoing transfer enabled status for a bridge.
    /// @param bridgeId The ID of the bridge.
    /// @param enabled True to enable outgoing transfer for the given bridge ID, false to disable.
    function setOutTransferEnabled(uint16 bridgeId, bool enabled) external;

    /// @notice Executes a scheduled outgoing bridge transfer.
    /// @param bridgeId The ID of the bridge.
    /// @param transferId The ID of the transfer to execute.
    /// @param data The optional data needed to execute the transfer.
    function sendOutBridgeTransfer(uint16 bridgeId, uint256 transferId, bytes calldata data) external;

    /// @notice Registers a message hash as authorized for an incoming bridge transfer.
    /// @param bridgeId The ID of the bridge.
    /// @param messageHash The hash of the message to authorize.
    function authorizeInBridgeTransfer(uint16 bridgeId, bytes32 messageHash) external;

    /// @notice Transfers a received bridge transfer out of the adapter.
    /// @param bridgeId The ID of the bridge.
    /// @param transferId The ID of the transfer to claim.
    function claimInBridgeTransfer(uint16 bridgeId, uint256 transferId) external;

    /// @notice Cancels an outgoing bridge transfer.
    /// @param bridgeId The ID of the bridge.
    /// @param transferId The ID of the transfer to cancel.
    function cancelOutBridgeTransfer(uint16 bridgeId, uint256 transferId) external;

    /// @notice Resets internal bridge counters for a given token, and withdraw token balances held by all bridge adapters.
    /// @dev This function is intended to be used by the DAO to realign bridge accounting state and maintain protocol consistency,
    ///      typically in response to operator deviations, external bridge discrepancies, or unbounded counter growth.
    /// @param token The address of the token.
    function resetBridgingState(address token) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

File 28 of 42 : Arrays.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)
// This file was procedurally generated from scripts/generate/templates/Arrays.js.

pragma solidity ^0.8.20;

import {Comparators} from "./Comparators.sol";
import {SlotDerivation} from "./SlotDerivation.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";

/**
 * @dev Collection of functions related to array types.
 */
library Arrays {
    using SlotDerivation for bytes32;
    using StorageSlot for bytes32;

    /**
     * @dev Sort an array of uint256 (in memory) following the provided comparator function.
     *
     * This function does the sorting "in place", meaning that it overrides the input. The object is returned for
     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
     *
     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
     * consume more gas than is available in a block, leading to potential DoS.
     *
     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
     */
    function sort(
        uint256[] memory array,
        function(uint256, uint256) pure returns (bool) comp
    ) internal pure returns (uint256[] memory) {
        _quickSort(_begin(array), _end(array), comp);
        return array;
    }

    /**
     * @dev Variant of {sort} that sorts an array of uint256 in increasing order.
     */
    function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
        sort(array, Comparators.lt);
        return array;
    }

    /**
     * @dev Sort an array of address (in memory) following the provided comparator function.
     *
     * This function does the sorting "in place", meaning that it overrides the input. The object is returned for
     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
     *
     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
     * consume more gas than is available in a block, leading to potential DoS.
     *
     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
     */
    function sort(
        address[] memory array,
        function(address, address) pure returns (bool) comp
    ) internal pure returns (address[] memory) {
        sort(_castToUint256Array(array), _castToUint256Comp(comp));
        return array;
    }

    /**
     * @dev Variant of {sort} that sorts an array of address in increasing order.
     */
    function sort(address[] memory array) internal pure returns (address[] memory) {
        sort(_castToUint256Array(array), Comparators.lt);
        return array;
    }

    /**
     * @dev Sort an array of bytes32 (in memory) following the provided comparator function.
     *
     * This function does the sorting "in place", meaning that it overrides the input. The object is returned for
     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
     *
     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
     * consume more gas than is available in a block, leading to potential DoS.
     *
     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
     */
    function sort(
        bytes32[] memory array,
        function(bytes32, bytes32) pure returns (bool) comp
    ) internal pure returns (bytes32[] memory) {
        sort(_castToUint256Array(array), _castToUint256Comp(comp));
        return array;
    }

    /**
     * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
     */
    function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
        sort(_castToUint256Array(array), Comparators.lt);
        return array;
    }

    /**
     * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops
     * at end (exclusive). Sorting follows the `comp` comparator.
     *
     * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.
     *
     * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
     * be used only if the limits are within a memory array.
     */
    function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {
        unchecked {
            if (end - begin < 0x40) return;

            // Use first element as pivot
            uint256 pivot = _mload(begin);
            // Position where the pivot should be at the end of the loop
            uint256 pos = begin;

            for (uint256 it = begin + 0x20; it < end; it += 0x20) {
                if (comp(_mload(it), pivot)) {
                    // If the value stored at the iterator's position comes before the pivot, we increment the
                    // position of the pivot and move the value there.
                    pos += 0x20;
                    _swap(pos, it);
                }
            }

            _swap(begin, pos); // Swap pivot into place
            _quickSort(begin, pos, comp); // Sort the left side of the pivot
            _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot
        }
    }

    /**
     * @dev Pointer to the memory location of the first element of `array`.
     */
    function _begin(uint256[] memory array) private pure returns (uint256 ptr) {
        assembly ("memory-safe") {
            ptr := add(array, 0x20)
        }
    }

    /**
     * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
     * that comes just after the last element of the array.
     */
    function _end(uint256[] memory array) private pure returns (uint256 ptr) {
        unchecked {
            return _begin(array) + array.length * 0x20;
        }
    }

    /**
     * @dev Load memory word (as a uint256) at location `ptr`.
     */
    function _mload(uint256 ptr) private pure returns (uint256 value) {
        assembly {
            value := mload(ptr)
        }
    }

    /**
     * @dev Swaps the elements memory location `ptr1` and `ptr2`.
     */
    function _swap(uint256 ptr1, uint256 ptr2) private pure {
        assembly {
            let value1 := mload(ptr1)
            let value2 := mload(ptr2)
            mstore(ptr1, value2)
            mstore(ptr2, value1)
        }
    }

    /// @dev Helper: low level cast address memory array to uint256 memory array
    function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
        assembly {
            output := input
        }
    }

    /// @dev Helper: low level cast bytes32 memory array to uint256 memory array
    function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
        assembly {
            output := input
        }
    }

    /// @dev Helper: low level cast address comp function to uint256 comp function
    function _castToUint256Comp(
        function(address, address) pure returns (bool) input
    ) private pure returns (function(uint256, uint256) pure returns (bool) output) {
        assembly {
            output := input
        }
    }

    /// @dev Helper: low level cast bytes32 comp function to uint256 comp function
    function _castToUint256Comp(
        function(bytes32, bytes32) pure returns (bool) input
    ) private pure returns (function(uint256, uint256) pure returns (bool) output) {
        assembly {
            output := input
        }
    }

    /**
     * @dev Searches a sorted `array` and returns the first index that contains
     * a value greater or equal to `element`. If no such index exists (i.e. all
     * values in the array are strictly less than `element`), the array length is
     * returned. Time complexity O(log n).
     *
     * NOTE: The `array` is expected to be sorted in ascending order, and to
     * contain no repeated elements.
     *
     * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks
     * support for repeated elements in the array. The {lowerBound} function should
     * be used instead.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && unsafeAccess(array, low - 1).value == element) {
            return low - 1;
        } else {
            return low;
        }
    }

    /**
     * @dev Searches an `array` sorted in ascending order and returns the first
     * index that contains a value greater or equal than `element`. If no such index
     * exists (i.e. all values in the array are strictly less than `element`), the array
     * length is returned. Time complexity O(log n).
     *
     * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].
     */
    function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value < element) {
                // this cannot overflow because mid < high
                unchecked {
                    low = mid + 1;
                }
            } else {
                high = mid;
            }
        }

        return low;
    }

    /**
     * @dev Searches an `array` sorted in ascending order and returns the first
     * index that contains a value strictly greater than `element`. If no such index
     * exists (i.e. all values in the array are strictly less than `element`), the array
     * length is returned. Time complexity O(log n).
     *
     * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].
     */
    function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value > element) {
                high = mid;
            } else {
                // this cannot overflow because mid < high
                unchecked {
                    low = mid + 1;
                }
            }
        }

        return low;
    }

    /**
     * @dev Same as {lowerBound}, but with an array in memory.
     */
    function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeMemoryAccess(array, mid) < element) {
                // this cannot overflow because mid < high
                unchecked {
                    low = mid + 1;
                }
            } else {
                high = mid;
            }
        }

        return low;
    }

    /**
     * @dev Same as {upperBound}, but with an array in memory.
     */
    function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeMemoryAccess(array, mid) > element) {
                high = mid;
            } else {
                // this cannot overflow because mid < high
                unchecked {
                    low = mid + 1;
                }
            }
        }

        return low;
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getAddressSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getBytes32Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getUint256Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getBytesSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getStringSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(address[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(bytes32[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(uint256[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(bytes[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(string[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }
}

File 29 of 42 : Common.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;

// ┌──────────────────────────────────────────────────────────────────────────────┐
// │ NOTE: We can't define e.g. WORD_SIZE_MINUS_ONE via WORD_SIZE - 1 because     │
// │       of solc restrictions on what constants can be used in inline assembly. │
// └──────────────────────────────────────────────────────────────────────────────┘

uint256 constant WORD_SIZE = 32;
uint256 constant WORD_SIZE_MINUS_ONE = 31; //=0x1f=0b00011111
//see section "prefer `< MAX + 1` over `<= MAX` for const comparison" in docs/Optimization.md
uint256 constant WORD_SIZE_PLUS_ONE = 33;

uint256 constant SCRATCH_SPACE_PTR = 0x00;
uint256 constant SCRATCH_SPACE_SIZE = 64;

uint256 constant FREE_MEMORY_PTR = 0x40;

File 30 of 42 : Transfer.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;

import {IERC20} from "IERC20/IERC20.sol";
import {SafeERC20} from "SafeERC20/SafeERC20.sol";

error PaymentFailure(address target);

//Note: Always forwards all gas, so consider gas griefing attack opportunities by the recipient.
//Note: Don't use this method if you need events for 0 amount transfers.
function tokenOrNativeTransfer(address tokenOrZeroForNative, address to, uint256 amount) {
  if (amount == 0)
    return;

  if (tokenOrZeroForNative == address(0)) {
    (bool success, ) = to.call{value: amount}(new bytes(0));
    if (!success)
      revert PaymentFailure(to);
  }
  else
    SafeERC20.safeTransfer(IERC20(tokenOrZeroForNative), to, amount);
}

File 31 of 42 : Revert.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;

import {WORD_SIZE} from "wormhole-sdk/constants/Common.sol";

//bubble up errors from low level calls
function reRevert(bytes memory err) pure {
  assembly ("memory-safe") {
    revert(add(err, WORD_SIZE), mload(err))
  }
}

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;

error NotAnEvmAddress(bytes32);

function toUniversalAddress(address addr) pure returns (bytes32 universalAddr) {
  universalAddr = bytes32(uint256(uint160(addr)));
}

function fromUniversalAddress(bytes32 universalAddr) pure returns (address addr) {
  if (bytes12(universalAddr) != 0)
    revert NotAnEvmAddress(universalAddr);

  assembly ("memory-safe") {
    addr := universalAddr
  }
}

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;

import {WORD_SIZE, SCRATCH_SPACE_PTR, FREE_MEMORY_PTR} from "wormhole-sdk/constants/Common.sol";

function keccak256Word(bytes32 word) pure returns (bytes32 hash) {
  /// @solidity memory-safe-assembly
  assembly {
    mstore(SCRATCH_SPACE_PTR, word)
    hash := keccak256(SCRATCH_SPACE_PTR, WORD_SIZE)
  }
}

function keccak256SliceUnchecked(
  bytes memory encoded,
  uint offset,
  uint length
) pure returns (bytes32 hash) {
  /// @solidity memory-safe-assembly
  assembly {
    // The length of the bytes type `length` field is that of a word in memory
    let ptr := add(add(encoded, offset), WORD_SIZE)
    hash := keccak256(ptr, length)
  }
}

function keccak256Cd(
  bytes calldata encoded
) pure returns (bytes32 hash) {
  /// @solidity memory-safe-assembly
  assembly {
    let freeMemory := mload(FREE_MEMORY_PTR)
    calldatacopy(freeMemory, encoded.offset, encoded.length)
    hash := keccak256(freeMemory, encoded.length)
  }
}

File 34 of 42 : EagerOps.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;

//see Optimization.md for rationale on avoiding short-circuiting
function eagerAnd(bool lhs, bool rhs) pure returns (bool ret) {
  /// @solidity memory-safe-assembly
  assembly {
    ret := and(lhs, rhs)
  }
}

//see Optimization.md for rationale on avoiding short-circuiting
function eagerOr(bool lhs, bool rhs) pure returns (bool ret) {
  /// @solidity memory-safe-assembly
  assembly {
    ret := or(lhs, rhs)
  }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides a set of functions to compare values.
 *
 * _Available since v5.1._
 */
library Comparators {
    function lt(uint256 a, uint256 b) internal pure returns (bool) {
        return a < b;
    }

    function gt(uint256 a, uint256 b) internal pure returns (bool) {
        return a > b;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)
// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
 * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
 * the solidity language / compiler.
 *
 * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
 *
 * Example usage:
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using StorageSlot for bytes32;
 *     using SlotDerivation for bytes32;
 *
 *     // Declare a namespace
 *     string private constant _NAMESPACE = "<namespace>"; // eg. OpenZeppelin.Slot
 *
 *     function setValueInNamespace(uint256 key, address newValue) internal {
 *         _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
 *     }
 *
 *     function getValueInNamespace(uint256 key) internal view returns (address) {
 *         return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {StorageSlot}.
 *
 * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
 * upgrade safety will ignore the slots accessed through this library.
 *
 * _Available since v5.1._
 */
library SlotDerivation {
    /**
     * @dev Derive an ERC-7201 slot from a string (namespace).
     */
    function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
        assembly ("memory-safe") {
            mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
            slot := and(keccak256(0x00, 0x20), not(0xff))
        }
    }

    /**
     * @dev Add an offset to a slot to get the n-th element of a structure or an array.
     */
    function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
        unchecked {
            return bytes32(uint256(slot) + pos);
        }
    }

    /**
     * @dev Derive the location of the first element in an array from the slot where the length is stored.
     */
    function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, slot)
            result := keccak256(0x00, 0x20)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, and(key, shr(96, not(0))))
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, iszero(iszero(key)))
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, key)
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, key)
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, key)
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            let length := mload(key)
            let begin := add(key, 0x20)
            let end := add(begin, length)
            let cache := mload(end)
            mstore(end, slot)
            result := keccak256(begin, add(length, 0x20))
            mstore(end, cache)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            let length := mload(key)
            let begin := add(key, 0x20)
            let end := add(begin, length)
            let cache := mload(end)
            mstore(end, slot)
            result := keccak256(begin, add(length, 0x20))
            mstore(end, cache)
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}

File 38 of 42 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Return the 512-bit addition of two uint256.
     *
     * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
     */
    function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        assembly ("memory-safe") {
            low := add(a, b)
            high := lt(low, a)
        }
    }

    /**
     * @dev Return the 512-bit multiplication of two uint256.
     *
     * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
     */
    function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
        // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = high * 2²⁵⁶ + low.
        assembly ("memory-safe") {
            let mm := mulmod(a, b, not(0))
            low := mul(a, b)
            high := sub(sub(mm, low), lt(mm, low))
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a + b;
            success = c >= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a - b;
            success = c <= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a * b;
            assembly ("memory-safe") {
                // Only true when the multiplication doesn't overflow
                // (c / a == b) || (a == 0)
                success := or(eq(div(c, a), b), iszero(a))
            }
            // equivalent to: success ? c : 0
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `DIV` opcode returns zero when the denominator is 0.
                result := div(a, b)
            }
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `MOD` opcode returns zero when the denominator is 0.
                result := mod(a, b)
            }
        }
    }

    /**
     * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryAdd(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
     */
    function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
        (, uint256 result) = trySub(a, b);
        return result;
    }

    /**
     * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryMul(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
     *
     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
     * one branch when needed, making this function more expensive.
     */
    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * SafeCast.toUint(condition));
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a > b, a, b);
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a < b, a, b);
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        // The following calculation ensures accurate ceiling division without overflow.
        // Since a is non-zero, (a - 1) / b will not overflow.
        // The largest possible result occurs when (a - 1) / b is type(uint256).max,
        // but the largest value we can obtain is type(uint256).max - 1, which happens
        // when a = type(uint256).max and b = 1.
        unchecked {
            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
        }
    }

    /**
     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     *
     * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);

            // Handle non-overflow cases, 256 by 256 division.
            if (high == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return low / denominator;
            }

            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
            if (denominator <= high) {
                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [high low].
            uint256 remainder;
            assembly ("memory-safe") {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                high := sub(high, gt(remainder, low))
                low := sub(low, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly ("memory-safe") {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [high low] by twos.
                low := div(low, twos)

                // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from high into low.
            low |= high * twos;

            // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
            inverse *= 2 - denominator * inverse; // inverse mod 2³²
            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
            // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
            // is no longer required.
            result = low * inverse;
            return result;
        }
    }

    /**
     * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
    }

    /**
     * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
     */
    function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);
            if (high >= 1 << n) {
                Panic.panic(Panic.UNDER_OVERFLOW);
            }
            return (high << (256 - n)) | (low >> n);
        }
    }

    /**
     * @dev Calculates x * y >> n with full precision, following the selected rounding direction.
     */
    function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
        return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
    }

    /**
     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
     *
     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
     *
     * If the input value is not inversible, 0 is returned.
     *
     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
     */
    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
        unchecked {
            if (n == 0) return 0;

            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
            // Used to compute integers x and y such that: ax + ny = gcd(a, n).
            // When the gcd is 1, then the inverse of a modulo n exists and it's x.
            // ax + ny = 1
            // ax = 1 + (-y)n
            // ax ≡ 1 (mod n) # x is the inverse of a modulo n

            // If the remainder is 0 the gcd is n right away.
            uint256 remainder = a % n;
            uint256 gcd = n;

            // Therefore the initial coefficients are:
            // ax + ny = gcd(a, n) = n
            // 0a + 1n = n
            int256 x = 0;
            int256 y = 1;

            while (remainder != 0) {
                uint256 quotient = gcd / remainder;

                (gcd, remainder) = (
                    // The old remainder is the next gcd to try.
                    remainder,
                    // Compute the next remainder.
                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
                    // where gcd is at most n (capped to type(uint256).max)
                    gcd - remainder * quotient
                );

                (x, y) = (
                    // Increment the coefficient of a.
                    y,
                    // Decrement the coefficient of n.
                    // Can overflow, but the result is casted to uint256 so that the
                    // next value of y is "wrapped around" to a value between 0 and n - 1.
                    x - y * int256(quotient)
                );
            }

            if (gcd != 1) return 0; // No inverse exists.
            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
        }
    }

    /**
     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
     *
     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.
     *
     * NOTE: this function does NOT check that `p` is a prime greater than `2`.
     */
    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
        unchecked {
            return Math.modExp(a, p - 2, p);
        }
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
     *
     * Requirements:
     * - modulus can't be zero
     * - underlying staticcall to precompile must succeed
     *
     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
     * sure the chain you're using it on supports the precompiled contract for modular exponentiation
     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly
     * interpreted as 0.
     */
    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
        (bool success, uint256 result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
     * to operate modulo 0 or if the underlying precompile reverted.
     *
     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
     * of a revert, but the result may be incorrectly interpreted as 0.
     */
    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
        if (m == 0) return (false, 0);
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            // | Offset    | Content    | Content (Hex)                                                      |
            // |-----------|------------|--------------------------------------------------------------------|
            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x60:0x7f | value of b | 0x<.............................................................b> |
            // | 0x80:0x9f | value of e | 0x<.............................................................e> |
            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |
            mstore(ptr, 0x20)
            mstore(add(ptr, 0x20), 0x20)
            mstore(add(ptr, 0x40), 0x20)
            mstore(add(ptr, 0x60), b)
            mstore(add(ptr, 0x80), e)
            mstore(add(ptr, 0xa0), m)

            // Given the result < m, it's guaranteed to fit in 32 bytes,
            // so we can use the memory scratch space located at offset 0.
            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
            result := mload(0x00)
        }
    }

    /**
     * @dev Variant of {modExp} that supports inputs of arbitrary length.
     */
    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
        (bool success, bytes memory result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.
     */
    function tryModExp(
        bytes memory b,
        bytes memory e,
        bytes memory m
    ) internal view returns (bool success, bytes memory result) {
        if (_zeroBytes(m)) return (false, new bytes(0));

        uint256 mLen = m.length;

        // Encode call args in result and move the free memory pointer
        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);

        assembly ("memory-safe") {
            let dataPtr := add(result, 0x20)
            // Write result on top of args to avoid allocating extra memory.
            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
            // Overwrite the length.
            // result.length > returndatasize() is guaranteed because returndatasize() == m.length
            mstore(result, mLen)
            // Set the memory pointer after the returned data.
            mstore(0x40, add(dataPtr, mLen))
        }
    }

    /**
     * @dev Returns whether the provided byte array is zero.
     */
    function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
        for (uint256 i = 0; i < byteArray.length; ++i) {
            if (byteArray[i] != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only
     * using integer operations.
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        unchecked {
            // Take care of easy edge cases when a == 0 or a == 1
            if (a <= 1) {
                return a;
            }

            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
            // the current value as `ε_n = | x_n - sqrt(a) |`.
            //
            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
            // bigger than any uint256.
            //
            // By noticing that
            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
            // to the msb function.
            uint256 aa = a;
            uint256 xn = 1;

            if (aa >= (1 << 128)) {
                aa >>= 128;
                xn <<= 64;
            }
            if (aa >= (1 << 64)) {
                aa >>= 64;
                xn <<= 32;
            }
            if (aa >= (1 << 32)) {
                aa >>= 32;
                xn <<= 16;
            }
            if (aa >= (1 << 16)) {
                aa >>= 16;
                xn <<= 8;
            }
            if (aa >= (1 << 8)) {
                aa >>= 8;
                xn <<= 4;
            }
            if (aa >= (1 << 4)) {
                aa >>= 4;
                xn <<= 2;
            }
            if (aa >= (1 << 2)) {
                xn <<= 1;
            }

            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
            //
            // We can refine our estimation by noticing that the middle of that interval minimizes the error.
            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
            // This is going to be our x_0 (and ε_0)
            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)

            // From here, Newton's method give us:
            // x_{n+1} = (x_n + a / x_n) / 2
            //
            // One should note that:
            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
            //              = ((x_n² + a) / (2 * x_n))² - a
            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
            //              = (x_n² - a)² / (2 * x_n)²
            //              = ((x_n² - a) / (2 * x_n))²
            //              ≥ 0
            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
            //
            // This gives us the proof of quadratic convergence of the sequence:
            // ε_{n+1} = | x_{n+1} - sqrt(a) |
            //         = | (x_n + a / x_n) / 2 - sqrt(a) |
            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
            //         = | (x_n - sqrt(a))² / (2 * x_n) |
            //         = | ε_n² / (2 * x_n) |
            //         = ε_n² / | (2 * x_n) |
            //
            // For the first iteration, we have a special case where x_0 is known:
            // ε_1 = ε_0² / | (2 * x_0) |
            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))
            //     ≤ 2**(e-3) / 3
            //     ≤ 2**(e-3-log2(3))
            //     ≤ 2**(e-4.5)
            //
            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
            // ε_{n+1} = ε_n² / | (2 * x_n) |
            //         ≤ (2**(e-k))² / (2 * 2**(e-1))
            //         ≤ 2**(2*e-2*k) / 2**e
            //         ≤ 2**(e-2*k)
            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above
            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5
            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9
            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18
            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36
            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72

            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
            // sqrt(a) or sqrt(a) + 1.
            return xn - SafeCast.toUint(xn > a / xn);
        }
    }

    /**
     * @dev Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // If upper 8 bits of 16-bit half set, add 8 to result
        r |= SafeCast.toUint((x >> r) > 0xff) << 3;
        // If upper 4 bits of 8-bit half set, add 4 to result
        r |= SafeCast.toUint((x >> r) > 0xf) << 2;

        // Shifts value right by the current result and use it as an index into this lookup table:
        //
        // | x (4 bits) |  index  | table[index] = MSB position |
        // |------------|---------|-----------------------------|
        // |    0000    |    0    |        table[0] = 0         |
        // |    0001    |    1    |        table[1] = 0         |
        // |    0010    |    2    |        table[2] = 1         |
        // |    0011    |    3    |        table[3] = 1         |
        // |    0100    |    4    |        table[4] = 2         |
        // |    0101    |    5    |        table[5] = 2         |
        // |    0110    |    6    |        table[6] = 2         |
        // |    0111    |    7    |        table[7] = 2         |
        // |    1000    |    8    |        table[8] = 3         |
        // |    1001    |    9    |        table[9] = 3         |
        // |    1010    |   10    |        table[10] = 3        |
        // |    1011    |   11    |        table[11] = 3        |
        // |    1100    |   12    |        table[12] = 3        |
        // |    1101    |   13    |        table[13] = 3        |
        // |    1110    |   14    |        table[14] = 3        |
        // |    1111    |   15    |        table[15] = 3        |
        //
        // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
        assembly ("memory-safe") {
            r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
        }
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
        return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

//https://eips.ethereum.org/EIPS/eip-20
interface IERC20 {
  event Transfer(address indexed from, address indexed to, uint256 value);
  event Approval(address indexed owner, address indexed spender, uint256 value);

  function totalSupply() external view returns (uint256);
  function balanceOf(address account) external view returns (uint256);
  function allowance(address owner, address spender) external view returns (uint256);

  function transfer(address to, uint256 amount) external returns (bool);
  function approve(address spender, uint256 amount) external returns (bool);
  function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;

import {IERC20} from "IERC20/IERC20.sol";
import {WORD_SIZE, SCRATCH_SPACE_PTR} from "wormhole-sdk/constants/Common.sol";

//Like OpenZeppelin's SafeERC20.sol, but slimmed down and more gas efficient.
//
//The main difference to OZ's implementation (besides the missing functions) is that we skip the
//  EXTCODESIZE check that OZ does upon successful calls to ensure that an actual contract was
//  called. The rationale for omitting this check is that ultimately the contract using the token
//  has to verify that it "makes sense" for its use case regardless. Otherwise, a random token, or
//  even just a contract that always returns true, could be passed, which makes this check
//  superfluous in the final analysis.
//
//We also save on code size by not duplicating the assembly code in two separate functions.
//  Otoh, we simply swallow revert reasons of failing token operations instead of bubbling them up.
//  This is less clean and makes debugging harder, but is likely still a worthwhile trade-off
//    given the cost in gas and code size.
library SafeERC20 {
  error SafeERC20FailedOperation(address token);

  function safeTransfer(IERC20 token, address to, uint256 value) internal {
    _revertOnFailure(token, abi.encodeCall(token.transfer, (to, value)));
  }

  function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
    _revertOnFailure(token, abi.encodeCall(token.transferFrom, (from, to, value)));
  }

  function forceApprove(IERC20 token, address spender, uint256 value) internal {
    bytes memory approveCall = abi.encodeCall(token.approve, (spender, value));

    if (!_callWithOptionalReturnCheck(token, approveCall)) {
      _revertOnFailure(token, abi.encodeCall(token.approve, (spender, 0)));
      _revertOnFailure(token, approveCall);
    }
  }

  function _callWithOptionalReturnCheck(
    IERC20 token,
    bytes memory encodedCall
  ) private returns (bool success) {
    /// @solidity memory-safe-assembly
    assembly {
      mstore(SCRATCH_SPACE_PTR, 0)
      success := call( //see https://www.evm.codes/?fork=cancun#f1
        gas(),                       //gas
        token,                       //callee
        0,                           //value
        add(encodedCall, WORD_SIZE), //input ptr
        mload(encodedCall),          //input size
        SCRATCH_SPACE_PTR,           //output ptr
        WORD_SIZE                    //output size
      )
      //calls to addresses without code are always successful
      if success {
        success := or(iszero(returndatasize()), mload(SCRATCH_SPACE_PTR))
      }
    }
  }

  function _revertOnFailure(IERC20 token, bytes memory encodedCall) private {
    if (!_callWithOptionalReturnCheck(token, encodedCall))
      revert SafeERC20FailedOperation(address(token));
  }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)

pragma solidity ^0.8.20;

/**
 * @dev Helper library for emitting standardized panic codes.
 *
 * ```solidity
 * contract Example {
 *      using Panic for uint256;
 *
 *      // Use any of the declared internal constants
 *      function foo() { Panic.GENERIC.panic(); }
 *
 *      // Alternatively
 *      function foo() { Panic.panic(Panic.GENERIC); }
 * }
 * ```
 *
 * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
 *
 * _Available since v5.1._
 */
// slither-disable-next-line unused-state
library Panic {
    /// @dev generic / unspecified error
    uint256 internal constant GENERIC = 0x00;
    /// @dev used by the assert() builtin
    uint256 internal constant ASSERT = 0x01;
    /// @dev arithmetic underflow or overflow
    uint256 internal constant UNDER_OVERFLOW = 0x11;
    /// @dev division or modulo by zero
    uint256 internal constant DIVISION_BY_ZERO = 0x12;
    /// @dev enum conversion error
    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
    /// @dev invalid encoding in storage
    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
    /// @dev empty array pop
    uint256 internal constant EMPTY_ARRAY_POP = 0x31;
    /// @dev array out of bounds access
    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
    /// @dev resource error (too large allocation or too large array)
    uint256 internal constant RESOURCE_ERROR = 0x41;
    /// @dev calling invalid internal function
    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;

    /// @dev Reverts with a panic code. Recommended to use with
    /// the internal constants with predefined codes.
    function panic(uint256 code) internal pure {
        assembly ("memory-safe") {
            mstore(0x00, 0x4e487b71)
            mstore(0x20, code)
            revert(0x1c, 0x24)
        }
    }
}

File 42 of 42 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}

Settings
{
  "remappings": [
    "@makina-periphery/=lib/makina-periphery/src/",
    "@makina-core/=lib/makina-core/src/",
    "@solady/=lib/solady/src/",
    "@aave/=lib/makina-periphery/lib/aave-v3-origin/src/contracts/",
    "@balancer-labs/=lib/makina-periphery/lib/balancer-v2-monorepo/../../node_modules/@balancer-labs/",
    "@balancer-v2-interfaces/=lib/makina-periphery/lib/balancer-v2-monorepo/pkg/interfaces/contracts/",
    "@balancer-v3-interfaces/=lib/makina-periphery/lib/balancer-v3-monorepo/pkg/interfaces/contracts/",
    "@enso-weiroll/=lib/makina-core/lib/enso-weiroll/contracts/",
    "@makina-core-script/=lib/makina-periphery/lib/makina-core/script/",
    "@makina-core-test/=lib/makina-periphery/lib/makina-core/test/",
    "@morpho/=lib/makina-periphery/lib/morpho-blue/src/",
    "@openzeppelin/contracts-upgradeable/=lib/makina-periphery/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/makina-periphery/lib/openzeppelin-contracts/contracts/",
    "@wormhole/sdk/=lib/makina-core/lib/wormhole-solidity-sdk/src/",
    "IERC20/=lib/makina-core/lib/wormhole-solidity-sdk/src/interfaces/token/",
    "SafeERC20/=lib/makina-core/lib/wormhole-solidity-sdk/src/libraries/",
    "aave-v3-origin/=lib/makina-periphery/lib/aave-v3-origin/",
    "balancer-v2-monorepo/=lib/makina-periphery/lib/",
    "balancer-v3-monorepo/=lib/makina-periphery/lib/",
    "ds-test/=lib/makina-periphery/lib/aave-v3-origin/lib/forge-std/lib/ds-test/src/",
    "enso-weiroll/=lib/makina-core/lib/enso-weiroll/contracts/",
    "erc4626-tests/=lib/makina-periphery/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/makina-periphery/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "makina-core/=lib/makina-core/",
    "makina-periphery/=lib/makina-periphery/",
    "morpho-blue/=lib/makina-periphery/lib/morpho-blue/",
    "openzeppelin-contracts-upgradeable/=lib/makina-periphery/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/makina-periphery/lib/openzeppelin-contracts/",
    "solady/=lib/solady/src/",
    "solidity-utils/=lib/makina-periphery/lib/aave-v3-origin/lib/solidity-utils/",
    "wormhole-sdk/=lib/makina-core/lib/wormhole-solidity-sdk/src/",
    "wormhole-solidity-sdk/=lib/makina-core/lib/wormhole-solidity-sdk/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_hubPeripheryFactory","type":"address"},{"internalType":"address","name":"_hubCoreFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"inputs":[],"name":"CONFIG_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPLOYER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"shareTokenName","type":"string"},{"internalType":"string","name":"shareTokenSymbol","type":"string"},{"internalType":"address","name":"accountingToken","type":"address"},{"internalType":"address[]","name":"baseTokens","type":"address[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint16","name":"depositorImplemId","type":"uint16"},{"internalType":"bool","name":"depositorWhitelistStatus","type":"bool"},{"internalType":"uint16","name":"redeemerImplemId","type":"uint16"},{"internalType":"bool","name":"redeemerWhitelistStatus","type":"bool"},{"internalType":"uint256","name":"redeemerFinalizationDelay","type":"uint256"},{"internalType":"uint256","name":"redeemerMinRedeemAmount","type":"uint256"},{"internalType":"uint16","name":"feeManagerImplemId","type":"uint16"},{"components":[{"internalType":"uint256","name":"initialMgmtFeeRatePerSecond","type":"uint256"},{"internalType":"uint256","name":"initialSmFeeRatePerSecond","type":"uint256"},{"internalType":"uint256","name":"initialPerfFeeRate","type":"uint256"},{"internalType":"uint256[]","name":"initialMgmtFeeSplitBps","type":"uint256[]"},{"internalType":"address[]","name":"initialMgmtFeeReceivers","type":"address[]"},{"internalType":"uint256[]","name":"initialPerfFeeSplitBps","type":"uint256[]"},{"internalType":"address[]","name":"initialPerfFeeReceivers","type":"address[]"}],"internalType":"struct IWatermarkFeeManager.WatermarkFeeManagerInitParams","name":"feeManagerInitParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"initialCaliberStaleThreshold","type":"uint256"},{"internalType":"uint256","name":"initialMaxFixedFeeAccrualRate","type":"uint256"},{"internalType":"uint256","name":"initialMaxPerfFeeAccrualRate","type":"uint256"},{"internalType":"uint256","name":"initialFeeMintCooldown","type":"uint256"},{"internalType":"uint256","name":"initialShareLimit","type":"uint256"}],"internalType":"struct IMachineZap.MachineInitParams","name":"machineInitParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"initialPositionStaleThreshold","type":"uint256"},{"internalType":"bytes32","name":"initialAllowedInstrRoot","type":"bytes32"},{"internalType":"uint256","name":"initialTimelockDuration","type":"uint256"},{"internalType":"uint256","name":"initialMaxPositionIncreaseLossBps","type":"uint256"},{"internalType":"uint256","name":"initialMaxPositionDecreaseLossBps","type":"uint256"},{"internalType":"uint256","name":"initialMaxSwapLossBps","type":"uint256"},{"internalType":"uint256","name":"initialCooldownDuration","type":"uint256"}],"internalType":"struct ICaliber.CaliberInitParams","name":"caliberInitParams","type":"tuple"},{"components":[{"internalType":"address","name":"initialMechanic","type":"address"},{"internalType":"address","name":"initialSecurityCouncil","type":"address"},{"internalType":"address","name":"initialRiskManager","type":"address"},{"internalType":"address","name":"initialRiskManagerTimelock","type":"address"},{"internalType":"address","name":"initialAuthority","type":"address"}],"internalType":"struct IMakinaGovernable.MakinaGovernableInitParams","name":"mgInitParams","type":"tuple"}],"name":"createMachine","outputs":[{"internalType":"address","name":"machine","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hubCoreFactory","outputs":[{"internalType":"contract IHubCoreFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hubPeripheryFactory","outputs":[{"internalType":"contract IHubPeripheryFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_hubCoreFactory","type":"address"}],"name":"setHubCoreFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_hubPeripheryFactory","type":"address"}],"name":"setHubPeripheryFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]

60803460b757601f61105c38819003918201601f19168301916001600160401b0383118484101760bb57808492604094855283398101031260b757604b602060458360cf565b920160cf565b5f80546001600160a01b03199081166001600160a01b03948516178255600180549091169390921692909217905533638b78c6d819819055907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3604051610f7990816100e38239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b038216820360b75756fe60806040526004361015610011575f80fd5b5f3560e01c80631346d50914610504578063183a4f6e146104ec5780631c10893f1461048c5780631cd64df414610453578063256929621461040a5780632de94807146103d85780634a4ee7b1146103b0578063514e62fc1461037857806354d1f13d14610334578063715018a6146102eb5780638da5cb5b146102bf578063957348b01461027c578063a4d19feb14610261578063aae496fc1461023a578063b683b768146101f8578063e23c47ab146101d0578063ecd00261146101b5578063f04e283e14610168578063f2fde38b1461012b5763fee81cf4146100f5575f80fd5b346101275760203660031901126101275761010e610d4d565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b60203660031901126101275761013f610d4d565b610147610eb2565b8060601b1561015b5761015990610ec1565b005b637448fbae5f526004601cfd5b60203660031901126101275761017c610d4d565b610184610eb2565b63389a75e1600c52805f526020600c2090815442116101a8575f6101599255610ec1565b636f5e88185f526004601cfd5b34610127575f36600319011261012757602060405160028152f35b34610127575f366003190112610127576001546040516001600160a01b039091168152602090f35b3461012757602036600319011261012757610211610d4d565b610219610e97565b5f80546001600160a01b0319166001600160a01b0392909216919091179055005b34610127575f366003190112610127575f546040516001600160a01b039091168152602090f35b34610127575f36600319011261012757602060405160048152f35b3461012757602036600319011261012757610295610d4d565b61029d610e97565b600180546001600160a01b0319166001600160a01b0392909216919091179055005b34610127575f36600319011261012757638b78c6d819546040516001600160a01b039091168152602090f35b5f366003190112610127576102fe610eb2565b5f638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35f638b78c6d81955005b5f3660031901126101275763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b3461012757604036600319011261012757610391610d4d565b638b78c6d8600c525f52602060243581600c2054161515604051908152f35b6040366003190112610127576101596103c7610d4d565b6103cf610eb2565b60243590610efe565b34610127576020366003190112610127576103f1610d4d565b638b78c6d8600c525f52602080600c2054604051908152f35b5f3660031901126101275763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b3461012757604036600319011261012757602061046e610d4d565b60243590638b78c6d8600c525f528082600c20541614604051908152f35b6040366003190112610127576104a0610d4d565b6104a8610eb2565b638b78c6d8600c525f526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b60203660031901126101275761015960043533610efe565b34610127576103c03660031901126101275760043567ffffffffffffffff811161012757610536903690600401610d1f565b60243567ffffffffffffffff811161012757610556903690600401610d1f565b90929091906044356001600160a01b03811681036101275767ffffffffffffffff60643511610127573660236064350112156101275767ffffffffffffffff6064356004013511610127573660246064356004013560051b6064350101116101275760a4359461ffff861686036101275760c4359586151587036101275760e43561ffff81168103610127576101043590811515820361012757610164359261ffff841684036101275767ffffffffffffffff61018435116101275760e061018435360360031901126101275760a0366101a31901126101275760e0366102431901126101275760a03661032319011261012757610120604052610324356001600160a01b038116810361012757608052610344356001600160a01b03811681036101275760a052610364356001600160a01b03811681036101275760c052610384356001600160a01b03811681036101275760e0526103a4356001600160a01b0381168103610127576080800152638b78c6d8600c52335f5260026020600c20541615610d04575b6107269960209160018060a01b035f54169060405192151584840152838352610709604084610d63565b5f604051809e81958294634b8c20af60e01b845260048401610da4565b03925af1988915610b9e575f99610cda575b50610794929160209160018060a01b035f5416906040519261012435858501526101443560408501521515606084015260608352610777608084610d63565b5f60405180978195829463e987b82760e01b845260048401610da4565b03925af1908115610b9e576108c4925f92610cb8575b5060209060018060a01b035f54166040519183808401526101843560040135604084015260246101843501356060840152604461018435013560808401526108a78361089961087061084861082061080e6064610184350161018435600401610dda565b60e060a0880152610120870191610e0f565b6108366084610184350161018435600401610dda565b868303603f190160c088015290610e33565b61085e60a4610184350161018435600401610dda565b858303603f190160e087015290610e0f565b61088660c4610184350161018435600401610dda565b848303603f190161010086015290610e33565b03601f198101855284610d63565b5f604051809781958294633361cf7160e01b845260048401610da4565b03925af1918215610b9e575f92610c97575b5060c0805160e0805130938490529290526001546040516001600160a01b039384169b9284169a919093169590610100840167ffffffffffffffff811185821017610c835760209960e0975f97610acc96610ab99460405260018060a01b0316885260018060a01b03168c88015260018060a01b031660408701526101a43560608701526101c43560808701526101e43560a08701526102043560c087015261022435888701526040519b8c9a898c9a9863bc5d11c98c9a1b8a5260018060a01b0381511660048b015260018060a01b038f8201511660248b015260018060a01b0360408201511660448b0152606081015160648b0152608081015160848b015260a081015160a48b015260c081015160c48b0152015160e48901526102443561010489015261026435610124890152610284356101448901526102a4356101648901526102c4356101848901526102e4356101a4890152610304356101c489015260018060a01b03608051166101e489015260018060a01b038d608001511661020489015260018060a01b036040608001511661022489015260018060a01b036060608001511661024489015260018060a01b0360808001511661026489015260018060a01b03166102848801526103006102a4880152610304870191610e77565b848103600319016102c486015291610e77565b6084356102e483015203925af1908115610b9e575f91610c64575b50604051630694823160e31b81526001600160a01b03919091169290602081600481875afa908115610b9e575f91610c35575b506001600160a01b0316925f5b60643560040135811015610ba9576024600582901b6064350101356001600160a01b038116919082900361012757853b1561012757604051916383e280d960e01b835260048301525f82602481838a5af1918215610b9e57600192610b8e575b5001610b27565b5f610b9891610d63565b86610b87565b6040513d5f823e3d90fd5b5082813b156101275760405190630316542360e51b825260048201525f8160248183865af18015610b9e57610c25575b50803b156101275760405191634ccc3df160e01b835260048301525f8260248183855af1918215610b9e57602092610c15575b50604051908152f35b5f610c1f91610d63565b82610c0c565b5f610c2f91610d63565b82610bd9565b610c57915060203d602011610c5d575b610c4f8183610d63565b810190610d85565b84610b1a565b503d610c45565b610c7d915060203d602011610c5d57610c4f8183610d63565b83610ae7565b634e487b7160e01b5f52604160045260245ffd5b610cb191925060203d602011610c5d57610c4f8183610d63565b90886108d6565b6020919250610cd390823d8411610c5d57610c4f8183610d63565b91906107aa565b602091995091610cfa6107949493833d8511610c5d57610c4f8183610d63565b9991509192610738565b638b78c6d8195433146106df575b6382b429005f526004601cfd5b9181601f840112156101275782359167ffffffffffffffff8311610127576020838186019501011161012757565b600435906001600160a01b038216820361012757565b90601f8019910116810190811067ffffffffffffffff821117610c8357604052565b9081602091031261012757516001600160a01b03811681036101275790565b9060609261ffff6020921683526040828401528051918291826040860152018484015e5f828201840152601f01601f1916010190565b9035601e198236030181121561012757016020813591019167ffffffffffffffff8211610127578160051b3603831361012757565b81835290916001600160fb1b0383116101275760209260051b809284830137010190565b916020908281520191905f905b808210610e4d5750505090565b90919283359060018060a01b03821680920361012757602081600193829352019401920190610e40565b908060209392818452848401375f828201840152601f01601f1916010190565b638b78c6d8600c52335f5260046020600c20541615610eb257565b638b78c6d819543303610d1257565b60018060a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3638b78c6d81955565b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a356fea2646970667358221220eba376283f7e0277aa0d90b63d439d3492f6f01f26619c6a07df34c745a149b264736f6c634300081c00330000000000000000000000009b4e525f665709c4ee31da676b83d824d3b34d6c0000000000000000000000004bad075188d11f513497a28aca6f6dcfee293bb5

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c80631346d50914610504578063183a4f6e146104ec5780631c10893f1461048c5780631cd64df414610453578063256929621461040a5780632de94807146103d85780634a4ee7b1146103b0578063514e62fc1461037857806354d1f13d14610334578063715018a6146102eb5780638da5cb5b146102bf578063957348b01461027c578063a4d19feb14610261578063aae496fc1461023a578063b683b768146101f8578063e23c47ab146101d0578063ecd00261146101b5578063f04e283e14610168578063f2fde38b1461012b5763fee81cf4146100f5575f80fd5b346101275760203660031901126101275761010e610d4d565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b60203660031901126101275761013f610d4d565b610147610eb2565b8060601b1561015b5761015990610ec1565b005b637448fbae5f526004601cfd5b60203660031901126101275761017c610d4d565b610184610eb2565b63389a75e1600c52805f526020600c2090815442116101a8575f6101599255610ec1565b636f5e88185f526004601cfd5b34610127575f36600319011261012757602060405160028152f35b34610127575f366003190112610127576001546040516001600160a01b039091168152602090f35b3461012757602036600319011261012757610211610d4d565b610219610e97565b5f80546001600160a01b0319166001600160a01b0392909216919091179055005b34610127575f366003190112610127575f546040516001600160a01b039091168152602090f35b34610127575f36600319011261012757602060405160048152f35b3461012757602036600319011261012757610295610d4d565b61029d610e97565b600180546001600160a01b0319166001600160a01b0392909216919091179055005b34610127575f36600319011261012757638b78c6d819546040516001600160a01b039091168152602090f35b5f366003190112610127576102fe610eb2565b5f638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35f638b78c6d81955005b5f3660031901126101275763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b3461012757604036600319011261012757610391610d4d565b638b78c6d8600c525f52602060243581600c2054161515604051908152f35b6040366003190112610127576101596103c7610d4d565b6103cf610eb2565b60243590610efe565b34610127576020366003190112610127576103f1610d4d565b638b78c6d8600c525f52602080600c2054604051908152f35b5f3660031901126101275763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b3461012757604036600319011261012757602061046e610d4d565b60243590638b78c6d8600c525f528082600c20541614604051908152f35b6040366003190112610127576104a0610d4d565b6104a8610eb2565b638b78c6d8600c525f526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b60203660031901126101275761015960043533610efe565b34610127576103c03660031901126101275760043567ffffffffffffffff811161012757610536903690600401610d1f565b60243567ffffffffffffffff811161012757610556903690600401610d1f565b90929091906044356001600160a01b03811681036101275767ffffffffffffffff60643511610127573660236064350112156101275767ffffffffffffffff6064356004013511610127573660246064356004013560051b6064350101116101275760a4359461ffff861686036101275760c4359586151587036101275760e43561ffff81168103610127576101043590811515820361012757610164359261ffff841684036101275767ffffffffffffffff61018435116101275760e061018435360360031901126101275760a0366101a31901126101275760e0366102431901126101275760a03661032319011261012757610120604052610324356001600160a01b038116810361012757608052610344356001600160a01b03811681036101275760a052610364356001600160a01b03811681036101275760c052610384356001600160a01b03811681036101275760e0526103a4356001600160a01b0381168103610127576080800152638b78c6d8600c52335f5260026020600c20541615610d04575b6107269960209160018060a01b035f54169060405192151584840152838352610709604084610d63565b5f604051809e81958294634b8c20af60e01b845260048401610da4565b03925af1988915610b9e575f99610cda575b50610794929160209160018060a01b035f5416906040519261012435858501526101443560408501521515606084015260608352610777608084610d63565b5f60405180978195829463e987b82760e01b845260048401610da4565b03925af1908115610b9e576108c4925f92610cb8575b5060209060018060a01b035f54166040519183808401526101843560040135604084015260246101843501356060840152604461018435013560808401526108a78361089961087061084861082061080e6064610184350161018435600401610dda565b60e060a0880152610120870191610e0f565b6108366084610184350161018435600401610dda565b868303603f190160c088015290610e33565b61085e60a4610184350161018435600401610dda565b858303603f190160e087015290610e0f565b61088660c4610184350161018435600401610dda565b848303603f190161010086015290610e33565b03601f198101855284610d63565b5f604051809781958294633361cf7160e01b845260048401610da4565b03925af1918215610b9e575f92610c97575b5060c0805160e0805130938490529290526001546040516001600160a01b039384169b9284169a919093169590610100840167ffffffffffffffff811185821017610c835760209960e0975f97610acc96610ab99460405260018060a01b0316885260018060a01b03168c88015260018060a01b031660408701526101a43560608701526101c43560808701526101e43560a08701526102043560c087015261022435888701526040519b8c9a898c9a9863bc5d11c98c9a1b8a5260018060a01b0381511660048b015260018060a01b038f8201511660248b015260018060a01b0360408201511660448b0152606081015160648b0152608081015160848b015260a081015160a48b015260c081015160c48b0152015160e48901526102443561010489015261026435610124890152610284356101448901526102a4356101648901526102c4356101848901526102e4356101a4890152610304356101c489015260018060a01b03608051166101e489015260018060a01b038d608001511661020489015260018060a01b036040608001511661022489015260018060a01b036060608001511661024489015260018060a01b0360808001511661026489015260018060a01b03166102848801526103006102a4880152610304870191610e77565b848103600319016102c486015291610e77565b6084356102e483015203925af1908115610b9e575f91610c64575b50604051630694823160e31b81526001600160a01b03919091169290602081600481875afa908115610b9e575f91610c35575b506001600160a01b0316925f5b60643560040135811015610ba9576024600582901b6064350101356001600160a01b038116919082900361012757853b1561012757604051916383e280d960e01b835260048301525f82602481838a5af1918215610b9e57600192610b8e575b5001610b27565b5f610b9891610d63565b86610b87565b6040513d5f823e3d90fd5b5082813b156101275760405190630316542360e51b825260048201525f8160248183865af18015610b9e57610c25575b50803b156101275760405191634ccc3df160e01b835260048301525f8260248183855af1918215610b9e57602092610c15575b50604051908152f35b5f610c1f91610d63565b82610c0c565b5f610c2f91610d63565b82610bd9565b610c57915060203d602011610c5d575b610c4f8183610d63565b810190610d85565b84610b1a565b503d610c45565b610c7d915060203d602011610c5d57610c4f8183610d63565b83610ae7565b634e487b7160e01b5f52604160045260245ffd5b610cb191925060203d602011610c5d57610c4f8183610d63565b90886108d6565b6020919250610cd390823d8411610c5d57610c4f8183610d63565b91906107aa565b602091995091610cfa6107949493833d8511610c5d57610c4f8183610d63565b9991509192610738565b638b78c6d8195433146106df575b6382b429005f526004601cfd5b9181601f840112156101275782359167ffffffffffffffff8311610127576020838186019501011161012757565b600435906001600160a01b038216820361012757565b90601f8019910116810190811067ffffffffffffffff821117610c8357604052565b9081602091031261012757516001600160a01b03811681036101275790565b9060609261ffff6020921683526040828401528051918291826040860152018484015e5f828201840152601f01601f1916010190565b9035601e198236030181121561012757016020813591019167ffffffffffffffff8211610127578160051b3603831361012757565b81835290916001600160fb1b0383116101275760209260051b809284830137010190565b916020908281520191905f905b808210610e4d5750505090565b90919283359060018060a01b03821680920361012757602081600193829352019401920190610e40565b908060209392818452848401375f828201840152601f01601f1916010190565b638b78c6d8600c52335f5260046020600c20541615610eb257565b638b78c6d819543303610d1257565b60018060a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3638b78c6d81955565b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a356fea2646970667358221220eba376283f7e0277aa0d90b63d439d3492f6f01f26619c6a07df34c745a149b264736f6c634300081c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000009b4e525f665709c4ee31da676b83d824d3b34d6c0000000000000000000000004bad075188d11f513497a28aca6f6dcfee293bb5

-----Decoded View---------------
Arg [0] : _hubPeripheryFactory (address): 0x9b4e525f665709C4Ee31DA676B83D824D3b34D6C
Arg [1] : _hubCoreFactory (address): 0x4bAD075188d11f513497A28AcA6f6DcfEE293BB5

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000009b4e525f665709c4ee31da676b83d824d3b34d6c
Arg [1] : 0000000000000000000000004bad075188d11f513497a28aca6f6dcfee293bb5


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.