APE Price: $0.73 (+3.29%)

Contract

0x0E00009d00d1000069ed00A908e00081F5006008

Overview

APE Balance

Apechain LogoApechain LogoApechain Logo0 APE

APE Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

2 Internal Transactions found.

Latest 2 internal transactions

Parent Transaction Hash Block From To
76584702025-01-06 19:54:3635 days ago1736193276
0x0E00009d...1F5006008
 Contract Creation0 APE
76584702025-01-06 19:54:3635 days ago1736193276  Contract Creation0 APE

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TokenMasterRouter

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 9999999 runs

Other Settings:
cancun EvmVersion, None license
File 1 of 35 : TokenMasterRouter.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

import "./Constants.sol";
import "./DataTypes.sol";
import "./Errors.sol";
import "./interfaces/ITokenMasterRouter.sol";
import "./interfaces/ITokenMasterFactory.sol";
import "./interfaces/ITokenMasterOracle.sol";
import "./interfaces/ITokenMasterBuyHook.sol";
import "./interfaces/ITokenMasterSellHook.sol";
import "./interfaces/ITokenMasterSpendHook.sol";
import "./interfaces/ITokenMasterERC20C.sol";
import "./libraries/LibOwnership.sol";
import "@limitbreak/tm-core-lib/src/utils/security/RoleSetClient.sol";
import "@limitbreak/tm-core-lib/src/utils/structs/EnumerableSet.sol";
import "@limitbreak/tm-core-lib/src/utils/cryptography/EfficientHash.sol";
import "@limitbreak/tm-core-lib/src/utils/security/TstorishReentrancyGuard.sol";
import "@limitbreak/permit-c/openzeppelin-optimized/EIP712.sol";
import "@limitbreak/tm-core-lib/src/token/erc20/utils/SafeERC20.sol";
import "@limitbreak/tm-core-lib/src/token/erc20/IERC20.sol";
import "@limitbreak/permit-c/interfaces/IPermitC.sol";
import "@limitbreak/trusted-forwarder/TrustedForwarderERC2771Context.sol";
import "@limitbreak/tm-core-lib/src/licenses/LicenseRef-PolyForm-Strict-1.0.0.sol";

/**
 * @title  TokenMasterRouter
 * @author Limit Break, Inc.
 * @notice The TokenMasterRouter contract is designed to deploy, manage and transact with ERC20C tokens that 
 *         are paired with another asset.
 * 
 * @dev    <h4>Features</h4>
 *         - Deployment of ERC20C tokens.
 *         - Creator controls for token pairing.
 *         - Buy, sell and spend tokens created through TokenMasterRouter.
 *         - Advanced order hooks for buying, selling and spending tokens.
 *         - Oracle adjustments for advanced order cost thresholds.
 * 
 * @dev    <h4>Details</h4>
 *         Pairing Restrictions:
 *         TokenMasterRouter gives ERC20C token creators the ability to enforce pairing restrictions for their
 *         tokens with the ability to restrict new pair deployments to originating from a creator's Trusted Forwarder
 *         which allows the creator to sign off on the specific deployment parameters, restrict pairing to only tokens
 *         deployed by the creator, restrict what deployers may deploy a new pair, and restrict to specific token 
 *         addresses being deployed using the new token's deterministic deployment address.
 *         
 *         By default, any ERC20 token that has not restricted its pairing will be eligible to be used as a paired
 *         token.
 * 
 *         Tokens launched through TokenMasterRouter can be restricted to only trade through authorized 
 *         Trusted Forwarders for order attribution, permissioning and analytics.
 * 
 *         For the security of ERC20C tokens that whitelist TokenMasterRouter, transactions executing through 
 *         TokenMasterRouter must be from pairs that were deployed by TokenMasterRouter and the factory used for
 *         deployment must be an allowed factory set by the `TOKENMASTER_ADMIN_ROLE`.
 * 
 *         Buy / Sell / Spend Tokens:
 *         Tokens deployed through TokenMasterRouter are special ERC20C token contracts that are paired with 
 *         another token. Allowed factories may deploy pools with different mechanics - for example, one factory's
 *         tokens may have a fluctuating price based on buying and selling while another factory is fully stable.
 *         Buys will exchange a quantity of the paired token for the token being purchased, sells will exchange 
 *         the token for the paired token, and spends remove tokens from the spender's account with an event 
 *         emission for offchain actions by the creator and/or an onchain hook being executed.
 * 
 *         Advanced orders must be signed by an account that is authorized by the creator as an order signer.
 *         Advanced buys and sells execute an onchain hook, spends may execute an onchain hook but also emit an
 *         event the creator can utilize for offchain purposes. Advanced transactions include a `hookExtraData`
 *         parameter to provide additional data to the hook contract that is called.
 * 
 *         Oracles: 
 *         Advanced orders may include an oracle contract address that adjusts the token cost of an order
 *         based on any factor that is relevant to the transaction being executed. The `oracleExtraData`
 *         parameter can be used provide additional data to the oracle contract that is called.
 */
contract TokenMasterRouter is ITokenMasterRouter, RoleSetClient, TrustedForwarderERC2771Context, EIP712, TstorishReentrancyGuard {
    using EnumerableSet for EnumerableSet.AddressSet;
    
    /// @dev Current infrastructure fee that will be included in newly deployed tokens.
    uint16 public infrastructureFeeBPS;
    /// @dev Mapping of allowed token factories, set by the TokenMaster Admin
    mapping (address => bool) public allowedTokenFactory;
    /// @dev Mapping of token settings set by the token owner or admin.
    mapping (address => TokenSettings) private tokenSettings;
    /// @dev Mapping of advanced order data to track amounts and status.
    mapping (bytes32 => OrderTracking) public orderTracking;

    /// @dev Role for the TokenMaster Admin in the Role Server.
    bytes32 private immutable TOKENMASTER_ADMIN_ROLE;
    /// @dev Role for the TokenMaster Deployment Signer in the Role Server.
    bytes32 private immutable TOKENMASTER_SIGNER_ROLE;
    /// @dev Role for the TokenMaster Fee Receiver in the Role Server.
    bytes32 private immutable TOKENMASTER_FEE_RECEIVER_ROLE;
    /// @dev Role for the TokenMaster Fee Collector in the Role Server.
    bytes32 private immutable TOKENMASTER_FEE_COLLECTOR_ROLE;

    modifier onlyAdminAuthority() {
        if (msg.sender != _getRoleHolder(TOKENMASTER_ADMIN_ROLE)) {
            revert TokenMasterRouter__CallerNotAllowed();
        }
        _;
    }

    constructor(
        address roleServer,
        bytes32 roleSet,
        address trustedForwarderFactory
    )
        RoleSetClient(roleServer, roleSet)
        TrustedForwarderERC2771Context(trustedForwarderFactory) 
        EIP712("TokenMasterRouter", "1") {

        TOKENMASTER_ADMIN_ROLE = _hashRoleSetRole(roleSet, TOKENMASTER_ADMIN_BASE_ROLE);
        TOKENMASTER_SIGNER_ROLE = _hashRoleSetRole(roleSet, TOKENMASTER_SIGNER_BASE_ROLE);
        TOKENMASTER_FEE_RECEIVER_ROLE = _hashRoleSetRole(roleSet, TOKENMASTER_FEE_RECEIVER_BASE_ROLE);
        TOKENMASTER_FEE_COLLECTOR_ROLE = _hashRoleSetRole(roleSet, TOKENMASTER_FEE_COLLECTOR_BASE_ROLE);
    }

    /**
     * @dev  Initializes role configuration during TokenMasterRouter deployment.
     */
    function _setupRoles(bytes32 roleSet) internal override {
        _setupRole(_hashRoleSetRole(roleSet, TOKENMASTER_ADMIN_BASE_ROLE), 0);
        _setupRole(_hashRoleSetRole(roleSet, TOKENMASTER_SIGNER_BASE_ROLE), 0);
        _setupRole(_hashRoleSetRole(roleSet, TOKENMASTER_FEE_RECEIVER_BASE_ROLE), 1 hours);
        _setupRole(_hashRoleSetRole(roleSet, TOKENMASTER_FEE_COLLECTOR_BASE_ROLE), 24 hours);
    }

    /*************************************************************************/
    /*                     BUY / SELL / SPEND FUNCTIONS                      */
    /*************************************************************************/

    /**
     * @notice  Executes a buy order for a token deployed through TokenMaster.
     * 
     * @dev     Throws when reentering the TokenMasterRouter contract before a prior call ends.
     * @dev     Throws when the calldata length does not match the expected length.
     * @dev     Throws when the token being purchased was not deployed through TokenMaster.
     * @dev     Throws when the token is configured to block transactions from untrusted
     * @dev     channels and the caller is not a trusted channel.
     * @dev     Throws when native value is sent for a token that is paired with an ERC20.
     * @dev     Throws when an ERC20 paired token fails to transfer to the token contract.
     * @dev     Throws when a refund is required by the router and the refund transfer fails.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. Paired value is transferred from the buyer to the token contract.
     * @dev    2. Tokens are minted to the buyer.
     * @dev    3. A `BuyOrderFilled` event has been emitted.
     * 
     * @param  buyOrder  Basic buy order details.
     */
    function buyTokens(BuyOrder calldata buyOrder) external payable nonReentrant {
        address executor = _getExecutor(BASE_MSG_LENGTH_BUY_ORDER);

        (
            ITokenMasterERC20C tokenMasterToken,
        ) = _validateTokenSettingsForTransaction(buyOrder.tokenMasterToken);
        address pairedToken = tokenMasterToken.PAIRED_TOKEN();
        uint256 pairedValueIn = _transferPairedValueToPool(pairedToken, address(tokenMasterToken), executor, buyOrder.pairedValueIn);

        _executeBuy(tokenMasterToken, executor, pairedValueIn, buyOrder.tokensToBuy, pairedToken);
    }

    /**
     * @notice  Executes an advanced buy order for a token deployed through TokenMaster.
     * 
     * @dev     Throws when reentering the TokenMasterRouter contract before a prior call ends.
     * @dev     Throws when the calldata length does not match the expected length.
     * @dev     Throws when the token being purchased was not deployed through TokenMaster.
     * @dev     Throws when the token is configured to block transactions from untrusted
     * @dev     channels and the caller is not a trusted channel.
     * @dev     Throws when native value is sent for a token that is paired with an ERC20.
     * @dev     Throws when an ERC20 paired token fails to transfer to the token contract.
     * @dev     Throws when a refund is required by the router and the refund transfer fails.
     * @dev     If the advanced buy includes an advanced order -
     * @dev         Throws when the order has expired.
     * @dev         Throws when the order is not signed by an authorized signer.
     * @dev         Throws when a cosigner is specified and the cosignature is invalid.
     * @dev         Throws when the buy amount does not meet the order minimum.
     * @dev         Throws when the order has been disabled.
     * @dev         Throws when the order has a maximum total and the buy will exceed it.
     * @dev         Throws when the order has a maximum per wallet and the buy will exceed it.
     * @dev         Throws when the hook call reverts.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. Paired value is transferred from the buyer to the token contract.
     * @dev    2. Tokens are minted to the buyer.
     * @dev    3. A `BuyOrderFilled` event has been emitted.
     * @dev    4. Buy hook is called if the advanced buy includes an advanced order.
     * 
     * @param  buyOrder        Basic buy order details.
     * @param  signedOrder     Advanced order details and signatures.
     * @param  permitTransfer  Permit transfer details if executing a permit transfer.
     */
    function buyTokensAdvanced(
        BuyOrder calldata buyOrder,
        SignedOrder calldata signedOrder,
        PermitTransfer calldata permitTransfer
    ) external payable nonReentrant {
        address executor = _getExecutor(
            _addAdjustedBytesLength(
                _addAdjustedBytesLength(
                    _addAdjustedBytesLength(
                        BASE_MSG_LENGTH_BUY_ORDER_ADVANCED,
                        permitTransfer.signedPermit.length
                    ),
                    signedOrder.oracleExtraData.length
                ),
                signedOrder.hookExtraData.length
            )
        );

        (
            ITokenMasterERC20C tokenMasterToken,
            TokenSettings storage settings
        ) = _validateTokenSettingsForTransaction(buyOrder.tokenMasterToken);
        address pairedToken = tokenMasterToken.PAIRED_TOKEN();

        uint256 pairedValueIn;
        if (permitTransfer.permitProcessor == address(0)) {
            pairedValueIn = _transferPairedValueToPool(pairedToken, address(tokenMasterToken), executor, buyOrder.pairedValueIn); 
        } else {
            pairedValueIn = _permitTransferTokensToBuy(
                executor,
                pairedToken,
                address(tokenMasterToken),
                buyOrder,
                signedOrder,
                permitTransfer
            );
        }

        (uint256 tokensToBuy, bool executeHook) = _validateBuyParameters(
            address(tokenMasterToken),
            settings.orderSigners,
            executor,
            buyOrder.tokensToBuy,
            signedOrder
        );

        _executeBuy(tokenMasterToken, executor, pairedValueIn, tokensToBuy, pairedToken);

        if (executeHook) {
            ITokenMasterBuyHook(signedOrder.hook).tokenMasterBuyHook(
                address(tokenMasterToken),
                executor,
                signedOrder.creatorIdentifier,
                tokensToBuy,
                signedOrder.hookExtraData
            );
        }
    }

    /**
     * @notice  Executes a sell order for a token deployed through TokenMaster.
     * 
     * @dev     Throws when reentering the TokenMasterRouter contract before a prior call ends.
     * @dev     Throws when the calldata length does not match the expected length.
     * @dev     Throws when the token being sold was not deployed through TokenMaster.
     * @dev     Throws when the token is configured to block transactions from untrusted
     * @dev     channels and the caller is not a trusted channel.
     * @dev     Throws when a transfer is required by the router and the transfer fails.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. Sold tokens are burned by the token contract.
     * @dev    2. Paired tokens are transferred to the seller.
     * @dev    3. A `SellOrderFilled` event has been emitted.
     * 
     * @param  sellOrder  Basic sell order details.
     */
    function sellTokens(SellOrder calldata sellOrder) external nonReentrant {
        address executor = _getExecutor(BASE_MSG_LENGTH_SELL_ORDER);

        (
            ITokenMasterERC20C tokenMasterToken,
        ) = _validateTokenSettingsForTransaction(sellOrder.tokenMasterToken);

        _executeSell(tokenMasterToken, executor, sellOrder);
    }

    /**
     * @notice  Executes an advanced sell order for a token deployed through TokenMaster.
     * 
     * @dev     Throws when reentering the TokenMasterRouter contract before a prior call ends.
     * @dev     Throws when the calldata length does not match the expected length.
     * @dev     Throws when the token being sold was not deployed through TokenMaster.
     * @dev     Throws when the token is configured to block transactions from untrusted
     * @dev     channels and the caller is not a trusted channel.
     * @dev     Throws when a transfer is required by the router and the transfer fails.
     * @dev     Throws when the order has expired.
     * @dev     Throws when the order is not signed by an authorized signer.
     * @dev     Throws when a cosigner is specified and the cosignature is invalid.
     * @dev     Throws when the sell amount does not meet the order minimum.
     * @dev     Throws when the order has been disabled.
     * @dev     Throws when the order has a maximum total and the sell will exceed it.
     * @dev     Throws when the order has a maximum per wallet and the sell will exceed it.
     * @dev     Throws when the hook call reverts.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. Sold tokens are burned by the token contract.
     * @dev    2. Paired tokens are transferred to the seller.
     * @dev    3. A `SellOrderFilled` event has been emitted.
     * @dev    4. Sell hook is called.
     * 
     * @param  sellOrder    Basic sell order details.
     * @param  signedOrder  Advanced order details and signatures.
     */
    function sellTokensAdvanced(SellOrder calldata sellOrder, SignedOrder calldata signedOrder) external nonReentrant {
        address executor = _getExecutor(
            _addAdjustedBytesLength(
                _addAdjustedBytesLength(
                    BASE_MSG_LENGTH_SELL_ORDER_ADVANCED,
                    signedOrder.oracleExtraData.length
                ),
                signedOrder.hookExtraData.length
            )
        );
        
        (
            ITokenMasterERC20C tokenMasterToken,
            TokenSettings storage settings
        ) = _validateTokenSettingsForTransaction(sellOrder.tokenMasterToken);

        _validateSellParameters(
            address(tokenMasterToken),
            settings.orderSigners,
            executor,
            sellOrder.tokensToSell,
            signedOrder
        );

        _executeSell(tokenMasterToken, executor, sellOrder);

        ITokenMasterSellHook(signedOrder.hook).tokenMasterSellHook(
            address(tokenMasterToken),
            executor,
            signedOrder.creatorIdentifier,
            sellOrder.tokensToSell,
            signedOrder.hookExtraData
        );
    }

    /**
     * @notice  Executes a spend order for a token deployed through TokenMaster.
     * 
     * @dev     Tokens spent are calculated by the base value on the signed order, adjusted
     * @dev     by an oracle if specified by the creator, times the multiplier on the spend
     * @dev     order.
     * 
     * @dev     Throws when reentering the TokenMasterRouter contract before a prior call ends.
     * @dev     Throws when the calldata length does not match the expected length.
     * @dev     Throws when the token being spent was not deployed through TokenMaster.
     * @dev     Throws when the token is configured to block transactions from untrusted
     * @dev     channels and the caller is not a trusted channel.
     * @dev     Throws when the order has expired.
     * @dev     Throws when the order is not signed by an authorized signer.
     * @dev     Throws when a cosigner is specified and the cosignature is invalid.
     * @dev     Throws when the amount to spend exceeds the user specified maximum.
     * @dev     Throws when the order has been disabled.
     * @dev     Throws when the order has a maximum total and the sell will exceed it.
     * @dev     Throws when the order has a maximum per wallet and the sell will exceed it.
     * @dev     Throws when the hook call reverts.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. Spent tokens are burned by the token contract.
     * @dev    2. A `SpendOrderFilled` event has been emitted.
     * @dev    3. Spend hook is called, if spend order includes a hook.
     * 
     * @param  spendOrder   Basic spend details.
     * @param  signedOrder  Advanced spend details and signature.
     */
    function spendTokens(
        SpendOrder calldata spendOrder,
        SignedOrder calldata signedOrder
    ) external nonReentrant {
        address executor = _getExecutor(
            _addAdjustedBytesLength(
                _addAdjustedBytesLength(
                    BASE_MSG_LENGTH_SPEND_ORDER,
                    signedOrder.oracleExtraData.length
                ),
                signedOrder.hookExtraData.length
            )
        );

        (
            ITokenMasterERC20C tokenMasterToken,
            TokenSettings storage settings
        ) = _validateTokenSettingsForTransaction(spendOrder.tokenMasterToken);

        (uint256 amountToSpend, uint256 multiplier) = _validateSpendParameters(
            settings.orderSigners,
            executor,
            spendOrder,
            signedOrder
        );

        if (amountToSpend > spendOrder.maxAmountToSpend) {
            revert TokenMasterRouter__AmountToSpendExceedsMax();
        }

        tokenMasterToken.spendTokens(executor, amountToSpend);

        if (signedOrder.hook != address(0)) {
            ITokenMasterSpendHook(signedOrder.hook).tokenMasterSpendHook(
                address(tokenMasterToken),
                executor,
                signedOrder.creatorIdentifier,
                multiplier,
                signedOrder.hookExtraData
            );
        }

        emit SpendOrderFilled(address(tokenMasterToken), signedOrder.creatorIdentifier, executor, amountToSpend, multiplier);
    }

    /*************************************************************************/
    /*                           CREATOR FUNCTIONS                           */
    /*************************************************************************/

    /**
     * @notice  Deploys a TokenMaster token using the parameters specified by the deployer.
     * 
     * @dev     Token deployments are deterministic, the provided address in deployment 
     * @dev     parameters *MUST* match the actual deployment address from the factory.
     * 
     * @dev     Partner fee recipient may only be changed after deployment by the 
     * @dev     the current partner proposing and the token owner accepting the 
     * @dev     proposed recipient. If no partner address is specified or the recipient
     * @dev     is a contract that cannot call the proposal function then the address
     * @dev     will not be changeable in the future. 
     * 
     * @dev     Throws when the calldata length does not match the expected length.
     * @dev     Throws when the paired token is configured to block transactions from 
     * @dev     untrusted channels and the caller is not a trusted channel.
     * @dev     Throws when the paired token is configured to limit pairings to lists
     * @dev     and the deployer or deterministic address of the token being deployed
     * @dev     are not on the list.
     * @dev     Throws when the specified token factory is not allowed by TokenMaster.
     * @dev     Throws when a signing authority is configured and the provided 
     * @dev     signature is not valid.
     * @dev     Throws when the initial paired value fails to transfer to the token 
     * @dev     contract address.
     * @dev     Throws when deploying a native-backed token and the supplied value
     * @dev     is not equal to the initial pairing amount.
     * @dev     Throws when the specified maximum infrastructure fee is less than
     * @dev     the current infrastructure fee setting.
     * @dev     Throws when the actual deployed address does not match the supplied
     * @dev     token address value.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. Initial paired value is transferred to the deployed token.
     * @dev    2. The token contract is created.
     * @dev    3. The token is marked as deployed by TokenMaster and initial settings stored.
     * @dev    4. A `TokenMasterTokenDeployed` event has been emitted.
     * 
     * @param  deploymentParameters  The parameters for the token being deployed.
     * @param  signature             If a signing authority is set, the signature from 
     *                               the signing authority.
     *                               If no signing authority is set, this may be any value.
     */
    function deployToken(
        DeploymentParameters calldata deploymentParameters,
        SignatureECDSA calldata signature
    ) external payable {
        address deployer = _getExecutor(
            _addAdjustedBytesLength(
                _addAdjustedBytesLength(
                    _addAdjustedBytesLength(
                        BASE_MSG_LENGTH_DEPLOY_TOKEN,
                        bytes(deploymentParameters.poolParams.name).length
                    ),
                    bytes(deploymentParameters.poolParams.symbol).length
                ),
                deploymentParameters.poolParams.encodedInitializationArgs.length
            )
        );

        _validateTokenSettingsForDeployment(
            deployer,
            deploymentParameters.tokenAddress,
            deploymentParameters.poolParams.pairedToken
        );

        if (!allowedTokenFactory[deploymentParameters.tokenFactory]) {
            revert TokenMasterRouter__TokenFactoryNotAllowed();
        }

        address signerAuthority = _getRoleHolder(TOKENMASTER_SIGNER_ROLE);

        if (signerAuthority != address(0)) {
            _validateDeploymentSignature(deploymentParameters, signature, signerAuthority);
        }

        uint256 pairedTokenIn = _transferPairedValueToPool(
            deploymentParameters.poolParams.pairedToken,
            deploymentParameters.tokenAddress,
            deployer,
            deploymentParameters.poolParams.initialPairedTokenToDeposit
        );
        if (deploymentParameters.poolParams.pairedToken == address(0)) {
            if (msg.value != deploymentParameters.poolParams.initialPairedTokenToDeposit) {
                revert TokenMasterRouter__InvalidMessageValue();
            }
            (bool success,) = deploymentParameters.tokenAddress.call{value: msg.value}("");
            if (!success) {
                revert TokenMasterRouter__FailedToDepositInitialPairedFunds();
            }
        }

        uint16 _infrastructureFeeBPS = infrastructureFeeBPS;
        if (_infrastructureFeeBPS > deploymentParameters.maxInfrastructureFeeBPS) {
            revert TokenMasterRouter__InvalidInfrastructureFeeBPS();
        }

        address tokenMasterToken = ITokenMasterFactory(deploymentParameters.tokenFactory).deployToken(
            deploymentParameters.tokenSalt,
            deploymentParameters.poolParams,
            pairedTokenIn,
            _infrastructureFeeBPS
        );

        if (tokenMasterToken == address(0) || tokenMasterToken != deploymentParameters.tokenAddress) {
            revert TokenMasterRouter__DeployedTokenAddressMismatch();
        }

        uint8 flags = FLAG_DEPLOYED_BY_TOKENMASTER;
        if (deploymentParameters.blockTransactionsFromUntrustedChannels) {
            flags |= FLAG_BLOCK_TRANSACTIONS_FROM_UNTRUSTED_CHANNELS;
        }
        if (deploymentParameters.restrictPairingToLists) {
            flags |= FLAG_RESTRICT_PAIRING_TO_LISTS;
        }
        tokenSettings[tokenMasterToken].flags = flags;
        tokenSettings[tokenMasterToken].partnerFeeRecipient = deploymentParameters.poolParams.partnerFeeRecipient;

        emit TokenMasterTokenDeployed(tokenMasterToken, deploymentParameters.poolParams.pairedToken, deploymentParameters.tokenFactory);
    }

    /**
     * @notice  Updates settings for a token for any transaction executed on TokenMasterRouter.
     * 
     * @dev     Settings may be set for tokens that were not deployed through TokenMaster
     * @dev     so that a token owner may control pairings for their token.
     * 
     * @dev     Throws when the caller is not the token, owner or an admin for the token.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. Token settings have been updated.
     * @dev    2. A `TokenSettingsUpdated` event has been emitted.
     * 
     * @param  tokenAddress                            The address of the token to set settings for.
     * @param  blockTransactionsFromUntrustedChannels  If true, requires transactions to be executed through 
     *                                                 a trusted channel.
     * @param  restrictPairingToLists                  If true, tokens can only be deployed if the deployer or 
     *                                                 token address are on an approved list.
     */
    function updateTokenSettings(
        address tokenAddress,
        bool blockTransactionsFromUntrustedChannels,
        bool restrictPairingToLists
    ) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdmin(tokenAddress);

        TokenSettings storage settings = tokenSettings[tokenAddress];
        settings.flags = 
            _setFlag(
                _setFlag(
                    settings.flags,
                    FLAG_BLOCK_TRANSACTIONS_FROM_UNTRUSTED_CHANNELS,
                    blockTransactionsFromUntrustedChannels
                ),
                FLAG_RESTRICT_PAIRING_TO_LISTS,
                restrictPairingToLists
            );
        
        emit TokenSettingsUpdated(tokenAddress, blockTransactionsFromUntrustedChannels, restrictPairingToLists);
    }

    /**
     * @notice  Sets or removes an address as an allowed signer for advanced orders for a token.
     * 
     * @dev     Throws when the caller is not the token, owner or an admin for the token.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The signer list for the token has been updated.
     * @dev    2. A `OrderSignerUpdated` event has been emitted.
     * 
     * @param  tokenMasterToken  The address of the token to update the signer for.
     * @param  signer            The address of the account to set or remove as a signer.
     * @param  allowed           If true, adds the account as a signer. If false, removes the account.
     */
    function setOrderSigner(address tokenMasterToken, address signer, bool allowed) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdmin(tokenMasterToken);

        if (allowed) {
            if (tokenSettings[tokenMasterToken].orderSigners.add(signer)) {
                emit OrderSignerUpdated(tokenMasterToken, signer, allowed);
            }
        } else {
            if (tokenSettings[tokenMasterToken].orderSigners.remove(signer)) {
                emit OrderSignerUpdated(tokenMasterToken, signer, allowed);
            }
        }
    }

    /**
     * @notice  Sets or removes an address as a trusted channel for a token.
     * 
     * @dev     Throws when the caller is not the token, owner or an admin for the token.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The trusted channel list for the token has been updated.
     * @dev    2. A `TrustedChannelUpdated` event has been emitted.
     * 
     * @param  tokenAddress  The address of the token to update the trusted channels for.
     * @param  channel       The address of the channel to set or remove as trusted.
     * @param  allowed       If true, adds the channel as a trusted. If false, removes the channel.
     */
    function setTokenAllowedTrustedChannel(address tokenAddress, address channel, bool allowed) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdmin(tokenAddress);

        if (allowed) {
            if (tokenSettings[tokenAddress].trustedChannels.add(channel)) {
                emit TrustedChannelUpdated(tokenAddress, channel, allowed);
            }
        } else {
            if (tokenSettings[tokenAddress].trustedChannels.remove(channel)) {
                emit TrustedChannelUpdated(tokenAddress, channel, allowed);
            }
        }
    }

    /**
     * @notice  Sets or removes an address as an allowed pair deployer.
     * 
     * @dev     Allowed pair deployers are allowed to deploy a token on TokenMaster
     * @dev     that pairs to the specified token when the token has pairing restrictions
     * @dev     enabled.
     * 
     * @dev     Throws when the caller is not the token, owner or an admin for the token.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The allowed pair to deployer list for the token has been updated.
     * @dev    2. A `AllowedPairToDeployersUpdated` event has been emitted.
     * 
     * @param  tokenAddress  The address of the token to update the allowed pair deployers for.
     * @param  deployer      The address of the deployer to set or remove as allowed.
     * @param  allowed       If true, adds the deployer as a allowed. If false, removes the deployer.
     */
    function setTokenAllowedPairToDeployer(address tokenAddress, address deployer, bool allowed) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdmin(tokenAddress);

        if (allowed) {
            if (tokenSettings[tokenAddress].allowedPairToDeployers.add(deployer)) {
                emit AllowedPairToDeployersUpdated(tokenAddress, deployer, allowed);
            }
        } else {
            if (tokenSettings[tokenAddress].allowedPairToDeployers.remove(deployer)) {
                emit AllowedPairToDeployersUpdated(tokenAddress, deployer, allowed);
            }
        }
    }

    /**
     * @notice  Sets or removes an address as an allowed pair token.
     * 
     * @dev     Allowed pair tokens are specific token addresses that are allowed to be 
     * @dev     with the specified token as the paired token. Token deployments in 
     * @dev     TokenMaster are deterministic so all of the settings may be validated
     * @dev     and the address precomputed to add as an allowed pair to token before
     * @dev     the token is deployed.
     * 
     * @dev     Throws when the caller is not the token, owner or an admin for the token.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The allowed pair to token list for the token has been updated.
     * @dev    2. A `AllowedPairToTokensUpdated` event has been emitted.
     * 
     * @param  tokenAddress        The address of the token to update the allowed pair tokens for.
     * @param  tokenAllowedToPair  The address of the token to set or remove as allowed.
     * @param  allowed             If true, adds the token as a allowed. If false, removes the token.
     */
    function setTokenAllowedPairToToken(address tokenAddress, address tokenAllowedToPair, bool allowed) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdmin(tokenAddress);

        if (allowed) {
            if (tokenSettings[tokenAddress].allowedPairToTokens.add(tokenAllowedToPair)) {
                emit AllowedPairToTokensUpdated(tokenAddress, tokenAllowedToPair, allowed);
            }
        } else {
            if (tokenSettings[tokenAddress].allowedPairToTokens.remove(tokenAllowedToPair)) {
                emit AllowedPairToTokensUpdated(tokenAddress, tokenAllowedToPair, allowed);
            }
        }
    }

    /**
     * @notice  Disables or re-enables a specific advanced buy order.
     *  
     * @dev     Throws when the caller is not the token, owner, an admin, or
     * @dev     order manager role holder for the token.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The specified order has been disabled or re-enabled.
     * @dev    2. A `BuyOrderDisabled` event has been emitted.
     * 
     * @param  tokenMasterToken  The address of the token to disable or re-enable the advanced order for.
     * @param  signedOrder       The advanced order details.
     * @param  disabled          If true, the order is disabled. If false, the order is re-enabled.
     */
    function disableBuyOrder(address tokenMasterToken, SignedOrder calldata signedOrder, bool disabled) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdminOrRole(
            tokenMasterToken,
            ORDER_MANAGER_ROLE
        );

        bytes32 buyOrderHash = _hashSignedOrder(BUY_TYPEHASH, tokenMasterToken, signedOrder);
        
        orderTracking[buyOrderHash].orderDisabled = disabled;
        emit BuyOrderDisabled(tokenMasterToken, signedOrder.creatorIdentifier, disabled);
    }

    /**
     * @notice  Disables or re-enables a specific advanced sell order.
     *  
     * @dev     Throws when the caller is not the token, owner, an admin, or
     * @dev     order manager role holder for the token.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The specified order has been disabled or re-enabled.
     * @dev    2. A `SellOrderDisabled` event has been emitted.
     * 
     * @param  tokenMasterToken  The address of the token to disable or re-enable the advanced order for.
     * @param  signedOrder       The advanced order details.
     * @param  disabled          If true, the order is disabled. If false, the order is re-enabled.
     */
    function disableSellOrder(address tokenMasterToken, SignedOrder calldata signedOrder, bool disabled) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdminOrRole(
            tokenMasterToken,
            ORDER_MANAGER_ROLE
        );

        bytes32 sellOrderHash = _hashSignedOrder(SELL_TYPEHASH, tokenMasterToken, signedOrder);
        
        orderTracking[sellOrderHash].orderDisabled = disabled;
        emit SellOrderDisabled(tokenMasterToken, signedOrder.creatorIdentifier, disabled);
    }

    /**
     * @notice  Disables or re-enables a specific spend order.
     *  
     * @dev     Throws when the caller is not the token, owner, an admin, or
     * @dev     order manager role holder for the token.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The specified order has been disabled or re-enabled.
     * @dev    2. A `SpendOrderDisabled` event has been emitted.
     * 
     * @param  tokenMasterToken  The address of the token to disable or re-enable the advanced order for.
     * @param  signedOrder       The advanced order details.
     * @param  disabled          If true, the order is disabled. If false, the order is re-enabled.
     */
    function disableSpendOrder(address tokenMasterToken, SignedOrder calldata signedOrder, bool disabled) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdminOrRole(
            tokenMasterToken,
            ORDER_MANAGER_ROLE
        );

        bytes32 spendOrderHash = _hashSignedOrder(SPEND_TYPEHASH, tokenMasterToken, signedOrder);
        
        orderTracking[spendOrderHash].orderDisabled = disabled;
        emit SpendOrderDisabled(tokenMasterToken, signedOrder.creatorIdentifier, disabled);
    }

    /**
     * @notice  Withdraws an amount of creator earnings from a TokenMaster token to a specified address.
     * 
     * @dev     Partner earnings and infrastructure fees are withdrawn at the same time.
     * 
     * @dev     Throws when the caller is not the token, owner or an admin for the token.
     * @dev     Throws when paired tokens are to be transferred by the router and a transfer fails.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The amount of creator share has been withdrawn.
     * @dev    2. The partner share has been withdrawn.
     * @dev    3. The infrastructure fees have been withdrawn.
     * 
     * @param  tokenMasterToken  The address of the token to withdraw creator share from.
     * @param  withdrawTo        The address to withdraw creator share to.
     * @param  withdrawAmount    The amount of creator share to withdraw.
     */
    function withdrawCreatorShare(ITokenMasterERC20C tokenMasterToken, address withdrawTo, uint256 withdrawAmount) external nonReentrant {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdmin(address(tokenMasterToken));
        
        address partnerFeeRecipient = tokenSettings[address(tokenMasterToken)].partnerFeeRecipient;
        address infrastructureFeeRecipient = _getRoleHolder(TOKENMASTER_FEE_RECEIVER_ROLE);
        (
            address pairedToken,
            uint256 transferByRouterAmountCreator,
            uint256 transferByRouterAmountInfrastructure,
            uint256 transferByRouterAmountPartner
        ) = tokenMasterToken.withdrawCreatorShare(withdrawTo, withdrawAmount, infrastructureFeeRecipient, partnerFeeRecipient);

        if (transferByRouterAmountCreator > 0) {
            _transferPoolPairedToken(
                tokenMasterToken,
                pairedToken,
                withdrawTo,
                transferByRouterAmountCreator
            );
        }

        if (transferByRouterAmountInfrastructure > 0) {
            _transferPoolPairedToken(
                tokenMasterToken,
                pairedToken,
                infrastructureFeeRecipient,
                transferByRouterAmountInfrastructure
            );
        }

        if (transferByRouterAmountPartner > 0) {
            _transferPoolPairedToken(
                tokenMasterToken,
                pairedToken,
                partnerFeeRecipient,
                transferByRouterAmountPartner
            );
        }
    }

    /**
     * @notice  Transfers an amount of creator earnings for a TokenMaster token to the token's market share.
     * 
     * @dev     Partner earnings and infrastructure fees are withdrawn during this transaction.
     * 
     * @dev     Throws when the caller is not the token, owner or an admin for the token.
     * @dev     Throws when paired tokens are to be transferred by the router and a transfer fails.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The amount of creator share has been transfered to market share.
     * @dev    2. The partner share has been withdrawn.
     * @dev    3. The infrastructure fees have been withdrawn.
     * 
     * @param  tokenMasterToken  The address of the token to transfer creator share to market share on.
     * @param  transferAmount    The amount of creator share to transfer to the market share.
     */
    function transferCreatorShareToMarket(ITokenMasterERC20C tokenMasterToken, uint256 transferAmount) external nonReentrant {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdmin(address(tokenMasterToken));
        
        address partnerFeeRecipient = tokenSettings[address(tokenMasterToken)].partnerFeeRecipient;
        address infrastructureFeeRecipient = _getRoleHolder(TOKENMASTER_FEE_RECEIVER_ROLE);
        (
            address pairedToken,
            uint256 transferByRouterAmountInfrastructure,
            uint256 transferByRouterAmountPartner
        ) = tokenMasterToken.transferCreatorShareToMarket(transferAmount, infrastructureFeeRecipient, partnerFeeRecipient);

        if (transferByRouterAmountInfrastructure > 0) {
            _transferPoolPairedToken(
                tokenMasterToken,
                pairedToken,
                infrastructureFeeRecipient,
                transferByRouterAmountInfrastructure
            );
        }

        if (transferByRouterAmountPartner > 0) {
            _transferPoolPairedToken(
                tokenMasterToken,
                pairedToken,
                partnerFeeRecipient,
                transferByRouterAmountPartner
            );
        }
    }

    /**
     * @notice  Accepts a proposed partner fee receiver update from the partner fee receiver.
     * 
     * @dev     Throws when the caller is not the token, owner or an admin for the token.
     * @dev     Throws when the proposed partner fee recipient address is the zero address.
     * @dev     Throws when the proposed partner fee recipient address does not match the expected address.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The partner fee recipient has been updated.
     * @dev    2. A `PartnerFeeRecipientUpdated` event has been emitted.
     * 
     * @param  tokenMasterToken             The address of the token to accept the proposed fee receiver on.
     * @param  expectedPartnerFeeRecipient  The address the caller expects to be the proposed address.
     */
    function acceptProposedPartnerFeeReceiver(address tokenMasterToken, address expectedPartnerFeeRecipient) external {
        LibOwnership.requireCallerIsTokenOrContractOwnerOrAdmin(tokenMasterToken);

        TokenSettings storage settings = tokenSettings[tokenMasterToken];
        address proposedPartnerFeeRecipient = settings.proposedPartnerFeeRecipient;
        if (
            proposedPartnerFeeRecipient == address(0)
            || proposedPartnerFeeRecipient != expectedPartnerFeeRecipient
        ) {
            revert TokenMasterRouter__InvalidRecipient();
        }
        settings.partnerFeeRecipient = proposedPartnerFeeRecipient;
        settings.proposedPartnerFeeRecipient = address(0);

        emit PartnerFeeRecipientUpdated(tokenMasterToken, proposedPartnerFeeRecipient);
    }

    /*************************************************************************/
    /*                           PARTNER FUNCTIONS                           */
    /*************************************************************************/

    /**
     * @notice  Proposes a new partner fee receiver for a token.
     * 
     * @dev     Throws when the caller is not the current partner fee receiver.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The proposed partner fee recipient has been updated.
     * @dev    2. A `PartnerFeeRecipientProposed` event has been emitted.
     * 
     * @param  tokenMasterToken             The address of the token to propose the fee receiver on.
     * @param  proposedPartnerFeeRecipient  The address to propose.
     */
    function partnerProposeFeeReceiver(
        address tokenMasterToken,
        address proposedPartnerFeeRecipient
    ) external {
        TokenSettings storage settings = tokenSettings[tokenMasterToken];
        address partnerFeeRecipient = settings.partnerFeeRecipient;

        if (msg.sender != partnerFeeRecipient) {
            revert TokenMasterRouter__CallerNotAllowed();
        }
        
        settings.proposedPartnerFeeRecipient = proposedPartnerFeeRecipient;
        emit PartnerFeeRecipientProposed(tokenMasterToken, proposedPartnerFeeRecipient);
    }

    /*************************************************************************/
    /*                          FEE MGMT FUNCTIONS                           */
    /*************************************************************************/

    /**
     * @notice  Withdraws partner shares and infrastructure fees from many TokenMaster tokens.
     * 
     * @dev     Throws when the caller is not the TokenMaster fee collector or partner fee recipient.
     * @dev     Throws when a transfer is to be made by the router and the transfer fails.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. Partner fees for each token have been transferred to their receiver.
     * @dev    2. Infrastructure fees for each token have been transferred to the fee receiver.
     * 
     * @param  tokenMasterTokens  Array of token addresses to withdraw fees from.
     */
    function withdrawFees(ITokenMasterERC20C[] calldata tokenMasterTokens) external nonReentrant {
        bool authorized = msg.sender == _getRoleHolder(TOKENMASTER_FEE_COLLECTOR_ROLE);
        address infrastructureFeeRecipient = _getRoleHolder(TOKENMASTER_FEE_RECEIVER_ROLE);
        for (uint256 i; i < tokenMasterTokens.length; ++i) {
            ITokenMasterERC20C tokenMasterToken = tokenMasterTokens[i];
            TokenSettings storage settings = tokenSettings[address(tokenMasterToken)];
            address partnerFeeRecipient = settings.partnerFeeRecipient;

            if (!authorized) {
                if (msg.sender != partnerFeeRecipient) {
                    revert TokenMasterRouter__CallerNotAllowed();
                }
            }
            
            (
                address pairedToken,
                uint256 transferByRouterAmountInfrastructure,
                uint256 transferByRouterAmountPartner
            ) = tokenMasterToken.withdrawFees(infrastructureFeeRecipient, partnerFeeRecipient);

            if (transferByRouterAmountInfrastructure > 0) {
                _transferPoolPairedToken(
                    tokenMasterToken,
                    pairedToken,
                    infrastructureFeeRecipient,
                    transferByRouterAmountInfrastructure
                );
            }

            if (transferByRouterAmountPartner > 0) {
                _transferPoolPairedToken(
                    tokenMasterToken,
                    pairedToken,
                    partnerFeeRecipient,
                    transferByRouterAmountPartner
                );
            }
        }
    }

    /*************************************************************************/
    /*                             ADMIN FUNCTIONS                           */
    /*************************************************************************/

    /**
     * @notice  Sets or removes an allowed token factory for token deployments.
     * 
     * @dev     Throws when the caller is not the TokenMaster admin.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The token factory allowed state has been updated.
     * @dev    2. A `AllowedTokenFactoryUpdated` event has been emitted.
     * 
     * @param  tokenFactory  Address of the token factory to update.
     * @param  allowed       If true, the factory will be allowed to deploy tokens.
     */
    function setAllowedTokenFactory(
        address tokenFactory,
        bool allowed
    ) external onlyAdminAuthority {
        allowedTokenFactory[tokenFactory] = allowed;

        emit AllowedTokenFactoryUpdated(tokenFactory, allowed);
    }

    /**
     * @notice  Sets the infrastructure fee for new TokenMaster deployments.
     * 
     * @dev     Throws when the caller is not the TokenMaster admin.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The infrastructure fee has been updated for new deployments.
     * @dev    2. A `InfrastructureFeeUpdated` event has been emitted.
     * 
     * @param  _infrastructureFeeBPS  The fee rate, in BPS, to apply to new deployments.
     */
    function setInfrastructureFee(uint16 _infrastructureFeeBPS) external onlyAdminAuthority {
        if (_infrastructureFeeBPS > BPS) {
            revert TokenMasterRouter__InvalidInfrastructureFeeBPS();
        }

        infrastructureFeeBPS = _infrastructureFeeBPS;
        emit InfrastructureFeeUpdated(_infrastructureFeeBPS);
    }

    /*************************************************************************/
    /*                            VIEW FUNCTIONS                             */
    /*************************************************************************/

    /**
     * @notice  Gets the current status of a buy order and checks signature, cosignature validity.
     * 
     * @dev     Throws when the a supplied signature has an invalid `v` value.
     * @dev     Throws when a signed order has a cosignature and the cosignature is expired.
     * 
     * @param  tokenMasterToken  The address of the token the buy order is for.
     * @param  signedOrder       The signed buy order to get tracking data for.
     * @param  buyer             The address of the buyer.
     * 
     * @return  totalBought        If the buy order has a max total, the amount that has been purchased.
     * @return  totalWalletBought  If the buy order has a max per wallet, the amount that has been purchased by the buyer.
     * @return  orderDisabled      True if the order has been disabled by the creator.
     * @return  signatureValid     True if the supplied signature is valid for the order.
     * @return  cosignatureValid   True if there is no cosignature required or if the cosignature is valid for the order.
     */
    function getBuyTrackingData(
        address tokenMasterToken,
        SignedOrder calldata signedOrder,
        address buyer
    ) external view returns (
        uint256 totalBought,
        uint256 totalWalletBought,
        bool orderDisabled,
        bool signatureValid,
        bool cosignatureValid
    ) {
        bytes32 buyOrderHash = _hashSignedOrder(BUY_TYPEHASH, tokenMasterToken, signedOrder);
        OrderTracking storage orderData = orderTracking[buyOrderHash];
        orderDisabled = orderData.orderDisabled;
        totalBought = orderData.orderTotal;
        totalWalletBought = orderData.orderTotalPerWallet[buyer];
        if (signedOrder.expiration >= block.timestamp) {
            signatureValid = _validateOrderSignature(
                tokenSettings[tokenMasterToken].orderSigners,
                buyOrderHash,
                signedOrder.signature
            );
            if (signedOrder.cosignature.signer == address(0)) {
                cosignatureValid = true;
            } else {
                cosignatureValid = _validateCosignature(buyer, signedOrder.signature, signedOrder.cosignature);
            }
        }
    }

    /**
     * @notice  Gets the current status of a sell order and checks signature, cosignature validity.
     * 
     * @dev     Throws when the a supplied signature has an invalid `v` value.
     * @dev     Throws when a signed order has a cosignature and the cosignature is expired.
     * 
     * @param  tokenMasterToken  The address of the token the sell order is for.
     * @param  signedOrder       The signed sell order to get tracking data for.
     * @param  seller            The address of the seller.
     * 
     * @return  totalSold         If the sell order has a max total, the amount that has been sold.
     * @return  totalWalletSold   If the sell order has a max per wallet, the amount that has been sold by the seller.
     * @return  orderDisabled     True if the order has been disabled by the creator.
     * @return  signatureValid    True if the supplied signature is valid for the order.
     * @return  cosignatureValid  True if there is no cosignature required or if the cosignature is valid for the order.
     */
    function getSellTrackingData(
        address tokenMasterToken,
        SignedOrder calldata signedOrder,
        address seller
    ) external view returns (
        uint256 totalSold,
        uint256 totalWalletSold,
        bool orderDisabled,
        bool signatureValid,
        bool cosignatureValid
    ) {
        bytes32 sellOrderHash = _hashSignedOrder(SELL_TYPEHASH, tokenMasterToken, signedOrder);
        OrderTracking storage orderData = orderTracking[sellOrderHash];
        orderDisabled = orderData.orderDisabled;
        totalSold = orderData.orderTotal;
        totalWalletSold = orderData.orderTotalPerWallet[seller];
        if (signedOrder.expiration >= block.timestamp) {
            signatureValid = _validateOrderSignature(
                tokenSettings[tokenMasterToken].orderSigners,
                sellOrderHash,
                signedOrder.signature
            );
            if (signedOrder.cosignature.signer == address(0)) {
                cosignatureValid = true;
            } else {
                cosignatureValid = _validateCosignature(seller, signedOrder.signature, signedOrder.cosignature);
            }
        }
    }

    /**
     * @notice  Gets the current status of a spend order and checks signature, cosignature validity.
     * 
     * @dev     Throws when the a supplied signature has an invalid `v` value.
     * @dev     Throws when a signed order has a cosignature and the cosignature is expired.
     * 
     * @param  tokenMasterToken  The address of the token the spend order is for.
     * @param  signedOrder       The signed spend order to get tracking data for.
     * @param  spender            The address of the spender.
     * 
     * @return  totalMultipliersSpent        If the spend order has a max total, the amount of multipliers spent.
     * @return  totalWalletMultipliersSpent  If the spend order has a max per wallet, the amount of multipliers spent by the spender.
     * @return  orderDisabled                True if the order has been disabled by the creator.
     * @return  signatureValid               True if the supplied signature is valid for the order.
     * @return  cosignatureValid             True if there is no cosignature required or if the cosignature is valid for the order.
     */
    function getSpendTrackingData(
        address tokenMasterToken,
        SignedOrder calldata signedOrder,
        address spender
    ) external view returns (
        uint256 totalMultipliersSpent,
        uint256 totalWalletMultipliersSpent,
        bool orderDisabled,
        bool signatureValid,
        bool cosignatureValid
    ) {
        bytes32 spendOrderHash = _hashSignedOrder(SPEND_TYPEHASH, tokenMasterToken, signedOrder);
        OrderTracking storage orderData = orderTracking[spendOrderHash];
        orderDisabled = orderData.orderDisabled;
        totalMultipliersSpent = orderData.orderTotal;
        totalWalletMultipliersSpent = orderData.orderTotalPerWallet[spender];
        if (signedOrder.expiration >= block.timestamp) {
            signatureValid = _validateOrderSignature(
                tokenSettings[tokenMasterToken].orderSigners,
                spendOrderHash,
                signedOrder.signature
            );
            if (signedOrder.cosignature.signer == address(0)) {
                cosignatureValid = true;
            } else {
                cosignatureValid = _validateCosignature(spender, signedOrder.signature, signedOrder.cosignature);
            }
        }
    }

    /**
     * @notice  Gets the current settings for a token.
     * 
     * @param tokenAddress  The address of the token to get settings for.
     * 
     * @return deployedByTokenMaster                   True if the token was deployed through TokenMaster.
     * @return blockTransactionsFromUntrustedChannels  True if transactions must be executed through a trusted channel.
     * @return restrictPairingToLists                  True if tokens pairing with the token must be on an approved list.
     * @return partnerFeeRecipient                     The address of the partner fee recipient.
     */
    function getTokenSettings(
        address tokenAddress
    ) external view returns (
        bool deployedByTokenMaster,
        bool blockTransactionsFromUntrustedChannels,
        bool restrictPairingToLists,
        address partnerFeeRecipient
    ) {
        TokenSettings storage settings = tokenSettings[tokenAddress];

        uint8 flags = settings.flags;
        deployedByTokenMaster = _isFlagSet(flags, FLAG_DEPLOYED_BY_TOKENMASTER);
        blockTransactionsFromUntrustedChannels = _isFlagSet(flags, FLAG_BLOCK_TRANSACTIONS_FROM_UNTRUSTED_CHANNELS);
        restrictPairingToLists = _isFlagSet(flags, FLAG_RESTRICT_PAIRING_TO_LISTS);

        partnerFeeRecipient = settings.partnerFeeRecipient;
    }

    /**
     * @notice  Returns an array of all active order signers for a token.
     * 
     * @param tokenMasterToken  The address of the token to get signers for.
     * 
     * @return orderSigners  An array of signer addresses.
     */
    function getOrderSigners(address tokenMasterToken) external view returns (address[] memory orderSigners) {
        orderSigners = tokenSettings[tokenMasterToken].orderSigners.values();
    }

    /**
     * @notice  Returns an array of trusted channels for a token.
     * 
     * @param tokenMasterToken  The address of the token to get trusted channels for.
     * 
     * @return trustedChannels  An array of trusted channel addresses.
     */
    function getTrustedChannels(address tokenMasterToken) external view returns (address[] memory trustedChannels) {
        trustedChannels = tokenSettings[tokenMasterToken].trustedChannels.values();
    }

    /**
     * @notice  Returns an array of all active pair deployers for a token.
     * 
     * @param tokenMasterToken  The address of the token to get pair deployers for.
     * 
     * @return allowedPairToDeployers  An array of pair deployer addresses.
     */
    function getAllowedPairToDeployers(address tokenMasterToken) external view returns (address[] memory allowedPairToDeployers) {
        allowedPairToDeployers = tokenSettings[tokenMasterToken].allowedPairToDeployers.values();
    }

    /**
     * @notice  Returns an array of all active token addresses that may pair to a token.
     * 
     * @param tokenMasterToken  The address of the token to get pair token addresses for.
     * 
     * @return allowedPairToTokens  An array of token addresses that may pair to the TokenMaster token.
     */
    function getAllowedPairToTokens(address tokenMasterToken) external view returns (address[] memory allowedPairToTokens) {
        allowedPairToTokens = tokenSettings[tokenMasterToken].allowedPairToTokens.values();
    }

    /*************************************************************************/
    /*                           INTERNAL FUNCTIONS                          */
    /*************************************************************************/

    /**
     * @dev  Validates that a token was deployed by TokenMaster and, if untrusted channels are blocked,
     * @dev  that the caller is a trusted channel.
     * 
     * @return tokenMasterToken  Cast version of the token address to ITokenMasterERC20C for stack optimization.
     * @return settings          Storage pointer to the token settings for stack optimization.
     */
    function _validateTokenSettingsForTransaction(
        address token
    ) internal view returns (ITokenMasterERC20C tokenMasterToken, TokenSettings storage settings) {
        tokenMasterToken = ITokenMasterERC20C(token);
        settings = tokenSettings[token];

        uint8 flags = settings.flags;
        if (!_isFlagSet(flags, FLAG_DEPLOYED_BY_TOKENMASTER)) {
            revert TokenMasterRouter__TokenNotDeployedByTokenMaster();
        }
        if (_isFlagSet(flags, FLAG_BLOCK_TRANSACTIONS_FROM_UNTRUSTED_CHANNELS)) {
            if (!settings.trustedChannels.contains(msg.sender)) {
                revert TokenMasterRouter__TransactionOriginatedFromUntrustedChannel();
            }
        }
    }

    /**
     * @dev  Validates the paired token's settings to ensure the deployment being executed
     * @dev  is permitted by the paired token's creator.
     */
    function _validateTokenSettingsForDeployment(
        address deployer,
        address tokenAddress,
        address pairedToken
    ) internal view {
        TokenSettings storage settings = tokenSettings[pairedToken];

        uint8 flags = settings.flags;
        if (_isFlagSet(flags, FLAG_BLOCK_TRANSACTIONS_FROM_UNTRUSTED_CHANNELS)) {
            if (!settings.trustedChannels.contains(msg.sender)) {
                revert TokenMasterRouter__TransactionOriginatedFromUntrustedChannel();
            }
        }
        if (_isFlagSet(flags, FLAG_RESTRICT_PAIRING_TO_LISTS)) {
            if (!LibOwnership.isCallerTokenOrContractOwnerOrAdmin(deployer, pairedToken)) {
                if (!settings.allowedPairToDeployers.contains(deployer)) {
                    if (!settings.allowedPairToTokens.contains(tokenAddress)) {
                        revert TokenMasterRouter__PairedTokenPairingRestricted();
                    }
                }
            }
        }
    }

    /**
     * @dev  Transfers an amount of the paired token from the executor to the TokenMaster token.
     * 
     * @dev  Throws when native value is sent for a token that is paired with an ERC20.
     * @dev  Throws when an ERC20 paired token fails to transfer to the token contract.
     * @dev  Throws when the paired token balance in the pool decreases after the transfer.
     * 
     * @param  pairedToken       Address of the paired token to transfer to the pool.
     * @param  tokenMasterToken  Address of the TokenMaster token to transfer paired tokens to.
     * @param  executor          Address of the account executing the transaction to withdraw paired tokens from.
     * @param  transferAmount    Amount of tokens to transfer to the pool.
     * 
     * @return pairedValueIn  The amount of paired value that has been sent to the pool.
     */
    function _transferPairedValueToPool(
        address pairedToken,
        address tokenMasterToken,
        address executor,
        uint256 transferAmount
    ) internal returns (uint256 pairedValueIn) {
        pairedValueIn = msg.value;
        if (pairedToken != address(0)) {
            if (msg.value > 0) {
                revert TokenMasterRouter__NativeValueNotAllowedOnERC20();
            }
            uint256 pairedBalanceBefore = IERC20(pairedToken).balanceOf(address(tokenMasterToken));
            bool isError = SafeERC20.safeTransferFrom(pairedToken, executor, address(tokenMasterToken), transferAmount);
            if (isError) {
                revert TokenMasterRouter__FailedToTransferPairedToken();
            }
            uint256 pairedBalanceAfter = IERC20(pairedToken).balanceOf(address(tokenMasterToken));
            if (pairedBalanceAfter < pairedBalanceBefore) {
                revert TokenMasterRouter__FailedToTransferPairedToken();
            }
            unchecked {
                pairedValueIn = pairedBalanceAfter - pairedBalanceBefore;
            }
        }
    }

    /**
     * @dev  Transfers an amount of the paired token from the executor to the TokenMaster token
     * @dev  using PermitC's permit transfer function.
     * 
     * @dev  Throws when the paired token address is the native token.
     * @dev  Throws when an ERC20 paired token fails to transfer to the token contract.
     * @dev  Throws when the paired token balance in the pool decreases after the transfer.
     * 
     * @param  executor          Address of the account executing the transaction to withdraw paired tokens from.
     * @param  pairedToken       Address of the paired token to transfer to the pool.
     * @param  tokenMasterToken  Address of the TokenMaster token to transfer paired tokens to.
     * @param  buyOrder          Basic buy order details.
     * @param  signedOrder       Advanced order details and signatures.
     * @param  permitTransfer    Permit transfer details for the permit transfer.
     * 
     * @return pairedValueIn  The amount of paired value that has been sent to the pool.
     */
    function _permitTransferTokensToBuy(
        address executor,
        address pairedToken,
        address tokenMasterToken,
        BuyOrder calldata buyOrder,
        SignedOrder calldata signedOrder,
        PermitTransfer calldata permitTransfer
    ) internal returns (uint256 pairedValueIn) {
        if (pairedToken == address(0)) {
            revert TokenMasterRouter__PermitNotCompatibleWithNativeValue();
        }

        uint256 pairedBalanceBefore = IERC20(pairedToken).balanceOf(tokenMasterToken);

        bool isError = IPermitC(permitTransfer.permitProcessor).permitTransferFromWithAdditionalDataERC20(
            pairedToken,
            permitTransfer.nonce,
            permitTransfer.permitAmount,
            permitTransfer.expiration,
            executor,
            tokenMasterToken,
            buyOrder.pairedValueIn,
            _hashBuyOrderPermitAdvancedData(buyOrder, signedOrder),
            PERMITTED_TRANSFER_ADDITIONAL_DATA_BUY_TYPEHASH,
            permitTransfer.signedPermit
        );
        if (isError) {
            revert TokenMasterRouter__PermitTransferFailed();
        }

        uint256 pairedBalanceAfter = IERC20(pairedToken).balanceOf(tokenMasterToken);
        if (pairedBalanceAfter < pairedBalanceBefore) {
            revert TokenMasterRouter__FailedToTransferPairedToken();
        }

        unchecked {
            pairedValueIn = pairedBalanceAfter - pairedBalanceBefore;
        }
    }

    /**
     * @dev  Executes a buy for tokens from a TokenMaster token.
     * 
     * @param  tokenMasterToken  The token to buy tokens of.
     * @param  pairedValueIn     Amount of paired value to buy tokens with.
     * @param  tokensToBuy       Amount of tokens to purchase.
     * @param  pairedToken       Address of the token paired with the TokenMaster token.
     */
    function _executeBuy(
        ITokenMasterERC20C tokenMasterToken,
        address executor,
        uint256 pairedValueIn,
        uint256 tokensToBuy,
        address pairedToken
    ) internal {
        (
            uint256 totalCost,
            uint256 refundByRouterAmount
        ) = tokenMasterToken.buyTokens{value: msg.value}(executor, pairedValueIn, tokensToBuy);

        if (refundByRouterAmount > 0) {
            _transferPoolPairedToken(
                tokenMasterToken,
                pairedToken,
                executor,
                refundByRouterAmount
            );
        }

        emit BuyOrderFilled(address(tokenMasterToken), executor, tokensToBuy, totalCost);
    }

    /**
     * @dev  Validation function for an advanced buy order.
     * 
     * @dev  Throws when the order has expired.
     * @dev  Throws when the order is not signed by an authorized signer.
     * @dev  Throws when a cosigner is specified and the cosignature is invalid.
     * @dev  Throws when the buy amount does not meet the order minimum.
     * @dev  Throws when the order has been disabled.
     * @dev  Throws when the order has a maximum total and the buy will exceed it.
     * @dev  Throws when the order has a maximum per wallet and the buy will exceed it.
     * 
     * @param  tokenMasterToken  The token to buy tokens of.
     * @param  orderSigners      Storage pointer for allowed signer addresses.
     * @param  executor          Address of the advanced order buyer.
     * @param  orderTokensToBuy  Amount of tokens being bought.
     * @param  signedOrder       Advanced order details and signatures.
     * 
     * @return  tokensToBuy  Amount of tokens being purchased, returned for stack optimization.
     * @return  executeHook  If true, the advanced order hook will execute after the buy.
     */
    function _validateBuyParameters(
        address tokenMasterToken,
        EnumerableSet.AddressSet storage orderSigners,
        address executor,
        uint256 orderTokensToBuy,
        SignedOrder calldata signedOrder
    ) internal returns (uint256 tokensToBuy, bool executeHook) {
        tokensToBuy = orderTokensToBuy;
        executeHook = signedOrder.hook != address(0);
        if (executeHook) {
            if (signedOrder.expiration < block.timestamp) {
                revert TokenMasterRouter__OrderExpired();
            }
            bytes32 orderHash = _hashSignedOrder(BUY_TYPEHASH, tokenMasterToken, signedOrder);

            if (!_validateOrderSignature(orderSigners, orderHash, signedOrder.signature)) {
                revert TokenMasterRouter__OrderSignerUnauthorized();
            }
            if (signedOrder.cosignature.signer != address(0)) {
                if (!_validateCosignature(executor, signedOrder.signature, signedOrder.cosignature)) {
                    revert TokenMasterRouter__CosignatureInvalid();
                }
            }

            uint256 minimumToBuy = signedOrder.baseValue;
            if (signedOrder.tokenMasterOracle != address(0)) {
                minimumToBuy = ITokenMasterOracle(signedOrder.tokenMasterOracle).adjustValue(
                    ORACLE_BUY_TRANSACTION_TYPE,
                    executor,
                    tokenMasterToken,
                    signedOrder.baseToken,
                    signedOrder.baseValue,
                    signedOrder.oracleExtraData
                );
            }

            if (tokensToBuy < minimumToBuy) {
                revert TokenMasterRouter__OrderDoesNotMeetMinimum();
            }

            OrderTracking storage orderData = orderTracking[orderHash];
            if (orderData.orderDisabled) {
                revert TokenMasterRouter__OrderDisabled();
            }
            if (signedOrder.maxTotal > 0) {
                uint256 newTotal = orderData.orderTotal + tokensToBuy;
                if (newTotal > signedOrder.maxTotal) {
                    revert TokenMasterRouter__OrderMaxTotalExceeded();
                }
                orderData.orderTotal = newTotal;
            }
            if (signedOrder.maxPerWallet > 0) {
                uint256 newTotal = orderData.orderTotalPerWallet[executor] + tokensToBuy;
                if (newTotal > signedOrder.maxPerWallet) {
                    revert TokenMasterRouter__OrderMaxPerWalletExceeded();
                }
                orderData.orderTotalPerWallet[executor] = newTotal;
            }
        }
    }

    /**
     * @dev  Validation function for an advanced sell order.
     * 
     * @dev  Throws when the order has expired.
     * @dev  Throws when the order is not signed by an authorized signer.
     * @dev  Throws when a cosigner is specified and the cosignature is invalid.
     * @dev  Throws when the sell amount does not meet the order minimum.
     * @dev  Throws when the order has been disabled.
     * @dev  Throws when the order has a maximum total and the sell will exceed it.
     * @dev  Throws when the order has a maximum per wallet and the sell will exceed it.
     * 
     * @param  tokenMasterToken  The token to buy tokens of.
     * @param  orderSigners      Storage pointer for allowed signer addresses.
     * @param  executor          Address of the advanced order seller.
     * @param  tokensToSell      Amount of tokens being sold.
     * @param  signedOrder       Advanced order details and signatures.
     */
    function _validateSellParameters(
        address tokenMasterToken,
        EnumerableSet.AddressSet storage orderSigners,
        address executor,
        uint256 tokensToSell,
        SignedOrder calldata signedOrder
    ) internal {
        if (signedOrder.expiration < block.timestamp) {
            revert TokenMasterRouter__OrderExpired();
        }
        bytes32 orderHash = _hashSignedOrder(SELL_TYPEHASH, tokenMasterToken, signedOrder);

        if (!_validateOrderSignature(orderSigners, orderHash, signedOrder.signature)) {
            revert TokenMasterRouter__OrderSignerUnauthorized();
        }
        if (signedOrder.cosignature.signer != address(0)) {
            if (!_validateCosignature(executor, signedOrder.signature, signedOrder.cosignature)) {
                revert TokenMasterRouter__CosignatureInvalid();
            }
        }

        uint256 minimumToSell = signedOrder.baseValue;
        if (signedOrder.tokenMasterOracle != address(0)) {
            minimumToSell = ITokenMasterOracle(signedOrder.tokenMasterOracle).adjustValue(
                ORACLE_SELL_TRANSACTION_TYPE,
                executor,
                tokenMasterToken,
                signedOrder.baseToken,
                signedOrder.baseValue,
                signedOrder.oracleExtraData
            );
        }

        if (tokensToSell < minimumToSell) {
            revert TokenMasterRouter__OrderDoesNotMeetMinimum();
        }

        OrderTracking storage orderData = orderTracking[orderHash];
        if (orderData.orderDisabled) {
            revert TokenMasterRouter__OrderDisabled();
        }
        if (signedOrder.maxTotal > 0) {
            uint256 newTotal = orderData.orderTotal + tokensToSell;
            if (newTotal > signedOrder.maxTotal) {
                revert TokenMasterRouter__OrderMaxTotalExceeded();
            }
            orderData.orderTotal = newTotal;
        }
        if (signedOrder.maxPerWallet > 0) {
            uint256 newTotal = orderData.orderTotalPerWallet[executor] + tokensToSell;
            if (newTotal > signedOrder.maxPerWallet) {
                revert TokenMasterRouter__OrderMaxPerWalletExceeded();
            }
            orderData.orderTotalPerWallet[executor] = newTotal;
        }
    }

    /**
     * @dev  Executes a sell for tokens from a TokenMaster token.
     * 
     * @param  tokenMasterToken  The token to buy tokens of.
     * @param  executor          Address of the seller.
     * @param  sellOrder         Basic sell order details.
     */
    function _executeSell(
        ITokenMasterERC20C tokenMasterToken,
        address executor,
        SellOrder calldata sellOrder
    ) internal {
        (
            address pairedToken,
            uint256 totalReceived,
            uint256 transferByRouterAmount
        ) = tokenMasterToken.sellTokens(executor, sellOrder.tokensToSell, sellOrder.minimumOut);

        emit SellOrderFilled(address(tokenMasterToken), executor, sellOrder.tokensToSell, totalReceived);

        if (transferByRouterAmount > 0) {
            _transferPoolPairedToken(
                tokenMasterToken,
                pairedToken,
                executor,
                transferByRouterAmount
            );
        }
    }

    /**
     * @dev  Validation function for an advanced sell order.
     * 
     * @dev  Throws when the order has expired.
     * @dev  Throws when the order is not signed by an authorized signer.
     * @dev  Throws when a cosigner is specified and the cosignature is invalid.
     * @dev  Throws when the amount to spend exceeds the user specified maximum.
     * @dev  Throws when the order has been disabled.
     * @dev  Throws when the order has a maximum total and the sell will exceed it.
     * @dev  Throws when the order has a maximum per wallet and the sell will exceed it.
     * 
     * @param  orderSigners  Storage pointer for allowed signer addresses.
     * @param  executor      Address of the spender.
     * @param  spendOrder    Basic spend details.
     * @param  signedOrder   Advanced spend details and signature.
     * 
     * @return  adjustedAmountToSpend  Amount to spend, adjusted by oracle if necessary.
     * @return  multiplier             Multiplier of spend order being executed.
     */
    function _validateSpendParameters(
        EnumerableSet.AddressSet storage orderSigners,
        address executor,
        SpendOrder calldata spendOrder,
        SignedOrder calldata signedOrder
    ) internal returns (uint256 adjustedAmountToSpend, uint256 multiplier) {
        if (signedOrder.expiration < block.timestamp) {
            revert TokenMasterRouter__OrderExpired();
        }
        bytes32 spendOrderHash = _hashSignedOrder(SPEND_TYPEHASH, spendOrder.tokenMasterToken, signedOrder);

        if (!_validateOrderSignature(orderSigners, spendOrderHash, signedOrder.signature)) {
            revert TokenMasterRouter__OrderSignerUnauthorized();
        }
        if (signedOrder.cosignature.signer != address(0)) {
            if (!_validateCosignature(executor, signedOrder.signature, signedOrder.cosignature)) {
                revert TokenMasterRouter__CosignatureInvalid();
            }
        }

        multiplier = spendOrder.multiplier;
        adjustedAmountToSpend = signedOrder.baseValue * multiplier;
        if (signedOrder.tokenMasterOracle != address(0)) {
            adjustedAmountToSpend = ITokenMasterOracle(signedOrder.tokenMasterOracle).adjustValue(
                ORACLE_SPEND_TRANSACTION_TYPE,
                executor,
                spendOrder.tokenMasterToken,
                signedOrder.baseToken,
                adjustedAmountToSpend,
                signedOrder.oracleExtraData
            );
        }

        OrderTracking storage orderData = orderTracking[spendOrderHash];
        if (orderData.orderDisabled) {
            revert TokenMasterRouter__OrderDisabled();
        }
        if (signedOrder.maxTotal > 0) {
            uint256 newTotal = orderData.orderTotal + multiplier;
            if (newTotal > signedOrder.maxTotal) {
                revert TokenMasterRouter__OrderMaxTotalExceeded();
            }
            orderData.orderTotal = newTotal;
        }
        if (signedOrder.maxPerWallet > 0) {
            uint256 newTotal = orderData.orderTotalPerWallet[executor] + multiplier;
            if (newTotal > signedOrder.maxPerWallet) {
                revert TokenMasterRouter__OrderMaxPerWalletExceeded();
            }
            orderData.orderTotalPerWallet[executor] = newTotal;
        }
    }

    /**
     * @dev  Hashes an advanced order for EIP-712 signature validation.
     * 
     * @param  typehash          The EIP712 struct typehash for the order type.
     * @param  tokenMasterToken  Address of the TokenMaster token the advanced order is for.
     * @param  signedOrder       Advanced order details.
     * 
     * @return  orderHash  The struct hash for EIP-712 signature validation.
     */
    function _hashSignedOrder(
        bytes32 typehash,
        address tokenMasterToken,
        SignedOrder calldata signedOrder
    ) internal pure returns (bytes32 orderHash) {
        orderHash = EfficientHash.efficientHashElevenStep2(
            EfficientHash.efficientHashElevenStep1(
                typehash,
                signedOrder.creatorIdentifier,
                bytes32(uint256(uint160(tokenMasterToken))),
                bytes32(uint256(uint160(signedOrder.tokenMasterOracle))),
                bytes32(uint256(uint160(signedOrder.baseToken))),
                bytes32(signedOrder.baseValue),
                bytes32(signedOrder.maxPerWallet),
                bytes32(signedOrder.maxTotal)
            ),
            bytes32(signedOrder.expiration),
            bytes32(uint256(uint160(signedOrder.hook))),
            bytes32(uint256(uint160(signedOrder.cosignature.signer)))
        );
    }

    /**
     * @dev  Hashes the advanced permit transfer data for a PermitC transfer of paired tokens.
     * 
     * @param  buyOrder     Basic buy details.
     * @param  signedOrder  Advanced order details.
     * 
     * @return  hash  The struct hash validation in PermitC.
     */
    function _hashBuyOrderPermitAdvancedData(
        BuyOrder calldata buyOrder,
        SignedOrder calldata signedOrder
    ) internal pure returns(bytes32 hash) {
        hash = EfficientHash.efficientHashNineStep2(
            EfficientHash.efficientHashNineStep1(
                PERMITTED_TRANSFER_BUY_TYPEHASH,
                bytes32(uint256(uint160(buyOrder.tokenMasterToken))),
                bytes32(buyOrder.tokensToBuy),
                bytes32(buyOrder.pairedValueIn),
                signedOrder.creatorIdentifier,
                bytes32(uint256(uint160(signedOrder.hook))),
                bytes32(signedOrder.signature.v),
                signedOrder.signature.r
            ),
            signedOrder.signature.s
        );
    }

    /**
     * @dev  Validates that an order signature is from an allowed order signer for the TokenMaster token.
     * 
     * @dev  Throws when the signature's supplied `v` value is greater than 255.
     * 
     * @param  orderSigners      Storage pointer for allowed signer addresses.
     * @param  orderHash         The order struct hash for EIP-712 signature validation.
     * @param  signature         Signature r, s, and v values for signer address recovery.
     * 
     * @return  isValid  True if the recovered signing address is a valid signer.
     */
    function _validateOrderSignature(
        EnumerableSet.AddressSet storage orderSigners,
        bytes32 orderHash,
        SignatureECDSA calldata signature
    ) internal view returns (bool isValid) {
        if (signature.v > type(uint8).max) {
            revert Error__InvalidSignatureV();
        }
        
        address signer = ecrecover(_hashTypedDataV4(orderHash), uint8(signature.v), signature.r, signature.s);

        isValid = orderSigners.contains(signer);
    }

    /**
     * @dev  Validates that an authority signature if signing authority is enabled for token deployments.
     * 
     * @dev  Throws when the signature's supplied `v` value is greater than 255.
     * 
     * @param  digest     EIP-712 digest for signer address recovery.
     * @param  signature  Signature r, s, and v values for signer address recovery.
     * @param  authority  The signing authority set in the role server.
     * 
     * @return  isValid  True if the recovered signing address is the signing authority.
     */
    function _validateAuthoritySignature(
        bytes32 digest,
        SignatureECDSA calldata signature,
        address authority
    ) internal pure returns (bool isValid) {
        if (signature.v > type(uint8).max) {
            revert Error__InvalidSignatureV();
        }

        isValid = authority == ecrecover(digest, uint8(signature.v), signature.r, signature.s);
    }

    /**
     * @dev  Validates that a cosignature is valid for an advanced order.
     * 
     * @dev  Throws when the cosignature has expired.
     * @dev  Throws when the signature's supplied `v` value is greater than 255.
     * 
     * @param  executor     Address of the transaction executor.
     * @param  signature    Signature r, s, and v values for the advanced order.
     * @param  cosignature  Cosignature to validate.
     * 
     * @return  isValid  True if the cosignature is valid.
     */
    function _validateCosignature(
        address executor,
        SignatureECDSA calldata signature,
        Cosignature calldata cosignature
    ) internal view returns (bool isValid) {
        if (cosignature.expiration < block.timestamp) {
            revert TokenMasterRouter__CosignatureExpired();
        }
        if (cosignature.v > type(uint8).max) {
            revert Error__InvalidSignatureV();
        }

        bytes32 cosignatureHash = _hashTypedDataV4(
            EfficientHash.efficientHash(
                COSIGNATURE_TYPEHASH,
                bytes32(signature.v),
                signature.r,
                signature.s,
                bytes32(cosignature.expiration),
                bytes32(uint256(uint160(executor)))
            )
        );

        isValid = ecrecover(cosignatureHash, uint8(cosignature.v), cosignature.r, cosignature.s) == cosignature.signer;
    }

    /**
     * @dev  Transfers an amount of paired token from a TokenMaster token to a recipient.
     * @dev  This function will attempt to reset token approvals to handle unusual approval 
     * @dev  formats in paired tokens.
     * 
     * @dev  Throws when the transfer fails.
     * 
     * @param  tokenMasterToken  Address of the TokenMaster token to transfer paired tokens from.
     * @param  pairedToken       Address of the paired token to transfer from the pool.
     * @param  to                Address to send the paired tokens to.
     * @param  amount            Amount of tokens to transfer from the pool.
     */
    function _transferPoolPairedToken(
        ITokenMasterERC20C tokenMasterToken,
        address pairedToken,
        address to,
        uint256 amount
    ) internal {
        bool isError = SafeERC20.safeTransferFrom(pairedToken, address(tokenMasterToken), to, amount);
        if (isError) {
            // Potential approval issue with non-standard ERC20 paired token
            // attempt to reset approvals and transfer again.
            tokenMasterToken.resetPairedTokenApproval();
            isError = SafeERC20.safeTransferFrom(pairedToken, address(tokenMasterToken), to, amount);
            if (isError) {
                revert TokenMasterRouter__FailedToTransferPairedToken();
            }
        }
    }

    /**
     * @dev  Returns the executor for a transaction with trusted forwarder context if appended data length is 20 bytes.
     *
     * @dev  Throws when appended data length is not zero or 20 bytes.
     * 
     * @param expectedDataLength  The length of calldata expected for the transaction.
     * 
     * @return executor  The address of the executor for the transaction.
     */
    function _getExecutor(
        uint256 expectedDataLength
    ) internal view returns(address executor) {
        unchecked {
            uint256 appendedDataLength = msg.data.length - expectedDataLength;
            executor = msg.sender;
            if (appendedDataLength > 0) {
                if (appendedDataLength != 20) revert TokenMasterRouter__BadCalldataLength();
                executor = _msgSender();
            }
        }
    }

    /**
     * @dev  Convenience function to adjust a calldata parameter's expected length rounding up to 
     * @dev  the nearest 32 byte amount.
     * 
     * @dev  Throws when the supplied bytes length is greater than type(uint32).max.
     * 
     * @param  currentDataLength  Current length of expected calldata.
     * @param  bytesLength        Length of the bytes field.
     * 
     * @return  totalLength  Length of expected calldata with the bytes length rounded up.
     */
    function _addAdjustedBytesLength(uint256 currentDataLength, uint256 bytesLength) internal pure returns (uint256 totalLength) {
        if (bytesLength > type(uint32).max) {
            revert TokenMasterRouter__BadCalldataLength();
        }
        unchecked {
            totalLength = currentDataLength + ((bytesLength + 31) & ~uint256(31));
        }
    }

    /**
     * @dev  Hashes the deployment parameters and validates the signature against the signing authority.
     * 
     * @dev  Throws when the signature is not from the signing authority.
     * 
     * @param  deploymentParameters  The parameters for the token being deployed.
     * @param  signature             The signature from the signing authority.
     * @param  deploymentAuthority   The address set as the signing authority for deployments in the role server.
     */
    function _validateDeploymentSignature(
        DeploymentParameters calldata deploymentParameters,
        SignatureECDSA calldata signature,
        address deploymentAuthority
    ) internal view {
        bytes32 digest = _hashTypedDataV4(
            _hashDeploymentParameters(deploymentParameters)
        );

        if (!_validateAuthoritySignature(digest, signature, deploymentAuthority)) {
            revert TokenMasterRouter__InvalidDeploymentSignature();
        }
    }

    /**
     * @dev  Hashes the deployment parameters for a new TokenMaster token deployment for EIP-712 signature validation.
     * 
     * @param  deploymentParameters  The parameters for the token being deployed.
     * 
     * @return  hash  The struct hash of the deployment parameters.
     */
    function _hashDeploymentParameters(DeploymentParameters calldata deploymentParameters) internal pure returns (bytes32 hash) {
        hash = EfficientHash.efficientHash(
            DEPLOYMENT_TYPEHASH,
            bytes32(uint256(uint160(deploymentParameters.tokenFactory))),
            deploymentParameters.tokenSalt,
            bytes32(uint256(uint160(deploymentParameters.tokenAddress))),
            bytes32(uint256(deploymentParameters.blockTransactionsFromUntrustedChannels ? 1 : 0)),
            bytes32(uint256(deploymentParameters.restrictPairingToLists ? 1 : 0))
        );
    }

    /**
     * @dev  Returns true if the `flagValue` has the `flag` set, false otherwise.
     *
     * @dev  This function uses the bitwise AND operator to check if the `flag` is set in `flagValue`.
     *
     * @param flagValue  The value to check for the presence of the `flag`.
     * @param flag       The flag to check for in the `flagValue`.
     */
    function _isFlagSet(uint8 flagValue, uint8 flag) internal pure returns (bool flagSet) {
        flagSet = (flagValue & flag) != 0;
    }

    /**
     * @dev  Sets the `flag` in `flagValue` to `flagSet` and returns the updated value.
     * 
     * @dev  This function uses the bitwise OR and AND operators to set or unset the `flag` in `flagValue`.
     *
     * @param flagValue The value to set the `flag` in.
     * @param flag      The flag to set in the `flagValue`.
     * @param flagSet   True to set the `flag`, false to unset the `flag`.
     */
    function _setFlag(uint8 flagValue, uint8 flag, bool flagSet) internal pure returns (uint8) {
        if (flagSet) {
            return (flagValue | flag);
        } else {
            unchecked {
                return (flagValue & (255 - flag));
            }
        }
    }
}

File 2 of 35 : DataTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @dev Storage data struct for stored approvals and order approvals
struct PackedApproval {
    // Only used for partial fill position 1155 transfers
    uint8 state;
    // Amount allowed
    uint200 amount;
    // Permission expiry
    uint48 expiration;
}

/// @dev Calldata data struct for order fill amounts
struct OrderFillAmounts {
    uint256 orderStartAmount;
    uint256 requestedFillAmount;
    uint256 minimumFillAmount;
}

File 3 of 35 : IPermitC.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {OrderFillAmounts} from "../DataTypes.sol";

interface IPermitC {

    /**
     * =================================================
     * ==================== Events =====================
     * =================================================
     */

    /// @dev Emitted when an approval is stored
    event Approval(
        address indexed owner,
        address indexed token,
        address indexed operator,
        uint256 id,
        uint200 amount,
        uint48 expiration
    );

    /// @dev Emitted when a user increases their master nonce
    event Lockdown(address indexed owner);

    /// @dev Emitted when an order is opened
    event OrderOpened(
        bytes32 indexed orderId,
        address indexed owner,
        address indexed operator,
        uint256 fillableQuantity
    );

    /// @dev Emitted when an order has a fill
    event OrderFilled(
        bytes32 indexed orderId,
        address indexed owner,
        address indexed operator,
        uint256 amount
    );

    /// @dev Emitted when an order has been fully filled or cancelled
    event OrderClosed(
        bytes32 indexed orderId, 
        address indexed owner, 
        address indexed operator, 
        bool wasCancellation);

    /// @dev Emitted when an order has an amount restored due to a failed transfer
    event OrderRestored(
        bytes32 indexed orderId,
        address indexed owner,
        uint256 amountRestoredToOrder
    );

    /**
     * =================================================
     * ============== Approval Transfers ===============
     * =================================================
     */
    function approve(uint256 tokenType, address token, uint256 id, address operator, uint200 amount, uint48 expiration) external;

    function updateApprovalBySignature(
        uint256 tokenType,
        address token,
        uint256 id,
        uint256 nonce,
        uint200 amount,
        address operator,
        uint48 approvalExpiration,
        uint48 sigDeadline,
        address owner,
        bytes calldata signedPermit
    ) external;

    function allowance(
        address owner, 
        address operator, 
        uint256 tokenType,
        address token, 
        uint256 id
    ) external view returns (uint256 amount, uint256 expiration);

    /**
     * =================================================
     * ================ Signed Transfers ===============
     * =================================================
     */
    function registerAdditionalDataHash(string memory additionalDataTypeString) external;

    function permitTransferFromERC721(
        address token,
        uint256 id,
        uint256 nonce,
        uint256 expiration,
        address owner,
        address to,
        bytes calldata signedPermit
    ) external returns (bool isError);

    function permitTransferFromWithAdditionalDataERC721(
        address token,
        uint256 id,
        uint256 nonce,
        uint256 expiration,
        address owner,
        address to,
        bytes32 additionalData,
        bytes32 advancedPermitHash,
        bytes calldata signedPermit
    ) external returns (bool isError);

    function permitTransferFromERC1155(
        address token,
        uint256 id,
        uint256 nonce,
        uint256 permitAmount,
        uint256 expiration,
        address owner,
        address to,
        uint256 transferAmount,
        bytes calldata signedPermit
    ) external returns (bool isError);

    function permitTransferFromWithAdditionalDataERC1155(
        address token,
        uint256 id,
        uint256 nonce,
        uint256 permitAmount,
        uint256 expiration,
        address owner,
        address to,
        uint256 transferAmount,
        bytes32 additionalData,
        bytes32 advancedPermitHash,
        bytes calldata signedPermit
    ) external returns (bool isError);

    function permitTransferFromERC20(
        address token,
        uint256 nonce,
        uint256 permitAmount,
        uint256 expiration,
        address owner,
        address to,
        uint256 transferAmount,
        bytes calldata signedPermit
    ) external returns (bool isError);

    function permitTransferFromWithAdditionalDataERC20(
        address token,
        uint256 nonce,
        uint256 permitAmount,
        uint256 expiration,
        address owner,
        address to,
        uint256 transferAmount,
        bytes32 additionalData,
        bytes32 advancedPermitHash,
        bytes calldata signedPermit
    ) external returns (bool isError);

    function isRegisteredTransferAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered);

    function isRegisteredOrderAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered);

    /**
     * =================================================
     * =============== Order Transfers =================
     * =================================================
     */
    function fillPermittedOrderERC1155(
        bytes calldata signedPermit,
        OrderFillAmounts calldata orderFillAmounts,
        address token,
        uint256 id,
        address owner,
        address to,
        uint256 nonce,
        uint48 expiration,
        bytes32 orderId,
        bytes32 advancedPermitHash
    ) external returns (uint256 quantityFilled, bool isError);

    function fillPermittedOrderERC20(
        bytes calldata signedPermit,
        OrderFillAmounts calldata orderFillAmounts,
        address token,
        address owner,
        address to,
        uint256 nonce,
        uint48 expiration,
        bytes32 orderId,
        bytes32 advancedPermitHash
    ) external returns (uint256 quantityFilled, bool isError);

    function closePermittedOrder(
        address owner,
        address operator,
        uint256 tokenType,
        address token,
        uint256 id,
        bytes32 orderId
    ) external;

    function allowance(
        address owner, 
        address operator, 
        uint256 tokenType,
        address token, 
        uint256 id,
        bytes32 orderId
    ) external view returns (uint256 amount, uint256 expiration);


    /**
     * =================================================
     * ================ Nonce Management ===============
     * =================================================
     */
    function invalidateUnorderedNonce(uint256 nonce) external;

    function isValidUnorderedNonce(address owner, uint256 nonce) external view returns (bool isValid);

    function lockdown() external;

    function masterNonce(address owner) external view returns (uint256);

    /**
     * =================================================
     * ============== Transfer Functions ===============
     * =================================================
     */
    function transferFromERC721(
        address from,
        address to,
        address token,
        uint256 id
    ) external returns (bool isError);

    function transferFromERC1155(
        address from,
        address to,
        address token,
        uint256 id,
        uint256 amount
    ) external returns (bool isError);

    function transferFromERC20(
        address from,
        address to,
        address token,
        uint256 amount
    ) external returns (bool isError);

    /**
     * =================================================
     * ============ Signature Verification =============
     * =================================================
     */
    function domainSeparatorV4() external view returns (bytes32);
}

File 4 of 35 : EIP712.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.8;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * _Available since v3.4._
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
 */
abstract contract EIP712 {
    bytes32 private constant _TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
    }
}

File 5 of 35 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 6 of 35 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 7 of 35 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32")
            mstore(0x1c, hash)
            message := keccak256(0x00, 0x3c)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, "\x19\x01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            data := keccak256(ptr, 0x42)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Data with intended validator, created from a
     * `validator` and `data` according to the version 0 of EIP-191.
     *
     * See {recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x00", validator, data));
    }
}

File 8 of 35 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // 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 prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 9 of 35 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 10 of 35 : TrustedForwarderERC2771Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (metatx/ERC2771Context.sol)
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/utils/Context.sol";
import "./interfaces/ITrustedForwarderFactory.sol";

/**
 * @title TrustedForwarderERC2771Context
 * @author Limit Break, Inc.
 * @notice Context variant that utilizes the TrustedForwarderFactory contract to determine if the sender is a trusted forwarder.
 */
abstract contract TrustedForwarderERC2771Context is Context {
    ITrustedForwarderFactory private immutable _factory;

    constructor(address factory) {
        _factory = ITrustedForwarderFactory(factory);
    }

    /**
     * @notice Returns true if the sender is a trusted forwarder, false otherwise.
     *
     * @dev    This function is required by ERC2771Context.
     *
     * @param forwarder The address to check.
     * @return True if the provided address is a trusted forwarder, false otherwise.
     */
    function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
        return _factory.isTrustedForwarder(forwarder);
    }

    function _msgSender() internal view virtual override returns (address sender) {
        if (_factory.isTrustedForwarder(msg.sender)) {
            if (msg.data.length >= 20) {
                // The assembly code is more direct than the Solidity version using `abi.decode`.
                /// @solidity memory-safe-assembly
                assembly {
                    sender := shr(96, calldataload(sub(calldatasize(), 20)))
                }
            } else {
                return super._msgSender();
            }
        } else {
            return super._msgSender();
        }
    }

    function _msgData() internal view virtual override returns (bytes calldata data) {
        if (_factory.isTrustedForwarder(msg.sender)) {
            assembly {
                let len := calldatasize()
                // Create a slice that defaults to the entire calldata
                data.offset := 0
                data.length := len
                // If the calldata is > 20 bytes, it contains the sender address at the end
                // and needs to be truncated
                if gt(len, 0x14) {
                    data.length := sub(len, 0x14)
                }
            }
        } else {
            return super._msgData();
        }
    }
}

File 11 of 35 : ITrustedForwarderFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface ITrustedForwarderFactory {
    error TrustedForwarderFactory__TrustedForwarderInitFailed(address admin, address appSigner);

    event TrustedForwarderCreated(address indexed trustedForwarder);

    function cloneTrustedForwarder(address admin, address appSigner, bytes32 salt)
        external
        returns (address trustedForwarder);
    function forwarders(address) external view returns (bool);
    function isTrustedForwarder(address sender) external view returns (bool);
    function trustedForwarderImplementation() external view returns (address);
}

File 12 of 35 : LicenseRef-PolyForm-Strict-1.0.0.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity ^0.8.0;

/*
# PolyForm Strict License 1.0.0

<https://polyformproject.org/licenses/strict/1.0.0>

## Acceptance

In order to get any license under these terms, you must agree
to them as both strict obligations and conditions to all
your licenses.

## Copyright License

The licensor grants you a copyright license for the software
to do everything you might do with the software that would
otherwise infringe the licensor's copyright in it for any
permitted purpose, other than distributing the software or
making changes or new works based on the software.

## Patent License

The licensor grants you a patent license for the software that
covers patent claims the licensor can license, or becomes able
to license, that you would infringe by using the software.

## Noncommercial Purposes

Any noncommercial purpose is a permitted purpose.

## Personal Uses

Personal use for research, experiment, and testing for
the benefit of public knowledge, personal study, private
entertainment, hobby projects, amateur pursuits, or religious
observance, without any anticipated commercial application,
is use for a permitted purpose.

## Noncommercial Organizations

Use by any charitable organization, educational institution,
public research organization, public safety or health
organization, environmental protection organization,
or government institution is use for a permitted purpose
regardless of the source of funding or obligations resulting
from the funding.

## Fair Use

You may have "fair use" rights for the software under the
law. These terms do not limit them.

## No Other Rights

These terms do not allow you to sublicense or transfer any of
your licenses to anyone else, or prevent the licensor from
granting licenses to anyone else.  These terms do not imply
any other licenses.

## Patent Defense

If you make any written claim that the software infringes or
contributes to infringement of any patent, your patent license
for the software granted under these terms ends immediately. If
your company makes such a claim, your patent license ends
immediately for work on behalf of your company.

## Violations

The first time you are notified in writing that you have
violated any of these terms, or done anything with the software
not covered by your licenses, your licenses can nonetheless
continue if you come into full compliance with these terms,
and take practical steps to correct past violations, within
32 days of receiving notice.  Otherwise, all your licenses
end immediately.

## No Liability

***As far as the law allows, the software comes as is, without
any warranty or condition, and the licensor will not be liable
to you for any damages arising out of these terms or the use
or nature of the software, under any kind of legal claim.***

## Definitions

The **licensor** is the individual or entity offering these
terms, and the **software** is the software the licensor makes
available under these terms.

**You** refers to the individual or entity agreeing to these
terms.

**Your company** is any legal entity, sole proprietorship,
or other kind of organization that you work for, plus all
organizations that have control over, are under the control of,
or are under common control with that organization.  **Control**
means ownership of substantially all the assets of an entity,
or the power to direct its management and policies by vote,
contract, or otherwise.  Control can be direct or indirect.

**Your licenses** are all the licenses granted to you for the
software under these terms.

**Use** means anything you do with the software requiring one
of your licenses.
*/

File 13 of 35 : IERC20.sol
pragma solidity ^0.8.4;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 14 of 35 : SafeERC20.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

library SafeERC20 {
    /**
     * @dev A gas efficient, and fallback-safe method to transfer ERC20 tokens owned by the contract.
     * 
     * @param tokenAddress  The address of the token to transfer.
     * @param to            The address to transfer tokens to.
     * @param amount        The amount of tokens to transfer.
     * 
     * @return isError      True if there was an error transferring, false if the call was successful.
     */
    function safeTransfer(
        address tokenAddress,
        address to,
        uint256 amount
    ) internal returns(bool isError) {
        assembly {
            function _callTransfer(_tokenAddress, _to, _amount) -> _isError {
                let ptr := mload(0x40)
                mstore(0x40, add(ptr, 0x60))
                mstore(ptr, 0xa9059cbb)
                mstore(add(0x20, ptr), _to)
                mstore(add(0x40, ptr), _amount)
                if call(gas(), _tokenAddress, 0, add(ptr, 0x1C), 0x44, 0x00, 0x00) {
                    if lt(returndatasize(), 0x20) {
                        _isError := iszero(extcodesize(_tokenAddress))
                        leave
                    }
                    returndatacopy(0x00, 0x00, 0x20)
                    _isError := iszero(mload(0x00))
                    leave
                }
                _isError := true
            }
            isError := _callTransfer(tokenAddress, to, amount)
        }
    }

    /**
     * @dev A gas efficient, and fallback-safe method to transfer ERC20 tokens owned by another address.
     * 
     * @param tokenAddress  The address of the token to transfer.
     * @param from          The address to transfer tokens from.
     * @param to            The address to transfer tokens to.
     * @param amount        The amount of tokens to transfer.
     * 
     * @return isError      True if there was an error transferring, false if the call was successful.
     */
    function safeTransferFrom(
        address tokenAddress,
        address from,
        address to,
        uint256 amount
    ) internal returns(bool isError) {
        assembly {
            function _callTransferFrom(_tokenAddress, _from, _to, _amount) -> _isError {
                let ptr := mload(0x40)
                mstore(0x40, add(ptr, 0x80))
                mstore(ptr, 0x23b872dd)
                mstore(add(0x20, ptr), _from)
                mstore(add(0x40, ptr), _to)
                mstore(add(0x60, ptr), _amount)
                if call(gas(), _tokenAddress, 0, add(ptr, 0x1C), 0x64, 0x00, 0x00) {
                    if lt(returndatasize(), 0x20) {
                        _isError := iszero(extcodesize(_tokenAddress))
                        leave
                    }
                    returndatacopy(0x00, 0x00, 0x20)
                    _isError := iszero(mload(0x00))
                    leave
                }
                _isError := true
            }
            isError := _callTransferFrom(tokenAddress, from, to, amount)
        }
    }

    /**
     * @dev A gas efficient, and fallback-safe method to set approval on ERC20 tokens.
     * 
     * @param tokenAddress  The address of the token to transfer.
     * @param spender       The address to allow to spend tokens.
     * @param allowance     The amount of tokens to allow `spender` to transfer.
     * 
     * @return isError      True if there was an error setting allowance, false if the call was successful.
     */
    function safeApprove(
        address tokenAddress,
        address spender,
        uint256 allowance
    ) internal returns(bool isError) {
        assembly {
            function _callApprove(_tokenAddress, _spender, _allowance) -> _isError {
                let ptr := mload(0x40)
                mstore(0x40, add(ptr, 0x60))
                mstore(ptr, 0x095ea7b3)
                mstore(add(0x20, ptr), _spender)
                mstore(add(0x40, ptr), _allowance)
                if call(gas(), _tokenAddress, 0, add(ptr, 0x1C), 0x44, 0x00, 0x00) {
                    if lt(returndatasize(), 0x20) {
                        _isError := iszero(extcodesize(_tokenAddress))
                        leave
                    }
                    returndatacopy(0x00, 0x00, 0x20)
                    _isError := iszero(mload(0x00))
                    leave
                }
                _isError := true
            }
            isError := _callApprove(tokenAddress, spender, allowance)
        }
    }

    /**
     * @dev A gas efficient, and fallback-safe method to set approval on ERC20 tokens.
     * @dev If the initial approve fails, it will retry setting the allowance to zero and then
     * @dev to the new allowance.
     * 
     * @param tokenAddress  The address of the token to transfer.
     * @param spender       The address to allow to spend tokens.
     * @param allowance     The amount of tokens to allow `spender` to transfer.
     * 
     * @return isError      True if there was an error setting allowance, false if the call was successful.
     */
    function safeApproveWithRetryAfterZero(
        address tokenAddress,
        address spender,
        uint256 allowance
    ) internal returns(bool isError) {
        assembly {
            function _callApprove(_ptr, _tokenAddress, _spender, _allowance) -> _isError {
                mstore(add(0x40, _ptr), _allowance)
                if call(gas(), _tokenAddress, 0, add(_ptr, 0x1C), 0x44, 0x00, 0x00) {
                    if lt(returndatasize(), 0x20) {
                        _isError := iszero(extcodesize(_tokenAddress))
                        leave
                    }
                    returndatacopy(0x00, 0x00, 0x20)
                    _isError := iszero(mload(0x00))
                    leave
                }
                _isError := true
            }

            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x60))
            mstore(ptr, 0x095ea7b3)
            mstore(add(0x20, ptr), spender)

            isError := _callApprove(ptr, tokenAddress, spender, allowance)
            if isError {
                pop(_callApprove(ptr, tokenAddress, spender, 0x00))
                isError := _callApprove(ptr, tokenAddress, spender, allowance)
            }
        }
    }
}

File 15 of 35 : Errors.sol
pragma solidity ^0.8.4;

// General Purpose Custom Errors
error Error__BadConstructorArgument();

// Authorization Errors
error RoleClient__Unauthorized();

// Extensible Custom Errors
error Extensible__ConflictingFunctionSelectorAlreadyInstalled();
error Extensible__ExtensionAlreadyInstalled();
error Extensible__ExtensionNotInstalled();
error Extensible__InvalidExtension();

File 16 of 35 : EfficientHash.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

/**
 * @title  EfficientHash
 * 
 * @author Limit Break
 * 
 * @notice Performs keccak256 hashing of value type parameters more efficiently than 
 * @notice high-level Solidity by utilizing scratch space for one or two values and
 * @notice efficient utilization of memory for parameter counts greater than two.
 * 
 * @notice Gas savings for EfficientHash compared to keccak256(abi.encode(...)):
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 1 / 67 / 67
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 5 / 66 / 66
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 10 / 58 / 58
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 15 / 1549 / 565
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 20 / 3379 / 1027
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 25 / 5807 / 1650
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 50 / 23691 / 10107
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 75 / 69164 / 41620
 * @notice Parameter Count / Gas Savings (Shanghai) / Gas Savings (Cancun): 99 / 172694 / 126646
 * 
 * @dev    Notes:
 * @dev    - `efficientHash` is overloaded for parameter counts between one and eight.
 * @dev    - Parameter counts between nine and sixteen require two functions to avoid
 * @dev        stack too deep errors. Each parameter count has a dedicated set of functions
 * @dev        (`efficientHashNineStep1`/`efficientHashNineStep2` ... `efficientHashSixteenStep1`/`efficientHashSixteenStep2`)
 * @dev        that must both be called to get the hash. 
 * @dev        `Step1` functions take eight parameters and return a memory pointer that is passed to `Step2`
 * @dev        `Step2` functions take the remaining parameters and return the hash of the values
 * @dev        Example: 
 * @dev              bytes32 hash = EfficientHash.efficientHashElevenStep2(
 * @dev                                   EfficientHash.efficientHashElevenStep1(
 * @dev                                       value1,
 * @dev                                       value2,
 * @dev                                       value3,
 * @dev                                       value4,
 * @dev                                       value5,
 * @dev                                       value6,
 * @dev                                       value7,
 * @dev                                       value8
 * @dev                                   ),
 * @dev                                   value9,
 * @dev                                   value10,
 * @dev                                   value11,
 * @dev                               );
 * @dev    - Parameter counts greater than sixteen must use the `Extension` functions.
 * @dev        Extension starts with `efficientHashExtensionStart` which takes the number
 * @dev        of parameters and the first eight parameters as an input and returns a
 * @dev        memory pointer that is passed to the `Continue` and `End` functions.
 * @dev        While the number of parameters remaining is greater than eight, call the
 * @dev        `efficientHashExtensionContinue` function with the pointer value and 
 * @dev        the next eight values.
 * @dev        When the number of parameters remaining is less than or equal to eight
 * @dev        call the `efficientHashExtensionEnd` function with the pointer value
 * @dev        and remaining values.
 * @dev        Example: 
 * @dev            bytes32 hash = EfficientHash.efficientHashExtensionEnd(
 * @dev                             EfficientHash.efficientHashExtensionContinue(
 * @dev                                 EfficientHash.efficientHashExtensionStart(
 * @dev                                     23,
 * @dev                                     value1,
 * @dev                                     value2,
 * @dev                                     value3,
 * @dev                                     value4,
 * @dev                                     value5,
 * @dev                                     value6,
 * @dev                                     value7,
 * @dev                                     value8
 * @dev                                 ), 
 * @dev                                 value9,
 * @dev                                 value10,
 * @dev                                 value11,
 * @dev                                 value12,
 * @dev                                 value13,
 * @dev                                 value14,
 * @dev                                 value15,
 * @dev                                 value16
 * @dev                             ),
 * @dev                             value17,
 * @dev                             value18,
 * @dev                             value19,
 * @dev                             value20,
 * @dev                             value21,
 * @dev                             value22,
 * @dev                             value23
 * @dev                         );
 */
library EfficientHash {
    
    /**
     * @notice Hashes one value type.
     * 
     * @param value The value to be hashed.
     * 
     * @return hash The hash of the value.
     */
    function efficientHash(bytes32 value) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(0x00, value)

            hash := keccak256(0x00, 0x20)
        }
    }
    
    /**
     * @notice Hashes two value types.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHash(bytes32 value1, bytes32 value2) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(0x00, value1)
            mstore(0x20, value2)
            
            hash := keccak256(0x00, 0x40)
        }
    }
    
    /**
     * @notice Hashes three value types.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHash(bytes32 value1, bytes32 value2, bytes32 value3) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x60))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            
            hash := keccak256(ptr, 0x60)
        }
    }
    
    /**
     * @notice Hashes four value types.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHash(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x80))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            
            hash := keccak256(ptr, 0x80)
        }
    }
    
    /**
     * @notice Hashes five value types.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHash(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0xA0))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            
            hash := keccak256(ptr, 0xA0)
        }
    }
    
    /**
     * @notice Hashes six value types.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHash(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0xC0))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            
            hash := keccak256(ptr, 0xC0)
        }
    }
    
    /**
     * @notice Hashes seven value types.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHash(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0xE0))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            
            hash := keccak256(ptr, 0xE0)
        }
    }
    
    /**
     * @notice Hashes eight value types.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHash(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x100))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
            
            hash := keccak256(ptr, 0x100)
        }
    }
    
    /**
     * @notice Step one of hashing nine values. Must be followed by `efficientHashNineStep2` to hash the values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashNineStep1(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x120))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
        }
    }
    
    /**
     * @notice Step two of hashing nine values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value9  Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashNineStep2(
        uint256 ptr,
        bytes32 value9
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(add(ptr, 0x100), value9)

            hash := keccak256(ptr, 0x120)
        }
    }
    
    /**
     * @notice Step one of hashing ten values. Must be followed by `efficientHashTenStep2` to hash the values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashTenStep1(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x140))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
        }
    }
    
    /**
     * @notice Step two of hashing ten values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value9  Value to be hashed.
     * @param value10 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashTenStep2(
        uint256 ptr,
        bytes32 value9, bytes32 value10
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(add(ptr, 0x100), value9)
            mstore(add(ptr, 0x120), value10)

            hash := keccak256(ptr, 0x140)
        }
    }
    
    /**
     * @notice Step one of hashing eleven values. Must be followed by `efficientHashElevenStep2` to hash the values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashElevenStep1(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x160))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
        }
    }
    
    /**
     * @notice Step two of hashing eleven values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value9  Value to be hashed.
     * @param value10 Value to be hashed.
     * @param value11 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashElevenStep2(
        uint256 ptr,
        bytes32 value9, bytes32 value10, bytes32 value11
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(add(ptr, 0x100), value9)
            mstore(add(ptr, 0x120), value10)
            mstore(add(ptr, 0x140), value11)

            hash := keccak256(ptr, 0x160)
        }
    }
    
    /**
     * @notice Step one of hashing twelve values. Must be followed by `efficientHashTwelveStep2` to hash the values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashTwelveStep1(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x180))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
        }
    }
    
    /**
     * @notice Step two of hashing twelve values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value9  Value to be hashed.
     * @param value10 Value to be hashed.
     * @param value11 Value to be hashed.
     * @param value12 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashTwelveStep2(
        uint256 ptr,
        bytes32 value9, bytes32 value10, bytes32 value11, bytes32 value12
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(add(ptr, 0x100), value9)
            mstore(add(ptr, 0x120), value10)
            mstore(add(ptr, 0x140), value11)
            mstore(add(ptr, 0x160), value12)

            hash := keccak256(ptr, 0x180)
        }
    }
    
    /**
     * @notice Step one of hashing thirteen values. Must be followed by `efficientHashThirteenStep2` to hash the values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashThirteenStep1(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x1A0))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
        }
    }
    
    /**
     * @notice Step two of hashing thirteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value9  Value to be hashed.
     * @param value10 Value to be hashed.
     * @param value11 Value to be hashed.
     * @param value12 Value to be hashed.
     * @param value13 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashThirteenStep2(
        uint256 ptr,
        bytes32 value9, bytes32 value10, bytes32 value11, bytes32 value12,
        bytes32 value13
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(add(ptr, 0x100), value9)
            mstore(add(ptr, 0x120), value10)
            mstore(add(ptr, 0x140), value11)
            mstore(add(ptr, 0x160), value12)
            mstore(add(ptr, 0x180), value13)

            hash := keccak256(ptr, 0x1A0)
        }
    }
    
    /**
     * @notice Step one of hashing fourteen values. Must be followed by `efficientHashFourteenStep2` to hash the values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashFourteenStep1(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x1C0))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
        }
    }
    
    /**
     * @notice Step two of hashing fourteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value9  Value to be hashed.
     * @param value10 Value to be hashed.
     * @param value11 Value to be hashed.
     * @param value12 Value to be hashed.
     * @param value13 Value to be hashed.
     * @param value14 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashFourteenStep2(
        uint256 ptr,
        bytes32 value9, bytes32 value10, bytes32 value11, bytes32 value12,
        bytes32 value13, bytes32 value14
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(add(ptr, 0x100), value9)
            mstore(add(ptr, 0x120), value10)
            mstore(add(ptr, 0x140), value11)
            mstore(add(ptr, 0x160), value12)
            mstore(add(ptr, 0x180), value13)
            mstore(add(ptr, 0x1A0), value14)

            hash := keccak256(ptr, 0x1C0)
        }
    }
    
    /**
     * @notice Step one of hashing fifteen values. Must be followed by `efficientHashFifteenStep2` to hash the values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashFifteenStep1(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x1E0))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
        }
    }
    
    /**
     * @notice Step two of hashing fifteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value9  Value to be hashed.
     * @param value10 Value to be hashed.
     * @param value11 Value to be hashed.
     * @param value12 Value to be hashed.
     * @param value13 Value to be hashed.
     * @param value14 Value to be hashed.
     * @param value15 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashFifteenStep2(
        uint256 ptr,
        bytes32 value9, bytes32 value10, bytes32 value11, bytes32 value12,
        bytes32 value13, bytes32 value14, bytes32 value15
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(add(ptr, 0x100), value9)
            mstore(add(ptr, 0x120), value10)
            mstore(add(ptr, 0x140), value11)
            mstore(add(ptr, 0x160), value12)
            mstore(add(ptr, 0x180), value13)
            mstore(add(ptr, 0x1A0), value14)
            mstore(add(ptr, 0x1C0), value15)

            hash := keccak256(ptr, 0x1E0)
        }
    }
    
    /**
     * @notice Step one of hashing sixteen values. Must be followed by `efficientHashSixteenStep2` to hash the values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashSixteenStep1(
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x200))

            mstore(ptr, value1)
            mstore(add(ptr, 0x20), value2)
            mstore(add(ptr, 0x40), value3)
            mstore(add(ptr, 0x60), value4)
            mstore(add(ptr, 0x80), value5)
            mstore(add(ptr, 0xA0), value6)
            mstore(add(ptr, 0xC0), value7)
            mstore(add(ptr, 0xE0), value8)
        }
    }
    
    /**
     * @notice Step two of hashing sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value9  Value to be hashed.
     * @param value10 Value to be hashed.
     * @param value11 Value to be hashed.
     * @param value12 Value to be hashed.
     * @param value13 Value to be hashed.
     * @param value14 Value to be hashed.
     * @param value15 Value to be hashed.
     * @param value16 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashSixteenStep2(
        uint256 ptr,
        bytes32 value9, bytes32 value10, bytes32 value11, bytes32 value12,
        bytes32 value13, bytes32 value14, bytes32 value15, bytes32 value16
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            mstore(add(ptr, 0x100), value9)
            mstore(add(ptr, 0x120), value10)
            mstore(add(ptr, 0x140), value11)
            mstore(add(ptr, 0x160), value12)
            mstore(add(ptr, 0x180), value13)
            mstore(add(ptr, 0x1A0), value14)
            mstore(add(ptr, 0x1C0), value15)
            mstore(add(ptr, 0x1E0), value16)

            hash := keccak256(ptr, 0x200)
        }
    }
    
    /**
     * @notice Step one of hashing more than sixteen values.
     * @notice Must be followed by at least one call to 
     * @notice `efficientHashExtensionContinue` and completed with
     * @notice a call to `efficientHashExtensionEnd` with the remaining
     * @notice values.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptr The memory pointer location for the values to hash.
     */
    function efficientHashExtensionStart(
        uint256 numberOfValues,
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptr) {
        assembly ("memory-safe") {
            ptr := mload(0x40)
            mstore(0x40, add(add(ptr, 0x20), mul(numberOfValues, 0x20)))
            mstore(ptr, 0x100)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)
            mstore(add(ptr, 0x60), value3)
            mstore(add(ptr, 0x80), value4)
            mstore(add(ptr, 0xA0), value5)
            mstore(add(ptr, 0xC0), value6)
            mstore(add(ptr, 0xE0), value7)
            mstore(add(ptr, 0x100), value8)
        }
    }
    
    /**
     * @notice Second step of hashing more than sixteen values.
     * @notice Adds another eight values to the values to be hashed.
     * @notice May be called as many times as necessary until the values
     * @notice remaining to be added to the hash is less than or equal to
     * @notice eight.
     * 
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return ptrReturn The memory pointer location for the values to hash.
     */
    function efficientHashExtensionContinue(
        uint256 ptr,
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(uint256 ptrReturn) {
        assembly ("memory-safe") {
            ptrReturn := ptr
            let length := mload(ptrReturn)
            mstore(ptrReturn, add(length, 0x100))

            ptr := add(ptrReturn, length)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)
            mstore(add(ptr, 0x60), value3)
            mstore(add(ptr, 0x80), value4)
            mstore(add(ptr, 0xA0), value5)
            mstore(add(ptr, 0xC0), value6)
            mstore(add(ptr, 0xE0), value7)
            mstore(add(ptr, 0x100), value8)
        }
    }

    /**
     * @notice Final step of hashing more than sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value1 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashExtensionEnd(
        uint256 ptr,
        bytes32 value1
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptrStart := ptr
            let length := mload(ptrStart)

            ptr := add(ptrStart, length)
            
            mstore(add(ptr, 0x20), value1)

            hash := keccak256(add(ptrStart, 0x20), add(length, 0x20))
        }
    }

    /**
     * @notice Final step of hashing more than sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashExtensionEnd(
        uint256 ptr,
        bytes32 value1, bytes32 value2
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptrStart := ptr
            let length := mload(ptrStart)

            ptr := add(ptrStart, length)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)

            hash := keccak256(add(ptrStart, 0x20), add(length, 0x40))
        }
    }

    /**
     * @notice Final step of hashing more than sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashExtensionEnd(
        uint256 ptr,
        bytes32 value1, bytes32 value2, bytes32 value3
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptrStart := ptr
            let length := mload(ptrStart)

            ptr := add(ptrStart, length)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)
            mstore(add(ptr, 0x60), value3)

            hash := keccak256(add(ptrStart, 0x20), add(length, 0x60))
        }
    }

    /**
     * @notice Final step of hashing more than sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashExtensionEnd(
        uint256 ptr,
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptrStart := ptr
            let length := mload(ptrStart)

            ptr := add(ptrStart, length)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)
            mstore(add(ptr, 0x60), value3)
            mstore(add(ptr, 0x80), value4)

            hash := keccak256(add(ptrStart, 0x20), add(length, 0x80))
        }
    }

    /**
     * @notice Final step of hashing more than sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashExtensionEnd(
        uint256 ptr,
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptrStart := ptr
            let length := mload(ptrStart)

            ptr := add(ptrStart, length)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)
            mstore(add(ptr, 0x60), value3)
            mstore(add(ptr, 0x80), value4)
            mstore(add(ptr, 0xA0), value5)

            hash := keccak256(add(ptrStart, 0x20), add(length, 0xA0))
        }
    }

    /**
     * @notice Final step of hashing more than sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashExtensionEnd(
        uint256 ptr,
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptrStart := ptr
            let length := mload(ptrStart)

            ptr := add(ptrStart, length)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)
            mstore(add(ptr, 0x60), value3)
            mstore(add(ptr, 0x80), value4)
            mstore(add(ptr, 0xA0), value5)
            mstore(add(ptr, 0xC0), value6)

            hash := keccak256(add(ptrStart, 0x20), add(length, 0xC0))
        }
    }

    /**
     * @notice Final step of hashing more than sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashExtensionEnd(
        uint256 ptr,
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptrStart := ptr
            let length := mload(ptrStart)

            ptr := add(ptrStart, length)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)
            mstore(add(ptr, 0x60), value3)
            mstore(add(ptr, 0x80), value4)
            mstore(add(ptr, 0xA0), value5)
            mstore(add(ptr, 0xC0), value6)
            mstore(add(ptr, 0xE0), value7)

            hash := keccak256(add(ptrStart, 0x20), add(length, 0xE0))
        }
    }

    /**
     * @notice Final step of hashing more than sixteen values.
     * 
     * @param ptr    The memory pointer location for the values to hash.
     * @param value1 Value to be hashed.
     * @param value2 Value to be hashed.
     * @param value3 Value to be hashed.
     * @param value4 Value to be hashed.
     * @param value5 Value to be hashed.
     * @param value6 Value to be hashed.
     * @param value7 Value to be hashed.
     * @param value8 Value to be hashed.
     * 
     * @return hash The hash of the values.
     */
    function efficientHashExtensionEnd(
        uint256 ptr,
        bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4,
        bytes32 value5, bytes32 value6, bytes32 value7, bytes32 value8
    ) internal pure returns(bytes32 hash) {
        assembly ("memory-safe") {
            let ptrStart := ptr
            let length := mload(ptrStart)

            ptr := add(ptrStart, length)
            
            mstore(add(ptr, 0x20), value1)
            mstore(add(ptr, 0x40), value2)
            mstore(add(ptr, 0x60), value3)
            mstore(add(ptr, 0x80), value4)
            mstore(add(ptr, 0xA0), value5)
            mstore(add(ptr, 0xC0), value6)
            mstore(add(ptr, 0xE0), value7)
            mstore(add(ptr, 0x100), value8)

            hash := keccak256(add(ptrStart, 0x20), add(length, 0x100))
        }
    }
}

File 17 of 35 : StorageTstorish.sol
pragma solidity ^0.8.24;

library StorageTstorish {   
    // keccak256(abi.encode(uint256(keccak256("storage.Tstorish")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant DATA_STORAGE_SLOT = 
        0xdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00;

    struct Data {
        // Indicates if TSTORE support has been activated during or post-deployment.
        bool tstoreSupport;
    }

    function data() internal pure returns (Data storage ptr) {
        bytes32 slot = DATA_STORAGE_SLOT;
        assembly {
            ptr.slot := slot
        }
    }
}

File 18 of 35 : Tstorish.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "./StorageTstorish.sol";

/**
 * @title  Tstorish
 * @notice Based on https://github.com/ProjectOpenSea/tstorish/commit/a81ed74453ed7b9fe7e96a9906bc4def19b73e33
 */
abstract contract Tstorish {

    /*
     * ------------------------------------------------------------------------+
     * Opcode      | Mnemonic         | Stack              | Memory            |
     * ------------------------------------------------------------------------|
     * 60 0x02     | PUSH1 0x02       | 0x02               |                   |
     * 60 0x1e     | PUSH1 0x1e       | 0x1e 0x02          |                   |
     * 61 0x3d5c   | PUSH2 0x3d5c     | 0x3d5c 0x1e 0x02   |                   |
     * 3d          | RETURNDATASIZE   | 0 0x3d5c 0x1e 0x02 |                   |
     *                                                                         |
     * :: store deployed bytecode in memory: (3d) RETURNDATASIZE (5c) TLOAD :: |
     * 52          | MSTORE           | 0x1e 0x02          | [0..0x20): 0x3d5c |
     * f3          | RETURN           |                    | [0..0x20): 0x3d5c |
     * ------------------------------------------------------------------------+
     */
    uint256 constant _TLOAD_TEST_PAYLOAD = 0x6002_601e_613d5c_3d_52_f3;
    uint256 constant _TLOAD_TEST_PAYLOAD_LENGTH = 0x0a;
    uint256 constant _TLOAD_TEST_PAYLOAD_OFFSET = 0x16;

    // Declare an immutable variable to store the tstore test contract address.
    address private immutable _tloadTestContract;

    // Declare an immutable variable to store the initial TSTORE support status.
    bool internal immutable _tstoreInitialSupport;

    // Declare an immutable function type variable for the _setTstorish function
    // based on chain support for tstore at time of deployment.
    function(uint256,uint256) internal immutable _setTstorish;

    // Declare an immutable function type variable for the _getTstorish function
    // based on chain support for tstore at time of deployment.
    function(uint256) view returns (uint256) internal immutable _getTstorish;

    // Declare an immutable function type variable for the _clearTstorish function
    // based on chain support for tstore at time of deployment.
    function(uint256) internal immutable _clearTstorish;

    // Declare a few custom revert error types.
    error TStoreAlreadyActivated();
    error TStoreNotSupported();
    error TloadTestContractDeploymentFailed();
    error OnlyDirectCalls();

    /**
     * @dev Determine TSTORE availability during deployment. This involves
     *      attempting to deploy a contract that utilizes TLOAD as part of the
     *      contract construction bytecode, and configuring initial support for
     *      using TSTORE in place of SSTORE based on the result.
     */
    constructor() {
        // Deploy the contract testing TLOAD support and store the address.
        address tloadTestContract = _prepareTloadTest();

        // Ensure the deployment was successful.
        if (tloadTestContract == address(0)) {
            revert TloadTestContractDeploymentFailed();
        }

        // Determine if TSTORE is supported.
        _tstoreInitialSupport = StorageTstorish.data().tstoreSupport = _testTload(tloadTestContract);

        if (_tstoreInitialSupport) {
            // If TSTORE is supported, set functions to their versions that use
            // tstore/tload directly without support checks.
            _setTstorish = _setTstore;
            _getTstorish = _getTstore;
            _clearTstorish = _clearTstore;
        } else {
            // If TSTORE is not supported, set functions to their versions that 
            // fallback to sstore/sload until tstoreSupport is true.
            _setTstorish = _setTstorishWithSstoreFallback;
            _getTstorish = _getTstorishWithSloadFallback;
            _clearTstorish = _clearTstorishWithSstoreFallback;
        }

        // Set the address of the deployed TLOAD test contract as an immutable.
        _tloadTestContract = tloadTestContract;
    }

    /**
     * @dev Called internally when tstore is activated by an external call to 
     *      `__activateTstore`. Developers must override this function and handle
     *      relevant transfers of data from regular storage to transient storage *OR*
     *      revert the transaction if it is in a state that should not support the activation
     *      of tstore.
     */
    function _onTstoreSupportActivated() internal virtual;

    /**
     * @dev External function to activate TSTORE usage. Does not need to be
     *      called if TSTORE is supported from deployment, and only needs to be
     *      called once. Reverts if TSTORE has already been activated or if the
     *      opcode is not available. Note that this must be called directly from
     *      an externally-owned account to avoid potential reentrancy issues.
     */
    function __activateTstore() external {
        // Determine if TSTORE can potentially be activated.
        if (_tstoreInitialSupport || StorageTstorish.data().tstoreSupport) {
            revert TStoreAlreadyActivated();
        }

        // Determine if TSTORE can be activated and revert if not.
        if (!_testTload(_tloadTestContract)) {
            revert TStoreNotSupported();
        }

        // Mark TSTORE as activated.
        StorageTstorish.data().tstoreSupport = true;

        _onTstoreSupportActivated();
    }

    /**
     * @dev Private function to set a TSTORISH value. Assigned to _setTstorish 
     *      internal function variable at construction if chain has tstore support.
     *
     * @param storageSlot The slot to write the TSTORISH value to.
     * @param value       The value to write to the given storage slot.
     */
    function _setTstore(uint256 storageSlot, uint256 value) internal {
        assembly {
            tstore(storageSlot, value)
        }
    }

    /**
     * @dev Private function to set a TSTORISH value with sstore fallback. 
     *      Assigned to _setTstorish internal function variable at construction
     *      if chain does not have tstore support.
     *
     * @param storageSlot The slot to write the TSTORISH value to.
     * @param value       The value to write to the given storage slot.
     */
    function _setTstorishWithSstoreFallback(uint256 storageSlot, uint256 value) internal {
        if (StorageTstorish.data().tstoreSupport) {
            assembly {
                tstore(storageSlot, value)
            }
        } else {
            assembly {
                sstore(storageSlot, value)
            }
        }
    }

    /**
     * @dev Private function to read a TSTORISH value. Assigned to _getTstorish
     *      internal function variable at construction if chain has tstore support.
     *
     * @param storageSlot The slot to read the TSTORISH value from.
     *
     * @return value The TSTORISH value at the given storage slot.
     */
    function _getTstore(
        uint256 storageSlot
    ) internal view returns (uint256 value) {
        assembly {
            value := tload(storageSlot)
        }
    }

    /**
     * @dev Private function to read a TSTORISH value with sload fallback. 
     *      Assigned to _getTstorish internal function variable at construction
     *      if chain does not have tstore support.
     *
     * @param storageSlot The slot to read the TSTORISH value from.
     *
     * @return value The TSTORISH value at the given storage slot.
     */
    function _getTstorishWithSloadFallback(
        uint256 storageSlot
    ) internal view returns (uint256 value) {
        if (StorageTstorish.data().tstoreSupport) {
            assembly {
                value := tload(storageSlot)
            }
        } else {
            assembly {
                value := sload(storageSlot)
            }
        }
    }

    /**
     * @dev Private function to clear a TSTORISH value. Assigned to _clearTstorish internal 
     *      function variable at construction if chain has tstore support.
     *
     * @param storageSlot The slot to clear the TSTORISH value for.
     */
    function _clearTstore(uint256 storageSlot) internal {
        assembly {
            tstore(storageSlot, 0)
        }
    }

    /**
     * @dev Private function to clear a TSTORISH value with sstore fallback. 
     *      Assigned to _clearTstorish internal function variable at construction
     *      if chain does not have tstore support.
     *
     * @param storageSlot The slot to clear the TSTORISH value for.
     */
    function _clearTstorishWithSstoreFallback(uint256 storageSlot) internal {
        if (StorageTstorish.data().tstoreSupport) {
            assembly {
                tstore(storageSlot, 0)
            }
        } else {
            assembly {
                sstore(storageSlot, 0)
            }
        }
    }

    /**
     * @dev Private function to copy a value from storage to transient storage at the same slot.
     *      Useful when tstore is activated on a chain that didn't initially support it.
     */
    function _copyFromStorageToTransient(uint256 storageSlot) internal {
        if (StorageTstorish.data().tstoreSupport) {
            assembly {
                tstore(storageSlot, sload(storageSlot))
            }
        } else {
            revert TStoreNotSupported();
        }
    }

    /**
     * @dev Private function to deploy a test contract that utilizes TLOAD as
     *      part of its fallback logic.
     */
    function _prepareTloadTest() private returns (address contractAddress) {
        // Utilize assembly to deploy a contract testing TLOAD support.
        assembly {
            // Write the contract deployment code payload to scratch space.
            mstore(0, _TLOAD_TEST_PAYLOAD)

            // Deploy the contract.
            contractAddress := create(
                0,
                _TLOAD_TEST_PAYLOAD_OFFSET,
                _TLOAD_TEST_PAYLOAD_LENGTH
            )
        }
    }

    /**
     * @dev Private view function to determine if TSTORE/TLOAD are supported by
     *      the current EVM implementation by attempting to call the test
     *      contract, which utilizes TLOAD as part of its fallback logic.
     */
    function _testTload(
        address tloadTestContract
    ) private view returns (bool ok) {
        // Call the test contract, which will perform a TLOAD test. If the call
        // does not revert, then TLOAD/TSTORE is supported. Do not forward all
        // available gas, as all forwarded gas will be consumed on revert.
        (ok, ) = tloadTestContract.staticcall{ gas: gasleft() / 10 }("");
    }
}

File 19 of 35 : IRoleClient.sol
pragma solidity ^0.8.4;

interface IRoleClient {
    function onRoleHolderChanged(bytes32 /*role*/, address /*roleHolder*/) external;
}

File 20 of 35 : IRoleServer.sol
pragma solidity ^0.8.4;

interface IRoleServer {
    function getRoleHolder(bytes32 /*role*/) external view returns (address);
    function setRoleHolder(bytes32 /*role*/, address /*authority*/, address[] calldata /*clients*/) external;
}

File 21 of 35 : RoleClientBase.sol
pragma solidity ^0.8.4;

import "./IRoleClient.sol";
import "./IRoleServer.sol";
import "../Errors.sol";

abstract contract RoleClientBase is IRoleClient {
    struct RoleRecord {
        address roleHolder;
        uint64 expiration;
        uint32 ttl;
    }

    IRoleServer private immutable _roleServer;

    struct RoleClientStorage {
        mapping (bytes32 role => RoleRecord record) roleRecords;
    }

    bytes32 private constant ROLE_CLIENT_STORAGE_SLOT = keccak256("storage.RoleClientBase");
    
    function roleClientStorage() internal pure returns (RoleClientStorage storage ptr) {
        bytes32 slot = ROLE_CLIENT_STORAGE_SLOT;
        assembly {
            ptr.slot := slot
        }
    }

    constructor(address roleServer) {
        if (roleServer == address(0)) {
            revert Error__BadConstructorArgument();
        }

        _roleServer = IRoleServer(roleServer);
    }

    modifier callerHasRole(bytes32 role) {
        _requireCallerHasRole(role);
        _;
    }

    function onRoleHolderChanged(bytes32 role, address roleHolder) external {
        if (msg.sender != address(_roleServer)) {
            revert RoleClient__Unauthorized();
        }

        unchecked {
            RoleRecord storage record = roleClientStorage().roleRecords[role];
            record.roleHolder = roleHolder;
            record.expiration = uint64(block.timestamp + record.ttl);
        }
    }

    function _getRoleHolder(bytes32 role) internal returns (address roleHolder) {
        RoleRecord storage record = roleClientStorage().roleRecords[role];
        roleHolder = record.roleHolder;

        unchecked {
            if (record.expiration < block.timestamp) {
                roleHolder = _roleServer.getRoleHolder(role);
                record.roleHolder = roleHolder;
                record.expiration = uint64(block.timestamp + record.ttl);
            }
        }
    }

    function _getRoleHolderView(bytes32 role) internal view returns (address roleHolder) {
        RoleRecord storage record = roleClientStorage().roleRecords[role];
        roleHolder = record.roleHolder;

        unchecked {
            if (record.expiration < block.timestamp) {
                roleHolder = _roleServer.getRoleHolder(role);
            }
        }
    }

    function _requireCallerHasRole(bytes32 role) internal {
        if (msg.sender != _getRoleHolder(role)) {
            revert RoleClient__Unauthorized();
        }
    }

    function _setupRole(bytes32 role, uint32 ttl) internal {
        unchecked {
            RoleRecord storage record = roleClientStorage().roleRecords[role];
            record.roleHolder = _roleServer.getRoleHolder(role);
            record.ttl = ttl;
            record.expiration = uint64(block.timestamp) + ttl;
        }
    }
}

File 22 of 35 : RoleSetClient.sol
pragma solidity ^0.8.4;

import "./RoleClientBase.sol";

abstract contract RoleSetClient is RoleClientBase {

    constructor(address roleServer, bytes32 roleSet) RoleClientBase(roleServer) {
        _setupRoles(roleSet);
    }

    function _hashRoleSetRole(
        bytes32 roleSet,
        bytes32 baseRole
    ) internal pure returns (bytes32 role) {
        role = keccak256(abi.encode(roleSet, baseRole));
    }

    function _setupRoles(bytes32 roleSet) internal virtual;
}

File 23 of 35 : TstorishReentrancyGuard.sol
pragma solidity ^0.8.24;

import "../misc/Tstorish.sol";

/**
 * @dev Variant of {ReentrancyGuard} that uses transient storage.
 *
 * NOTE: This variant only works on networks where EIP-1153 is available.
 */
abstract contract TstorishReentrancyGuard is Tstorish {

    // keccak256(abi.encode(uint256(keccak256("storage.TstorishReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    uint256 private constant REENTRANCY_GUARD_STORAGE = 
        0xeff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb890500;

    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() Tstorish() {
        if (!_tstoreInitialSupport) {
            _setTstorish(REENTRANCY_GUARD_STORAGE, NOT_ENTERED);
        }
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_getTstorish(REENTRANCY_GUARD_STORAGE) == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _setTstorish(REENTRANCY_GUARD_STORAGE, ENTERED);
    }

    function _nonReentrantAfter() private {
        _setTstorish(REENTRANCY_GUARD_STORAGE, NOT_ENTERED);
    }

    function _onTstoreSupportActivated() internal virtual override {
        _copyFromStorageToTransient(REENTRANCY_GUARD_STORAGE);
    }
}

File 24 of 35 : EnumerableSet.sol
pragma solidity ^0.8.4;

/**
 * @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.
 *
 * ```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 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 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;

        /// @solidity memory-safe-assembly
        assembly {
            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 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;

        /// @solidity memory-safe-assembly
        assembly {
            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 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;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 25 of 35 : Constants.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

/// @dev Constant value for BPS where 1 BPS is 0.01%
uint16 constant BPS = 100_00;
/// @dev Constant value for zero.
uint256 constant ZERO = 0;
/// @dev Constant value for one.
uint256 constant ONE = 1;
// Target supply baseline is a uint48 multiplied by 10 ^ scale factor
// Limiting scale factor to 62 prevents an overflow of expected supply 
// since type(uint48).max * 10**62 equals 2.81e76.
// To overflow with target supply growth rate the current timestamp would need to exceed
// the baseline timestamp by 3.5e40 years.
uint16 constant MAX_BASELINE_SCALE_FACTOR = 62;

/// @dev Pausable flag to pause buys in a TokenMaster token.
uint256 constant PAUSE_FLAG_BUYS = 1 << 0;
/// @dev Pausable flag to pause sells in a TokenMaster token.
uint256 constant PAUSE_FLAG_SELLS = 1 << 1;
/// @dev Pausable flag to pause spends in a TokenMaster token.
uint256 constant PAUSE_FLAG_SPENDS = 1 << 2;

/// @dev EIP-712 typehash for deployments that require signature validation.
bytes32 constant DEPLOYMENT_TYPEHASH = keccak256("DeploymentParameters(address tokenFactory,bytes32 tokenSalt,address tokenAddress,bool blockTransactionsFromUntrustedChannels,bool restrictPairingToLists)");
/// @dev EIP-712 typehash for advanced buy orders.
bytes32 constant BUY_TYPEHASH = keccak256("BuyTokenMasterToken(bytes32 creatorBuyIdentifier,address tokenMasterToken,address tokenMasterOracle,address baseToken,uint256 baseValue,uint256 maxPerWallet,uint256 maxTotal,uint256 expiration,address hook,address cosigner)");
/// @dev EIP-712 typehash for advanced sell orders.
bytes32 constant SELL_TYPEHASH = keccak256("SellTokenMasterToken(bytes32 creatorSellIdentifier,address tokenMasterToken,address tokenMasterOracle,address baseToken,uint256 baseValue,uint256 maxPerWallet,uint256 maxTotal,uint256 expiration,address hook,address cosigner)");
/// @dev EIP-712 typehash for spend orders.
bytes32 constant SPEND_TYPEHASH = keccak256("SpendTokenMasterToken(bytes32 creatorSpendIdentifier,address tokenMasterToken,address tokenMasterOracle,address baseToken,uint256 baseValue,uint256 maxPerWallet,uint256 maxTotal,uint256 expiration,address hook,address cosigner)");
/// @dev EIP-712 tyephash for cosignatures.
bytes32 constant COSIGNATURE_TYPEHASH = keccak256("Cosignature(uint8 v,bytes32 r,bytes32 s,uint256 expiration,address executor)");
/// @dev EIP-712 typehash for advanced PermitC transfers.
bytes32 constant PERMITTED_TRANSFER_ADDITIONAL_DATA_BUY_TYPEHASH = keccak256("PermitTransferFromWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce,AdvancedBuyOrder advancedBuyOrder)AdvancedBuyOrder(address tokenMasterToken,uint256 tokensToBuy,uint256 pairedValueIn,bytes32 creatorBuyIdentifier,address hook,uint8 buyOrderSignatureV,bytes32 buyOrderSignatureR,bytes32 buyOrderSignatureS)");
/// @dev EIP-712 typehash for the advanced data struct in PermitC advanced transfers.
bytes32 constant PERMITTED_TRANSFER_BUY_TYPEHASH = keccak256("AdvancedBuyOrder(address tokenMasterToken,uint256 tokensToBuy,uint256 pairedValueIn,bytes32 creatorBuyIdentifier,address hook,uint8 buyOrderSignatureV,bytes32 buyOrderSignatureR,bytes32 buyOrderSignatureS)");

/// @dev Role constant for roles in a token to grant an address the ability to manage orders.
bytes32 constant ORDER_MANAGER_ROLE = bytes32(bytes4(keccak256("ORDER_MANAGER")));

/// @dev Base amount of calldata expected for a buy order when not being called by a trusted forwarder.
// | 4        | 96       | = 100 bytes
// | selector | buyOrder |
uint256 constant BASE_MSG_LENGTH_BUY_ORDER = 100;
/// @dev Base amount of calldata expected for an advanced buy order when not being called by a trusted forwarder.
// | 4        | 96       | 32                 | 32                    | 640         | 192            | = 996 bytes
// | selector | buyOrder | signedOrder Offset | permitTransfer Offset | signedOrder | permitTransfer |
uint256 constant BASE_MSG_LENGTH_BUY_ORDER_ADVANCED = 996;
/// @dev Base amount of calldata expected for a sell order when not being called by a trusted forwarder.
// | 4        | 96        | = 100 bytes
// | selector | sellOrder |
uint256 constant BASE_MSG_LENGTH_SELL_ORDER = 100;
/// @dev Base amount of calldata expected for an advanced sell order when not being called by a trusted forwarder.
// | 4        | 96        | 32                 | 640         | = 772 bytes
// | selector | sellOrder | signedOrder Offset | signedOrder |
uint256 constant BASE_MSG_LENGTH_SELL_ORDER_ADVANCED = 772;
/// @dev Base amount of calldata expected for a spend order when not being called by a trusted forwarder.
// | 4        | 96         | 32                 | 640         | = 772 bytes
// | selector | spendOrder | signedOrder Offset | signedOrder |
uint256 constant BASE_MSG_LENGTH_SPEND_ORDER = 772;
/// @dev Base amount of calldata expected for a token deployment when not being called by a trusted forwarder.
// | 4        | 32                         | 96        | 672                  | = 996 bytes
// | selector | deploymentParmeters Offset | signature | deploymentParameters |
uint256 constant BASE_MSG_LENGTH_DEPLOY_TOKEN = 804;

/// @dev Token setting flag to indicate a token was deployed by TokenMaster.
uint8 constant FLAG_DEPLOYED_BY_TOKENMASTER = 1 << 0;
/// @dev Token setting flag to block transactions from untrusted channels.
uint8 constant FLAG_BLOCK_TRANSACTIONS_FROM_UNTRUSTED_CHANNELS = 1 << 1;
/// @dev Token setting flag to restrict pairing of the token to only allowed addresses.
uint8 constant FLAG_RESTRICT_PAIRING_TO_LISTS = 1 << 2;

/// @dev Base role constant for the TokenMaster Admin in the Role Server.
bytes32 constant TOKENMASTER_ADMIN_BASE_ROLE = keccak256("TOKENMASTER_ADMIN_ROLE");
/// @dev Base role constant for the TokenMaster Deployment Signer in the Role Server.
bytes32 constant TOKENMASTER_SIGNER_BASE_ROLE = keccak256("TOKENMASTER_SIGNER_ROLE");
/// @dev Base role constant for the TokenMaster Fee Receiver in the Role Server.
bytes32 constant TOKENMASTER_FEE_RECEIVER_BASE_ROLE = keccak256("TOKENMASTER_FEE_RECEIVER");
/// @dev Base role constant for the TokenMaster Fee Collector in the Role Server.
bytes32 constant TOKENMASTER_FEE_COLLECTOR_BASE_ROLE = keccak256("TOKENMASTER_FEE_COLLECTOR");

/// @dev Transaction type value passed to a TokenMasterOracle when the transaction being executed is a buy.
uint256 constant ORACLE_BUY_TRANSACTION_TYPE = 0;
/// @dev Transaction type value passed to a TokenMasterOracle when the transaction being executed is a sell.
uint256 constant ORACLE_SELL_TRANSACTION_TYPE = 1;
/// @dev Transaction type value passed to a TokenMasterOracle when the transaction being executed is a spend.
uint256 constant ORACLE_SPEND_TRANSACTION_TYPE = 2;

/// @dev Constant value for the maximum address value for masking in factories.
address constant ADDRESS_MASK = address(type(uint160).max);

File 26 of 35 : DataTypes.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

import "@limitbreak/tm-core-lib/src/utils/structs/EnumerableSet.sol";

/**
 * @dev This struct defines storage for token settings.
 * 
 * @dev **flags**: Bit packed flags for token settings defined in constants.
 * @dev **spacer**: Unused
 * @dev **partnerFeeRecipient**: Address of the partner fee recipient for a token.
 * @dev **proposedPartnerFeeRecipient**: Address proposed by the current partner fee recipient to be the new fee recipient.
 * @dev **orderSigners**: Enumerable list of addresses that are allowed order signers.
 * @dev **trustedChannels**: Enumerable list of channels that are allowed for token transactions.
 * @dev **allowedPairToDeployers**: Enumberable list of deployers that are allowed to deploy tokens paired with the token.
 * @dev **allowedPairToTokens**: Enumberable list of tokens that are allowed to deploy as paired with the token.
 */
struct TokenSettings {
    uint8 flags;
    uint248 spacer;
    address partnerFeeRecipient;
    address proposedPartnerFeeRecipient;
    EnumerableSet.AddressSet orderSigners;
    EnumerableSet.AddressSet trustedChannels;
    EnumerableSet.AddressSet allowedPairToDeployers;
    EnumerableSet.AddressSet allowedPairToTokens;
}

/**
 * @dev This struct defines parameters used by the TokenMasterRouter and factories for deploying tokens.
 * 
 * @dev **tokenFactory**: The token factory to use to deploy a specific pool type.
 * @dev **tokenSalt**: The salt value to use when deploying the token to control the deterministic address.
 * @dev **tokenAddress**: The deterministic address of the token that will be deployed.
 * @dev **blockTransactionsFromUntrustedChannels**: Initial setting for blocking transactions from untrusted channels.
 * @dev **restrictPairingToLists**: Initial setting for restricting pairing of the new token with other tokens.
 * @dev **poolParams**: The parameters that will be sent during token contract construction.
 * @dev **maxInfrastructureFeeBPS**: The maximum infrastructure fee that is allowed without reverting the deployment.
 */
struct DeploymentParameters {
    address tokenFactory;
    bytes32 tokenSalt;
    address tokenAddress;
    bool blockTransactionsFromUntrustedChannels;
    bool restrictPairingToLists;
    PoolDeploymentParameters poolParams;
    uint16 maxInfrastructureFeeBPS;
}

/**
 * @dev This struct defines parameters that are sent by token factories to create a token contract.
 * 
 * @dev **name**: The name of the token.
 * @dev **symbol**: The symbol of the token.
 * @dev **decimals**: The number of decimals of the token.
 * @dev **initialOwner**: Address to set as the initial owner of the token.
 * @dev **pairedToken**: Address of the token to pair with the new token, for native token use `address(0)`.
 * @dev **initialPairedTokenToDeposit**: Amount of paired token to deposit to the new token pool.
 * @dev **encodedInitializationArgs**: Bytes array of ABI encoded initialization arguments to allow new pool types 
 * @dev with different types of constructor arguments that are decoded during deployment.
 * @dev **defaultTransferValidator**: Address of the initial transfer validator for a token.
 * @dev **useRouterForPairedTransfers**: If true, the pool will default to allowing the router to transfer paired tokens
 * @dev during operations that require the paired token to transfer from the pool. This is useful when pairing with
 * @dev ERC20C tokens that utilize the default operator whitelist which includes the TokenMasterRouter but does not
 * @dev include individual token pools.
 * @dev **partnerFeeRecipient**: The address that will receive partner fee shares.
 * @dev **partnerFeeBPS**: The fee rate in BPS for partner fees.
 */
struct PoolDeploymentParameters {
    string name;
    string symbol;
    uint8 tokenDecimals;
    address initialOwner;
    address pairedToken;
    uint256 initialPairedTokenToDeposit;
    bytes encodedInitializationArgs;
    address defaultTransferValidator;
    bool useRouterForPairedTransfers;
    address partnerFeeRecipient;
    uint256 partnerFeeBPS;
}

/**
 * @dev This struct defines storage for tracking advanced orders.
 * 
 * @dev **orderDisabled**: True if the order has been disabled by the creator.
 * @dev **orderTotal**: The total amount executed by all users on the order.
 * @dev **orderTotalPerWallet**: The total amount per wallet executed on the order.
 */
struct OrderTracking {
    bool orderDisabled;
    uint256 orderTotal;
    mapping (address => uint256) orderTotalPerWallet;
}

/**
 * @dev This struct defines buy order base parameters.
 * 
 * @dev **tokenMasterToken**: The address of the TokenMaster token to buy.
 * @dev **tokensToBuy**: The amount of tokens to buy.
 * @dev **pairedValueIn**: The amount of paired tokens to transfer in to the token contract for the purchase.
 */
struct BuyOrder {
    address tokenMasterToken;
    uint256 tokensToBuy;
    uint256 pairedValueIn;
}

/**
 * @dev This struct defines a permit transfer parameters.
 * 
 * @dev **permitProcessor**: The address of the PermitC-compliant permit processor to use for the transfer.
 * @dev **nonce**: The permit nonce to use for the permit transfer signature validation.
 * @dev **permitAmount**: The amount that the permit was signed for.
 * @dev **expiration**: The time, in seconds since the Unix epoch, that the permit will expire.
 * @dev **signedPermit**: The permit signature bytes authorizing the transfer.
 */
struct PermitTransfer {
    address permitProcessor;
    uint256 nonce;
    uint256 permitAmount;
    uint256 expiration;
    bytes signedPermit;
}

/**
 * @dev This struct defines sell order base parameters.
 * 
 * @dev **tokenMasterToken**: The address of the TokenMaster token to sell.
 * @dev **tokensToSell**: The amount of tokens to sell.
 * @dev **minimumOut**: The minimum output of paired tokens to be received by the seller without the transaction reverting.
 */
struct SellOrder {
    address tokenMasterToken;
    uint256 tokensToSell;
    uint256 minimumOut;
}

/**
 * @dev This struct defines spend order base parameters.
 * 
 * @dev **tokenMasterToken**: The address of the TokenMaster token to spend.
 * @dev **multiplier**: The multiplier of the signed spend order's `baseValue`, adjusted by an oracle if specified, to be spent.
 * @dev **maxAmountToSpend**: The maximum amount the spender will spend on the order without the transaction reverting.
 */
struct SpendOrder {
    address tokenMasterToken;
    uint256 multiplier;
    uint256 maxAmountToSpend;
}

/**
 * @dev This struct defines advanced order execution parameters.
 * 
 * @dev **creatorIdentifier**: A value specified by the creator to identify the order for any onchain or offchain benefits
 * @dev to the order executor for executing the order.
 * @dev **tokenMasterOracle**: An address for an onchain oracle that can adjust the `baseValue` for an advanced order.
 * @dev **baseToken**: An address for a token to base the `baseValue` on when adjusting value through a TokenMaster Oracle.
 * @dev **baseValue**: The amount of token required for the order to be executed.
 * @dev If `tokenMasterOracle` is set to `address(0)`, the `baseToken` will not be utilized and the advanced order will 
 * @dev execute with `baseValue` being the amount of the TokenMaster token to be required for the order.
 * @dev **maxPerWallet**: The maximum amount per wallet that can be executed on the order. For buy and sell advanced orders
 * @dev this amount is in the TokenMaster token amount, for spend orders it is multipliers.
 * @dev **maxPerWallet**: The maximum amount for all wallets that can be executed on the order. For buy and sell advanced orders
 * @dev this amount is in the TokenMaster token amount, for spend orders it is multipliers.
 * @dev **expiration**: The time, in seconds since the Unix epoch, that the order will expire.
 * @dev **hook**: An address for an onchain hook for an order to execute after the buy, sell or spend is executed.
 * @dev **signature**: The signature from an allowed order signer to authorize the order.
 * @dev **cosignature**: The cosignature from the cosigner specified by the order signer.
 * @dev **hookExtraData**: Extra data to send with the call to the onchain hook contract.
 * @dev **oracleExtraData**: Extra data to send with the call to the oracle contract.
 */
struct SignedOrder {
    bytes32 creatorIdentifier;
    address tokenMasterOracle;
    address baseToken;
    uint256 baseValue;
    uint256 maxPerWallet;
    uint256 maxTotal;
    uint256 expiration;
    address hook;
    SignatureECDSA signature;
    Cosignature cosignature;
    bytes hookExtraData;
    bytes oracleExtraData;
}

/**
 * @dev The `v`, `r`, and `s` components of an ECDSA signature.  For more information
 *      [refer to this article](https://medium.com/mycrypto/the-magic-of-digital-signatures-on-ethereum-98fe184dc9c7).
 */
struct SignatureECDSA {
    uint256 v;
    bytes32 r;
    bytes32 s;
}

/**
 * @dev This struct defines the cosignature for verifying an order that is a cosigned order.
 *
 * @dev **signer**: The address that signed the cosigned order. This must match the cosigner that is part of the order signature.
 * @dev **expiration**: The time, in seconds since the Unix epoch, that the cosignature will expire.
 * @dev The `v`, `r`, and `s` components of an ECDSA signature.  For more information
 *      [refer to this article](https://medium.com/mycrypto/the-magic-of-digital-signatures-on-ethereum-98fe184dc9c7).
 */
struct Cosignature {
    address signer;
    uint256 expiration;
    uint256 v;
    bytes32 r;
    bytes32 s;
}

File 27 of 35 : Errors.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

/// @dev Thrown when a signature `v` value exceeds 255.
error Error__InvalidSignatureV();

// TokenMaster Errors
/// @dev Thrown when a deployment call is made to a token factory and it does not originate from the TokenMasterRouter.
error TokenMasterFactory__CallerMustBeRouter();
/// @dev Thrown when deploying a token factory and the TokenMasterRouter address is not set in the factory configuration contract.
error TokenMasterFactory__RouterAddressNotSet();

/// @dev Thrown when the amount of tokens to be spent exceeds the maximum amount specified by the spender.
error TokenMasterRouter__AmountToSpendExceedsMax();
/// @dev Thrown when calldata length does not match the expected calldata length.
error TokenMasterRouter__BadCalldataLength();
/// @dev Thrown when a caller is attempting to execute a permissioned function they are not permitted for.
error TokenMasterRouter__CallerNotAllowed();
/// @dev Thrown when the block time is after the expiration of a cosignature.
error TokenMasterRouter__CosignatureExpired();
/// @dev Thrown when a cosigner is specified on an advanced order and the cosignature is invalid.
error TokenMasterRouter__CosignatureInvalid();
/// @dev Thrown when the deterministic address specified in deployment parameters does not match the address returned from a token factory.
error TokenMasterRouter__DeployedTokenAddressMismatch();
/// @dev Thrown when a new TokenMaster token deployment expects to deposit native funds to the pool and the funds fail to transfer.
error TokenMasterRouter__FailedToDepositInitialPairedFunds();
/// @dev Thrown when the paired token value fails to transfer to or from a pool.
error TokenMasterRouter__FailedToTransferPairedToken();
/// @dev Thrown when deployment signing is enabled and the supplied signature is invalid.
error TokenMasterRouter__InvalidDeploymentSignature();
/// @dev Thrown when the TokenMaster admin sets the infrastructure fee greater than 10_000 or during deployment when the current fee exceeds the max specified fee.
error TokenMasterRouter__InvalidInfrastructureFeeBPS();
/// @dev Thrown when a TokenMaster token owner attempts to accept the zero address as the new partner fee recipient.
error TokenMasterRouter__InvalidRecipient();
/// @dev Thrown when the message value for a deployment pairing with native tokens does not match the specified initial paired token to deposit.
error TokenMasterRouter__InvalidMessageValue();
/// @dev Thrown when transferring ERC20 tokens to a pool and native value is sent with the call to the router.
error TokenMasterRouter__NativeValueNotAllowedOnERC20();
/// @dev Thrown when an advanced order has expired.
error TokenMasterRouter__OrderExpired();
/// @dev Thrown when an advanced order has been disabled.
error TokenMasterRouter__OrderDisabled();
/// @dev Thrown when the amount of tokens being bought or sold on an advanced order does not meet the order's minimum amount.
error TokenMasterRouter__OrderDoesNotMeetMinimum();
/// @dev Thrown when the cumulative amount being bought, sold or spent on an advanced order exceeds the order's maximum total.
error TokenMasterRouter__OrderMaxTotalExceeded();
/// @dev Thrown when the cumulative amount being bought, sold or spent on an advanced order by a user exceeds the order's maximum for one user.
error TokenMasterRouter__OrderMaxPerWalletExceeded();
/// @dev Thrown when the supplied signature for an advanced order recovers to an address that is not authorized as an order signer.
error TokenMasterRouter__OrderSignerUnauthorized();
/// @dev Thrown when pairing with a token that has enabled pairing restrictions and the deployer or token are not specified as allowed.
error TokenMasterRouter__PairedTokenPairingRestricted();
/// @dev Thrown when attempting to use PermitC transfers with a token that is paired with the chain native token.
error TokenMasterRouter__PermitNotCompatibleWithNativeValue();
/// @dev Thrown when the permit transfer fails to execute the transfer of tokens to the pool.
error TokenMasterRouter__PermitTransferFailed();
/// @dev Thrown when deploying a token with a token factory specified that is not allowed by TokenMasterRouter.
error TokenMasterRouter__TokenFactoryNotAllowed();
/// @dev Thrown when attempting to buy, sell or spend a token that was not deployed with TokenMaster.
error TokenMasterRouter__TokenNotDeployedByTokenMaster();
/// @dev Thrown when a token has disabled transactions from untrusted channels and the call originates from a caller that is not trusted.
error TokenMasterRouter__TransactionOriginatedFromUntrustedChannel();

/// @dev Thrown when an address other than the router calls a function in a token that must be called by the router.
error TokenMasterERC20__CallerMustBeRouter();
/// @dev Thrown when attempting to withdraw an unrelated token from the pool and the address specified is the paired token.
error TokenMasterERC20__CannotWithdrawPairedToken();
/// @dev Thrown when attempting to withdraw an unrelated ERC20 token from the pool and the transfer fails.
error TokenMasterERC20__ERC20TransferFailed();
/// @dev Thrown when attempting to reset the token approval for the router to transfer paired tokens and the approval fails.
error TokenMasterERC20__FailedToSetApproval();
/// @dev Thrown when attempting to forfeit claimable emissions in an amount greater than the current claimable amount.
error TokenMasterERC20__ForfeitAmountGreaterThanClaimable();
/// @dev Thrown when the initial paired amount supplied is zero.
error TokenMasterERC20__InitialPairedDepositCannotBeZero();
/// @dev Thrown when the initial supply amount specified is zero.
error TokenMasterERC20__InitialSupplyCannotBeZero();
/// @dev Thrown when the amount of value supplied for a purchase of tokens is insufficient for the cost.
error TokenMasterERC20__InsufficientBuyInput();
/// @dev Thrown when the output value of paired tokens does not meet the sellers supplied minimum output.
error TokenMasterERC20__InsufficientSellOutput();
/// @dev Thrown when attempting to deploy or purchase an exceptionally large quantity of tokens that could destablize the token.
error TokenMasterERC20__InvalidPairedValues();
/// @dev Thrown when parameters that are being set are not within a valid range.
error TokenMasterERC20__InvalidParameters();
/// @dev Thrown when a transfer of native token value fails to execute.
error TokenMasterERC20__NativeTransferFailed();
/// @dev Thrown when adjusting the hard cap on claimable emissions and the value supplied is greater than the current cap.
error TokenMasterERC20__NewHardCapGreaterThanCurrent();
/// @dev Thrown when attempting to renounce ownership of a token contract.
error TokenMasterERC20__RenounceNotAllowed();
/// @dev Thrown when attempting to withdraw or transfer a creator share to market in an amount greater than the current creator share.
error TokenMasterERC20__WithdrawOrTransferAmountGreaterThanShare();

/// @dev Thrown when calling a function in a token contract that is not supported by the pool type.
error TokenMasterERC20__OperationNotSupportedByPool();
/// @dev Thrown when deploying a pool and an insufficient amount of value is provided for the initial supply requested.
error TokenMasterERC20__InsufficientSeedFunding();
/// @dev Thrown when multiple arrays are expected to be of equal lengths and their lengths are not equal.
error TokenMasterERC20__ArrayLengthMismatch();

File 28 of 35 : ITokenMasterBuyHook.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

/**
 * @title  ITokenMasterBuyHook
 * @author Limit Break, Inc.
 * @notice Interface that must be implemented by contracts acting as a buy hook 
 * @notice for advanced buy orders.
 */
interface ITokenMasterBuyHook {
    function tokenMasterBuyHook(
        address tokenMasterToken,
        address buyer,
        bytes32 creatorBuyIdentifier,
        uint256 amountPurchased,
        bytes calldata hookExtraData
    ) external;
}

File 29 of 35 : ITokenMasterERC20C.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

/**
 * @title  ITokenMasterERC20C
 * @author Limit Break, Inc.
 * @notice Interface that must be implemented by token contracts that will be
 * @notice deployed through TokenMasterRouter.
 */
interface ITokenMasterERC20C {

    /// @dev Emitted when a creator withdraws their share or when fees are withdrawn.
    event CreatorShareWithdrawn(address to, uint256 withdrawAmount, uint256 infrastructureAmount, uint256 partnerAmount);

    /// @dev Emitted when a creator transfers a portion of their share to the market bonded value. Infrastructure and partner amounts are transferred to their respective receivers.
    event CreatorShareTransferredToMarket(address to, uint256 transferAmount, uint256 infrastructureAmount, uint256 partnerAmount);
    
    function PAIRED_TOKEN() external view returns(address);
    function buyTokens(
        address buyer,
        uint256 pairedTokenIn,
        uint256 pooledTokenToBuy
    ) external payable returns(uint256 totalCost, uint256 refundByRouterAmount);
    function sellTokens(
        address seller,
        uint256 pooledTokenToSell,
        uint256 pairedTokenMinimumOut
    ) external returns (address pairedToken, uint256 pairedValueToSeller, uint256 transferByRouterAmount);
    function spendTokens(address spender, uint256 pooledTokenToSpend) external;
    function withdrawCreatorShare(
        address withdrawTo,
        uint256 withdrawAmount,
        address infrastructureFeeRecipient,
        address partnerFeeRecipient
    ) external returns (
        address pairedToken,
        uint256 transferByRouterAmountCreator,
        uint256 transferByRouterAmountInfrastructure,
        uint256 transferByRouterAmountPartner
    );
    function transferCreatorShareToMarket(
        uint256 transferAmount,
        address infrastructureFeeRecipient,
        address partnerFeeRecipient
    ) external returns(address pairedToken, uint256 transferByRouterAmountInfrastructure, uint256 transferByRouterAmountPartner);
    function withdrawFees(
        address infrastructureFeeRecipient,
        address partnerFeeRecipient
    ) external returns (
        address pairedToken,
        uint256 transferByRouterAmountInfrastructure,
        uint256 transferByRouterAmountPartner
    );
    function withdrawUnrelatedToken(address tokenAddress, address withdrawTo, uint256 withdrawAmount) external;
    function resetPairedTokenApproval() external;
    function pairedTokenShares() external view returns(uint256 marketShare, uint256 creatorShare, uint256 infrastructureShare, uint256 partnerShare);
}

File 30 of 35 : ITokenMasterFactory.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

import "../DataTypes.sol";

/**
 * @title  ITokenMasterFactory
 * @author Limit Break, Inc.
 * @notice Interface that must be implemented by contracts that are factories
 * @notice for tokens that will be deployed through TokenMasterRouter.
 */
interface ITokenMasterFactory {
    function deployToken(
        bytes32 tokenSalt,
        PoolDeploymentParameters calldata poolParams,
        uint256 pairedValueIn,
        uint256 infrastructureFeeBPS
    ) external returns(address deployedAddress);

    function computeDeploymentAddress(
        bytes32 tokenSalt,
        PoolDeploymentParameters calldata poolParams,
        uint256 pairedValueIn,
        uint256 infrastructureFeeBPS
    ) external view returns(address deploymentAddress);
}

File 31 of 35 : ITokenMasterOracle.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

/**
 * @title  ITokenMasterOracle
 * @author Limit Break, Inc.
 * @notice Interface that must be implemented by contracts acting as an oracle
 * @notice for advanced orders.
 */
interface ITokenMasterOracle {
    function adjustValue(
        uint256 transactionType,
        address executor,
        address tokenMasterToken,
        address baseToken,
        uint256 baseValue,
        bytes calldata oracleExtraData
    ) external view returns(uint256 tokenValue);
}

File 32 of 35 : ITokenMasterRouter.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

import "../DataTypes.sol";
import "./ITokenMasterERC20C.sol";

/**
 * @title  ITokenMasterRouter
 * @author Limit Break, Inc.
 * @notice Interface definition for the TokenMasterRouter contract.
 */
interface ITokenMasterRouter {
    /// @dev Emitted when the TokenMaster admin updates the infrastructure fee for new token deployments.
    event InfrastructureFeeUpdated(uint16 infrastructureFeeBPS);

    /// @dev Emitted when the TokenMaster admin updates an allowed token factory.
    event AllowedTokenFactoryUpdated(address indexed tokenFactory, bool allowed);

    /// @dev Emitted when a token has been deployed.
    event TokenMasterTokenDeployed(address indexed tokenMasterToken, address indexed pairedToken, address indexed tokenFactory);

    /// @dev Emitted when a token's settings have been updated.
    event TokenSettingsUpdated(
        address indexed tokenMasterToken,
        bool blockTransactionsFromUntrustedChannels,
        bool restrictPairingToLists
    );

    /// @dev Emitted when a trusted channel has been added or removed.
    event TrustedChannelUpdated(
        address indexed tokenAddress,
        address indexed channel,
        bool allowed
    );

    /// @dev Emitted when a token's partner has proposed a new fee recipient address.
    event PartnerFeeRecipientProposed(
        address indexed tokenAddress,
        address proposedPartnerFeeRecipient
    );

    /// @dev Emitted when the creator has accepted the token partner's proposed fee recipient address.
    event PartnerFeeRecipientUpdated(
        address indexed tokenAddress,
        address partnerFeeRecipient
    );

    /// @dev Emitted when a deployer has been added or removed as an allowed deployer for tokens pairing to a creator's token.
    event AllowedPairToDeployersUpdated(
        address indexed tokenAddress,
        address indexed deployer,
        bool allowed
    );

    /// @dev Emitted when a specific token has been added or removed as an allowed token for pairing to a creator's token.
    event AllowedPairToTokensUpdated(
        address indexed tokenAddress,
        address indexed tokenAllowedToPair,
        bool allowed
    );

    /// @dev Emitted when a buy tokens order has been filled.
    event BuyOrderFilled(
        address indexed tokenMasterToken,
        address indexed buyer,
        uint256 amountPurchased,
        uint256 totalCost
    );

    /// @dev Emitted when a sell tokens order has been filled.
    event SellOrderFilled(
        address indexed tokenMasterToken,
        address indexed seller,
        uint256 amountSold,
        uint256 totalReceived
    );

    /// @dev Emitted when a spend tokens order has been filled.
    event SpendOrderFilled(
        address indexed tokenMasterToken,
        bytes32 indexed creatorSpendIdentifier,
        address indexed spender,
        uint256 amountSpent,
        uint256 multiplier
    );

    /// @dev Emitted when a order signer has been updated.
    event OrderSignerUpdated(
        address indexed tokenMasterToken,
        address indexed signer,
        bool allowed
    );

    /// @dev Emitted when an advanced buy order has been disabled or enabled.
    event BuyOrderDisabled(
        address indexed tokenMasterToken,
        bytes32 indexed creatorBuyIdentifier,
        bool disabled
    );

    /// @dev Emitted when an advanced sell order has been disabled or enabled.
    event SellOrderDisabled(
        address indexed tokenMasterToken,
        bytes32 indexed creatorSellIdentifier,
        bool disabled
    );

    /// @dev Emitted when an spend order has been disabled or enabled.
    event SpendOrderDisabled(
        address indexed tokenMasterToken,
        bytes32 indexed creatorSpendIdentifier,
        bool disabled
    );

    function buyTokens(BuyOrder calldata buyOrder) external payable;
    function buyTokensAdvanced(
        BuyOrder calldata buyOrder,
        SignedOrder calldata signedOrder,
        PermitTransfer calldata permitTransfer
    ) external payable;
    function sellTokens(SellOrder calldata sellOrder) external;
    function sellTokensAdvanced(SellOrder calldata sellOrder, SignedOrder calldata signedOrder) external;
    function spendTokens(
        SpendOrder calldata spendOrder,
        SignedOrder calldata signedOrder
    ) external;
    function deployToken(
        DeploymentParameters calldata deploymentParameters,
        SignatureECDSA calldata signature
    ) external payable;
    function updateTokenSettings(
        address tokenAddress,
        bool blockTransactionsFromUntrustedChannels,
        bool restrictPairingToLists
    ) external;
    function setOrderSigner(address tokenMasterToken, address signer, bool allowed) external;
    function setTokenAllowedPairToDeployer(address tokenAddress, address deployer, bool allowed) external;
    function setTokenAllowedPairToToken(address tokenAddress, address tokenAllowedToPair, bool allowed) external;
    function disableBuyOrder(address tokenMasterToken, SignedOrder calldata signedOrder, bool disabled) external;
    function disableSellOrder(address tokenMasterToken, SignedOrder calldata signedOrder, bool disabled) external;
    function disableSpendOrder(address tokenMasterToken, SignedOrder calldata signedOrder, bool disabled) external;
    function withdrawCreatorShare(ITokenMasterERC20C tokenMasterToken, address withdrawTo, uint256 withdrawAmount) external;
    function transferCreatorShareToMarket(ITokenMasterERC20C tokenMasterToken, uint256 transferAmount) external;
    function acceptProposedPartnerFeeReceiver(address tokenMasterToken, address expectedPartnerFeeRecipient) external;
    function partnerProposeFeeReceiver(address tokenMasterToken, address proposedPartnerFeeRecipient) external;
    function setAllowedTokenFactory(address tokenFactory, bool allowed) external;
    function setInfrastructureFee(uint16 _infrastructureFeeBPS) external;
    function withdrawFees(ITokenMasterERC20C[] calldata tokenMasterTokens) external;
    function getBuyTrackingData(
        address tokenMasterToken,
        SignedOrder calldata signedOrder,
        address buyer
    ) external view returns (
        uint256 totalBought,
        uint256 totalWalletBought,
        bool orderDisabled,
        bool signatureValid,
        bool cosignatureValid
    );
    function getSellTrackingData(
        address tokenMasterToken,
        SignedOrder calldata signedOrder,
        address seller
    ) external view returns (
        uint256 totalSold,
        uint256 totalWalletSold,
        bool orderDisabled,
        bool signatureValid,
        bool cosignatureValid
    );
    function getSpendTrackingData(
        address tokenMasterToken,
        SignedOrder calldata signedOrder,
        address spender
    ) external view returns (
        uint256 totalMultipliersSpent,
        uint256 totalWalletMultipliersSpent,
        bool orderDisabled,
        bool signatureValid,
        bool cosignatureValid
    );
    function getTokenSettings(
        address tokenAddress
    ) external view returns (
        bool deployedByTokenMaster,
        bool blockTransactionsFromUntrustedChannels,
        bool restrictPairingToLists,
        address partnerFeeRecipient
    );
    function getOrderSigners(address tokenMasterToken) external view returns (address[] memory orderSigners);
    function getTrustedChannels(address tokenMasterToken) external view returns (address[] memory trustedChannels);
    function getAllowedPairToDeployers(address tokenMasterToken) external view returns (address[] memory allowedPairToDeployers);
    function getAllowedPairToTokens(address tokenMasterToken) external view returns (address[] memory allowedPairToTokens);
}

File 33 of 35 : ITokenMasterSellHook.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

/**
 * @title  ITokenMasterSellHook
 * @author Limit Break, Inc.
 * @notice Interface that must be implemented by contracts acting as a sell hook 
 * @notice for advanced sell orders.
 */
interface ITokenMasterSellHook {
    function tokenMasterSellHook(
        address tokenMasterToken,
        address seller,
        bytes32 creatorSellIdentifier,
        uint256 amountSold,
        bytes calldata hookExtraData
    ) external;
}

File 34 of 35 : ITokenMasterSpendHook.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

/**
 * @title  ITokenMasterSpendHook
 * @author Limit Break, Inc.
 * @notice Interface that must be implemented by contracts acting as a spend hook 
 * @notice for spend orders.
 */
interface ITokenMasterSpendHook {
    function tokenMasterSpendHook(
        address tokenMasterToken,
        address spender,
        bytes32 creatorSpendIdentifier,
        uint256 multiplier,
        bytes calldata hookExtraData
    ) external;
}

File 35 of 35 : LibOwnership.sol
//SPDX-License-Identifier: LicenseRef-PolyForm-Strict-1.0.0
pragma solidity 0.8.24;

library LibOwnership {

    bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;
    error Ownership__CallerIsNotTokenOrOwnerOrAdmin();
    error Ownership__CallerIsNotTokenOrOwnerOrAdminOrRole();

    /**
     * @notice Reverts the transaction if the caller is not the owner or assigned the default
     * @notice admin role of the contract at `tokenAddress`.
     *
     * @dev    Throws when the caller is neither owner nor assigned the default admin role.
     * 
     * @param tokenAddress The contract address of the token to check permissions for.
     */
    function requireCallerIsTokenOrContractOwnerOrAdmin(address tokenAddress) internal view {
        if (msg.sender == tokenAddress) {
            return;
        }

        (address contractOwner,) = safeOwner(tokenAddress);
        if (msg.sender == contractOwner) {
            return;
        }

        (bool callerIsContractAdmin,) = safeHasRole(tokenAddress, DEFAULT_ACCESS_CONTROL_ADMIN_ROLE, msg.sender);
        if (callerIsContractAdmin) {
            return;
        }

        revert Ownership__CallerIsNotTokenOrOwnerOrAdmin();
    }

    /**
     * @notice Returns if the caller is the token contract, owner or assigned the default
     * @notice admin role of the contract at `tokenAddress`.
     * 
     * @param caller       The address calling the contract
     * @param tokenAddress The contract address of the token to check permissions for.
     * 
     * @return isTokenOwnerOrAdmin True if caller is token, owner or admin, false otherwise
     */
    function isCallerTokenOrContractOwnerOrAdmin(
        address caller,
        address tokenAddress
    ) internal view returns (bool isTokenOwnerOrAdmin) {
        if (caller == tokenAddress) {
            return true;
        }

        (address contractOwner,) = safeOwner(tokenAddress);
        if (caller == contractOwner) {
            return true;
        }

        (bool callerIsContractAdmin,) = safeHasRole(tokenAddress, DEFAULT_ACCESS_CONTROL_ADMIN_ROLE, caller);
        return callerIsContractAdmin;
    }

    /**
     * @notice Reverts the transaction if the caller is not the owner or assigned the default
     * @notice admin role of the contract at `tokenAddress`.
     *
     * @dev    Throws when the caller is neither owner nor assigned the default admin role.
     * 
     * @param tokenAddress The contract address of the token to check permissions for.
     */
    function requireCallerIsTokenOrContractOwnerOrAdminOrRole(address tokenAddress, bytes32 role) internal view {        
        if (msg.sender == tokenAddress) {
            return;
        }

        (address contractOwner,) = safeOwner(tokenAddress);
        if (msg.sender == contractOwner) {
            return;
        }

        (bool callerIsContractAdmin,) = safeHasRole(tokenAddress, DEFAULT_ACCESS_CONTROL_ADMIN_ROLE, msg.sender);
        if (callerIsContractAdmin) {
            return;
        }

        (bool callerHasRole,) = safeHasRole(tokenAddress, role, msg.sender);
        if (callerHasRole) {
            return;
        }

        revert Ownership__CallerIsNotTokenOrOwnerOrAdminOrRole();
    }

    /**
     * @dev A gas efficient, and fallback-safe way to call the owner function on a token contract.
     *      This will get the owner if it exists - and when the function is unimplemented, the
     *      presence of a fallback function will not result in halted execution.
     * 
     * @param tokenAddress  The address of the token collection to get the owner of.
     * 
     * @return owner   The owner of the token collection contract.
     * @return isError True if there was an error in retrieving the owner, false if the call was successful.
     */
    function safeOwner(
        address tokenAddress
    ) private view returns(address owner, bool isError) {
        assembly ("memory-safe") {
            function _callOwner(_tokenAddress) -> _owner, _isError {
                mstore(0x00, 0x8da5cb5b)
                if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _tokenAddress, 0x1C, 0x04, 0x00, 0x20)) {
                    _owner := mload(0x00)
                    leave
                }
                _isError := true
            }
            owner, isError := _callOwner(tokenAddress)
        }
    }
    
    /**
     * @dev A gas efficient, and fallback-safe way to call the hasRole function on a token contract.
     *      This will check if the account `hasRole` if `hasRole` exists - and when the function is unimplemented, the
     *      presence of a fallback function will not result in halted execution.
     * 
     * @param tokenAddress  The address of the token collection to call hasRole on.
     * @param role          The role to check if the account has on the collection.
     * @param account       The address of the account to check if they have a specified role.
     * 
     * @return hasRole The owner of the token collection contract.
     * @return isError True if there was an error in retrieving the owner, false if the call was successful.
     */
    function safeHasRole(
        address tokenAddress,
        bytes32 role,
        address account
    ) private view returns(bool hasRole, bool isError) {
        assembly ("memory-safe") {
            function _callHasRole(_tokenAddress, _role, _account) -> _hasRole, _isError {
                let ptr := mload(0x40)
                mstore(0x40, add(ptr, 0x60))
                mstore(ptr, 0x91d14854)
                mstore(add(0x20, ptr), _role)
                mstore(add(0x40, ptr), _account)
                if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _tokenAddress, add(ptr, 0x1C), 0x44, 0x00, 0x20)) {
                    _hasRole := mload(0x00)
                    leave
                }
                _isError := true
            }
            hasRole, isError := _callHasRole(tokenAddress, role, account)
        }
    }
}

Settings
{
  "remappings": [
    "@limitbreak/tm-core-lib/=lib/tm-core-lib/",
    "@limitbreak/permit-c/=lib/PermitC/src/",
    "@limitbreak/trusted-forwarder/=lib/TrustedForwarder/src/",
    "@limitbreak/tm-role-server/=lib/tm-role-server/src/",
    "@limitbreak/creator-token-transfer-validator/=lib/creator-token-transfer-validator/src/",
    "@openzeppelin/=lib/TrustedForwarder/lib/openzeppelin-contracts/",
    "@rari-capital/solmate/=lib/PermitC/lib/solmate/",
    "PermitC/=lib/PermitC/",
    "TrustedForwarder/=lib/TrustedForwarder/",
    "creator-token-transfer-validator/=lib/creator-token-transfer-validator/src/",
    "ds-test/=lib/tm-role-server/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/TrustedForwarder/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-metering/=lib/PermitC/lib/forge-gas-metering/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/TrustedForwarder/lib/openzeppelin-contracts/",
    "openzeppelin/=lib/TrustedForwarder/lib/openzeppelin-contracts/contracts/",
    "solady/=lib/PermitC/lib/forge-gas-metering/lib/solady/",
    "solmate/=lib/PermitC/lib/solmate/src/",
    "tm-core-lib/=lib/tm-core-lib/src/",
    "tm-role-server/=lib/tm-role-server/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 9999999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"roleServer","type":"address"},{"internalType":"bytes32","name":"roleSet","type":"bytes32"},{"internalType":"address","name":"trustedForwarderFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Error__BadConstructorArgument","type":"error"},{"inputs":[],"name":"Error__InvalidSignatureV","type":"error"},{"inputs":[],"name":"OnlyDirectCalls","type":"error"},{"inputs":[],"name":"Ownership__CallerIsNotTokenOrOwnerOrAdmin","type":"error"},{"inputs":[],"name":"Ownership__CallerIsNotTokenOrOwnerOrAdminOrRole","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RoleClient__Unauthorized","type":"error"},{"inputs":[],"name":"TStoreAlreadyActivated","type":"error"},{"inputs":[],"name":"TStoreNotSupported","type":"error"},{"inputs":[],"name":"TloadTestContractDeploymentFailed","type":"error"},{"inputs":[],"name":"TokenMasterRouter__AmountToSpendExceedsMax","type":"error"},{"inputs":[],"name":"TokenMasterRouter__BadCalldataLength","type":"error"},{"inputs":[],"name":"TokenMasterRouter__CallerNotAllowed","type":"error"},{"inputs":[],"name":"TokenMasterRouter__CosignatureExpired","type":"error"},{"inputs":[],"name":"TokenMasterRouter__CosignatureInvalid","type":"error"},{"inputs":[],"name":"TokenMasterRouter__DeployedTokenAddressMismatch","type":"error"},{"inputs":[],"name":"TokenMasterRouter__FailedToDepositInitialPairedFunds","type":"error"},{"inputs":[],"name":"TokenMasterRouter__FailedToTransferPairedToken","type":"error"},{"inputs":[],"name":"TokenMasterRouter__InvalidDeploymentSignature","type":"error"},{"inputs":[],"name":"TokenMasterRouter__InvalidInfrastructureFeeBPS","type":"error"},{"inputs":[],"name":"TokenMasterRouter__InvalidMessageValue","type":"error"},{"inputs":[],"name":"TokenMasterRouter__InvalidRecipient","type":"error"},{"inputs":[],"name":"TokenMasterRouter__NativeValueNotAllowedOnERC20","type":"error"},{"inputs":[],"name":"TokenMasterRouter__OrderDisabled","type":"error"},{"inputs":[],"name":"TokenMasterRouter__OrderDoesNotMeetMinimum","type":"error"},{"inputs":[],"name":"TokenMasterRouter__OrderExpired","type":"error"},{"inputs":[],"name":"TokenMasterRouter__OrderMaxPerWalletExceeded","type":"error"},{"inputs":[],"name":"TokenMasterRouter__OrderMaxTotalExceeded","type":"error"},{"inputs":[],"name":"TokenMasterRouter__OrderSignerUnauthorized","type":"error"},{"inputs":[],"name":"TokenMasterRouter__PairedTokenPairingRestricted","type":"error"},{"inputs":[],"name":"TokenMasterRouter__PermitNotCompatibleWithNativeValue","type":"error"},{"inputs":[],"name":"TokenMasterRouter__PermitTransferFailed","type":"error"},{"inputs":[],"name":"TokenMasterRouter__TokenFactoryNotAllowed","type":"error"},{"inputs":[],"name":"TokenMasterRouter__TokenNotDeployedByTokenMaster","type":"error"},{"inputs":[],"name":"TokenMasterRouter__TransactionOriginatedFromUntrustedChannel","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowedPairToDeployersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAllowedToPair","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowedPairToTokensUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenFactory","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowedTokenFactoryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"creatorBuyIdentifier","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"disabled","type":"bool"}],"name":"BuyOrderDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountPurchased","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalCost","type":"uint256"}],"name":"BuyOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"infrastructureFeeBPS","type":"uint16"}],"name":"InfrastructureFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"OrderSignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"proposedPartnerFeeRecipient","type":"address"}],"name":"PartnerFeeRecipientProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"partnerFeeRecipient","type":"address"}],"name":"PartnerFeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"creatorSellIdentifier","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"disabled","type":"bool"}],"name":"SellOrderDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalReceived","type":"uint256"}],"name":"SellOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"creatorSpendIdentifier","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"disabled","type":"bool"}],"name":"SpendOrderDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"creatorSpendIdentifier","type":"bytes32"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"multiplier","type":"uint256"}],"name":"SpendOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":true,"internalType":"address","name":"pairedToken","type":"address"},{"indexed":true,"internalType":"address","name":"tokenFactory","type":"address"}],"name":"TokenMasterTokenDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenMasterToken","type":"address"},{"indexed":false,"internalType":"bool","name":"blockTransactionsFromUntrustedChannels","type":"bool"},{"indexed":false,"internalType":"bool","name":"restrictPairingToLists","type":"bool"}],"name":"TokenSettingsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"channel","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"TrustedChannelUpdated","type":"event"},{"inputs":[],"name":"__activateTstore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"internalType":"address","name":"expectedPartnerFeeRecipient","type":"address"}],"name":"acceptProposedPartnerFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedTokenFactory","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"internalType":"uint256","name":"tokensToBuy","type":"uint256"},{"internalType":"uint256","name":"pairedValueIn","type":"uint256"}],"internalType":"struct BuyOrder","name":"buyOrder","type":"tuple"}],"name":"buyTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"internalType":"uint256","name":"tokensToBuy","type":"uint256"},{"internalType":"uint256","name":"pairedValueIn","type":"uint256"}],"internalType":"struct BuyOrder","name":"buyOrder","type":"tuple"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"},{"components":[{"internalType":"address","name":"permitProcessor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"bytes","name":"signedPermit","type":"bytes"}],"internalType":"struct PermitTransfer","name":"permitTransfer","type":"tuple"}],"name":"buyTokensAdvanced","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenFactory","type":"address"},{"internalType":"bytes32","name":"tokenSalt","type":"bytes32"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"blockTransactionsFromUntrustedChannels","type":"bool"},{"internalType":"bool","name":"restrictPairingToLists","type":"bool"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"},{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"pairedToken","type":"address"},{"internalType":"uint256","name":"initialPairedTokenToDeposit","type":"uint256"},{"internalType":"bytes","name":"encodedInitializationArgs","type":"bytes"},{"internalType":"address","name":"defaultTransferValidator","type":"address"},{"internalType":"bool","name":"useRouterForPairedTransfers","type":"bool"},{"internalType":"address","name":"partnerFeeRecipient","type":"address"},{"internalType":"uint256","name":"partnerFeeBPS","type":"uint256"}],"internalType":"struct PoolDeploymentParameters","name":"poolParams","type":"tuple"},{"internalType":"uint16","name":"maxInfrastructureFeeBPS","type":"uint16"}],"internalType":"struct DeploymentParameters","name":"deploymentParameters","type":"tuple"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"}],"name":"deployToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"disableBuyOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"disableSellOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"disableSpendOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"}],"name":"getAllowedPairToDeployers","outputs":[{"internalType":"address[]","name":"allowedPairToDeployers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"}],"name":"getAllowedPairToTokens","outputs":[{"internalType":"address[]","name":"allowedPairToTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"},{"internalType":"address","name":"buyer","type":"address"}],"name":"getBuyTrackingData","outputs":[{"internalType":"uint256","name":"totalBought","type":"uint256"},{"internalType":"uint256","name":"totalWalletBought","type":"uint256"},{"internalType":"bool","name":"orderDisabled","type":"bool"},{"internalType":"bool","name":"signatureValid","type":"bool"},{"internalType":"bool","name":"cosignatureValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"}],"name":"getOrderSigners","outputs":[{"internalType":"address[]","name":"orderSigners","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"},{"internalType":"address","name":"seller","type":"address"}],"name":"getSellTrackingData","outputs":[{"internalType":"uint256","name":"totalSold","type":"uint256"},{"internalType":"uint256","name":"totalWalletSold","type":"uint256"},{"internalType":"bool","name":"orderDisabled","type":"bool"},{"internalType":"bool","name":"signatureValid","type":"bool"},{"internalType":"bool","name":"cosignatureValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"},{"internalType":"address","name":"spender","type":"address"}],"name":"getSpendTrackingData","outputs":[{"internalType":"uint256","name":"totalMultipliersSpent","type":"uint256"},{"internalType":"uint256","name":"totalWalletMultipliersSpent","type":"uint256"},{"internalType":"bool","name":"orderDisabled","type":"bool"},{"internalType":"bool","name":"signatureValid","type":"bool"},{"internalType":"bool","name":"cosignatureValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"getTokenSettings","outputs":[{"internalType":"bool","name":"deployedByTokenMaster","type":"bool"},{"internalType":"bool","name":"blockTransactionsFromUntrustedChannels","type":"bool"},{"internalType":"bool","name":"restrictPairingToLists","type":"bool"},{"internalType":"address","name":"partnerFeeRecipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"}],"name":"getTrustedChannels","outputs":[{"internalType":"address[]","name":"trustedChannels","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"infrastructureFeeBPS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"roleHolder","type":"address"}],"name":"onRoleHolderChanged","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"orderTracking","outputs":[{"internalType":"bool","name":"orderDisabled","type":"bool"},{"internalType":"uint256","name":"orderTotal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"internalType":"address","name":"proposedPartnerFeeRecipient","type":"address"}],"name":"partnerProposeFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"internalType":"uint256","name":"tokensToSell","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"}],"internalType":"struct SellOrder","name":"sellOrder","type":"tuple"}],"name":"sellTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"internalType":"uint256","name":"tokensToSell","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"}],"internalType":"struct SellOrder","name":"sellOrder","type":"tuple"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"}],"name":"sellTokensAdvanced","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenFactory","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setAllowedTokenFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_infrastructureFeeBPS","type":"uint16"}],"name":"setInfrastructureFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setOrderSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"deployer","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setTokenAllowedPairToDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"tokenAllowedToPair","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setTokenAllowedPairToToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"channel","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setTokenAllowedTrustedChannel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenMasterToken","type":"address"},{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint256","name":"maxAmountToSpend","type":"uint256"}],"internalType":"struct SpendOrder","name":"spendOrder","type":"tuple"},{"components":[{"internalType":"bytes32","name":"creatorIdentifier","type":"bytes32"},{"internalType":"address","name":"tokenMasterOracle","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"baseValue","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTotal","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"address","name":"hook","type":"address"},{"components":[{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signature","type":"tuple"},{"components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Cosignature","name":"cosignature","type":"tuple"},{"internalType":"bytes","name":"hookExtraData","type":"bytes"},{"internalType":"bytes","name":"oracleExtraData","type":"bytes"}],"internalType":"struct SignedOrder","name":"signedOrder","type":"tuple"}],"name":"spendTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITokenMasterERC20C","name":"tokenMasterToken","type":"address"},{"internalType":"uint256","name":"transferAmount","type":"uint256"}],"name":"transferCreatorShareToMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"blockTransactionsFromUntrustedChannels","type":"bool"},{"internalType":"bool","name":"restrictPairingToLists","type":"bool"}],"name":"updateTokenSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITokenMasterERC20C","name":"tokenMasterToken","type":"address"},{"internalType":"address","name":"withdrawTo","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"withdrawCreatorShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITokenMasterERC20C[]","name":"tokenMasterTokens","type":"address[]"}],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]

61026060405234801562000011575f80fd5b50604051620064e8380380620064e883398101604081905262000034916200069c565b60408051808201825260118152702a37b5b2b726b0b9ba32b92937baba32b960791b602080830191909152825180840190935260018352603160f81b9083015290828585816001600160a01b038116620000a15760405163191c4f4560e01b815260040160405180910390fd5b6001600160a01b0316608052620000b8816200037f565b50506001600160a01b031660a052815160208084019190912061010052815190820120610120524660e052620001516101005161012051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b60c052505f9050620001626200048b565b90506001600160a01b0381166200018c57604051632aea588760e01b815260040160405180910390fd5b6200019781620004a4565b5f8051602062006468833981519152805460ff19169115801592831790915561016091909152620002075762000506602090811b62002935176001600160401b03908116610180526200050d821b6200293c1781166101a0526200051190911b6200294017166101c05262000247565b62000517602090811b62002946176001600160401b03908116610180526200053b821b6200297b1781166101a0526200056390911b620029b417166101c0525b6001600160a01b031661014052610160516200028d576200028d7feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb89050060016101805160201c565b506040805160208082018490525f80516020620064c8833981519152828401528251808303840181526060830184528051908201206101e052608082018490525f805160206200648883398151915260a0808401919091528351808403909101815260c0830184528051908201206102005260e082018490525f8051602062006448833981519152610100808401919091528351808403909101815261012083018452805190820120610220526101408201939093525f80516020620064a88339815191526101608083019190915282518083039091018152610180909101909152805191012061024052506200071d565b6040805160208082018490525f80516020620064c88339815191528284015282518083038401815260609092019092528051910120620003c1905b5f62000587565b6040805160208082018490525f805160206200648883398151915282840152825180830384018152606090920190925280519101206200040190620003ba565b6040805160208082018490525f805160206200644883398151915282840152825180830384018152606090920190925280519101206200044490610e1062000587565b6040805160208082018490525f80516020620064a8833981519152828401528251808303840181526060909201909252805191012062000488906201518062000587565b50565b5f696002601e613d5c3d52f35f52600a60165ff0905090565b5f816001600160a01b0316600a5a620004be9190620006da565b6040515f8181818686fa925050503d805f8114620004f8576040519150601f19603f3d011682016040523d82523d5f602084013e620004fd565b606091505b50909392505050565b80825d5050565b5c90565b5f815d50565b5f80516020620064688339815191525460ff1615620005375780825d5050565b9055565b5f5f80516020620064688339815191525460ff16156200055a57505c90565b5080545b919050565b5f80516020620064688339815191525460ff161562000582575f815d50565b5f9055565b5f7fba783d0f337aa315f54f5ed7ca2c2d311b62a50e6c2536aa37414989987635c15f848152602091909152604090819020608051915163663e433560e01b8152600481018690529092506001600160a01b039091169063663e433590602401602060405180830381865afa15801562000603573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620006299190620006fa565b81546001600160a01b0391909116600160a01b600160e01b0390911617600160e01b63ffffffff9390931692830217600160a01b600160e01b031916600160a01b42939093016001600160401b03169290920291909117905550565b80516001600160a01b03811681146200055e575f80fd5b5f805f60608486031215620006af575f80fd5b620006ba8462000685565b925060208401519150620006d16040850162000685565b90509250925092565b5f82620006f557634e487b7160e01b5f52601260045260245ffd5b500490565b5f602082840312156200070b575f80fd5b620007168262000685565b9392505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e051610200516102205161024051615c62620007e65f395f611cbf01525f818161139001528181611d19015261273101525f6117c601525f8181611f0f015261202501525f50505f612cde01525f8181612d64015261320001525f6110ad01525f61113401525f61510c01525f6150e401525f61506b01525f61509301525f8181610e840152614ad701525f81816124a501526139ed0152615c625ff3fe608060405260043610610229575f3560e01c80639fbd6b2d11610131578063ddfda6ad116100ac578063fa5375fd1161007c578063fc86e5d711610062578063fc86e5d714610700578063fe2cd4ea1461071f578063febab7fa1461073e575f80fd5b8063fa5375fd146106c2578063fa61569c146106e1575f80fd5b8063ddfda6ad14610652578063dfb7091614610671578063ebd3744a14610690578063f856bd20146106af575f80fd5b8063a82f4d0211610101578063d05126f0116100e7578063d05126f0146105e6578063d74c76ba14610614578063dbd0138914610633575f80fd5b8063a82f4d021461059b578063adc6f0fa146105c7575f80fd5b80639fbd6b2d1461052b578063a03261f01461054a578063a29f4a5614610569578063a697b8c71461057c575f80fd5b8063572b6c05116101c15780637659d70f1161019157806399c565691161017757806399c56569146104ce5780639b95711f146104ed5780639de24cfa1461050c575f80fd5b80637659d70f14610483578063882b90f0146104af575f80fd5b8063572b6c05146104025780636c062a93146104315780636f8a3099146104505780637423eb3c1461046f575f80fd5b8063339d6e2c116101fc578063339d6e2c14610332578063368e8d98146103455780633a2e573e1461039457806350f66444146103e3575f80fd5b8063044792371461022d57806306e1555b1461024e5780631bbfc89e1461026d57806323dddcae14610313575b5f80fd5b348015610238575f80fd5b5061024c6102473660046151a0565b61075d565b005b348015610259575f80fd5b5061024c6102683660046151f9565b610842565b348015610278575f80fd5b506102d061028736600461524e565b73ffffffffffffffffffffffffffffffffffffffff9081165f90815260026020819052604090912080546001918201549181161515949281161515936004909116151592911690565b60408051941515855292151560208501529015159183019190915273ffffffffffffffffffffffffffffffffffffffff1660608201526080015b60405180910390f35b34801561031e575f80fd5b5061024c61032d3660046151a0565b61092b565b61024c610340366004615279565b610a02565b348015610350575f80fd5b5061037d61035f366004615293565b60036020525f90815260409020805460019091015460ff9091169082565b60408051921515835260208301919091520161030a565b34801561039f575f80fd5b506103b36103ae3660046152aa565b610ad3565b6040805195865260208601949094529115159284019290925290151560608301521515608082015260a00161030a565b3480156103ee575f80fd5b5061024c6103fd3660046152ff565b610beb565b34801561040d575f80fd5b5061042161041c36600461524e565b610e3d565b604051901515815260200161030a565b34801561043c575f80fd5b5061024c61044b3660046151f9565b610ef5565b34801561045b575f80fd5b5061024c61046a3660046151a0565b610fd4565b34801561047a575f80fd5b5061024c6110ab565b34801561048e575f80fd5b506104a261049d36600461524e565b6111e2565b60405161030a919061534b565b3480156104ba575f80fd5b5061024c6104c93660046153a4565b611215565b3480156104d9575f80fd5b5061024c6104e83660046153db565b61134d565b3480156104f8575f80fd5b506104a261050736600461524e565b611493565b348015610517575f80fd5b506103b36105263660046152aa565b6114c6565b348015610536575f80fd5b5061024c610545366004615405565b6114f7565b348015610555575f80fd5b5061024c6105643660046152ff565b6115c5565b61024c610577366004615432565b6116bb565b348015610587575f80fd5b5061024c610596366004615482565b611cb1565b3480156105a6575f80fd5b505f546105b49061ffff1681565b60405161ffff909116815260200161030a565b3480156105d2575f80fd5b506103b36105e13660046152aa565b611ed9565b3480156105f1575f80fd5b5061042161060036600461524e565b60016020525f908152604090205460ff1681565b34801561061f575f80fd5b5061024c61062e3660046154f1565b611f0a565b34801561063e575f80fd5b5061024c61064d36600461551d565b612020565b34801561065d575f80fd5b506104a261066c36600461524e565b612153565b34801561067c575f80fd5b5061024c61068b3660046151f9565b612186565b34801561069b575f80fd5b5061024c6106aa366004615279565b612265565b61024c6106bd36600461553e565b6122a3565b3480156106cd575f80fd5b5061024c6106dc3660046155a9565b61248d565b3480156106ec575f80fd5b5061024c6106fb3660046151a0565b6125e4565b34801561070b575f80fd5b506104a261071a36600461524e565b6126bb565b34801561072a575f80fd5b5061024c6107393660046155cc565b6126ee565b348015610749575f80fd5b5061024c6107583660046153a4565b612855565b610766836129e9565b80156108115773ffffffffffffffffffffffffffffffffffffffff83165f90815260026020526040902061079d9060050183612a83565b1561080c578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3de230308d4d0764777a08c77de6f714b8245b04084ff21e69fee482b62eb0183604051610803911515815260200190565b60405180910390a35b505050565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260026020526040902061079d9060050183612aab565b61086c837f3c6581d000000000000000000000000000000000000000000000000000000000612acc565b5f6108987f65549d51d8dfff0328fddb86e5cd1955c5deb61b381c98611d77ae032a5b09848585612b85565b5f8181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155915191825291925084359173ffffffffffffffffffffffffffffffffffffffff8716917f6425e9ae263933832976bbebe0ebdd5c9c4756e0d64e087a886c5b2811f2b17d91015b60405180910390a350505050565b610934836129e9565b80156109d15773ffffffffffffffffffffffffffffffffffffffff83165f90815260026020526040902061096b9060030183612a83565b1561080c578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f9ea48f1b48320f8b799b9e308f92d6c860a4767c0fc9d470bd920692f220258283604051610803911515815260200190565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260026020526040902061096b9060030183612aab565b610a0a612cb6565b5f610a156064612d8b565b90505f610a2d610a28602085018561524e565b612de2565b5090505f8173ffffffffffffffffffffffffffffffffffffffff1663c1345fcc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a9e919061560a565b90505f610ab18284868860400135612e9b565b9050610ac48385838860200135866130a5565b50505050610ad06131d8565b50565b5f805f805f80610b047f65549d51d8dfff0328fddb86e5cd1955c5deb61b381c98611d77ae032a5b09848a8a612b85565b5f8181526003602090815260408083208054600182015473ffffffffffffffffffffffffffffffffffffffff8e16865260028301909452919093205491995090975060ff1695509091504260c08a013510610bde5773ffffffffffffffffffffffffffffffffffffffff8a165f908152600260205260409020610b8f90600301836101008c01613227565b93505f610ba46101808b016101608c0161524e565b73ffffffffffffffffffffffffffffffffffffffff1603610bc85760019250610bde565b610bdb888a610100018b610160016132ff565b92505b5050939792965093509350565b610bf3612cb6565b5f610c28610c23610c15610304610c0e610220870187615625565b90506134b4565b610c0e610200860186615625565b612d8b565b90505f80610c3c610a28602087018761524e565b915091505f80610c518360030186898961351d565b915091508660400135821115610c93576040517fe8a5fc3200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f5dec8ae900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015260248201849052851690635dec8ae9906044015f604051808303815f87803b158015610d00575f80fd5b505af1158015610d12573d5f803e3d5ffd5b505f9250610d2a915050610100880160e0890161524e565b73ffffffffffffffffffffffffffffffffffffffff1614610dd357610d56610100870160e0880161524e565b73ffffffffffffffffffffffffffffffffffffffff166352eea23d8587893585610d846102008d018d615625565b6040518763ffffffff1660e01b8152600401610da5969594939291906156d4565b5f604051808303815f87803b158015610dbc575f80fd5b505af1158015610dce573d5f803e3d5ffd5b505050505b604080518381526020810183905273ffffffffffffffffffffffffffffffffffffffff80881692893592918816917f52a55a521e660b7874a8f400a869c29d6999d07667cebb5fd4ed471a277ca6ca910160405180910390a45050505050610e396131d8565b5050565b6040517f572b6c0500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063572b6c0590602401602060405180830381865afa158015610ecb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eef9190615725565b92915050565b610f1f837f3c6581d000000000000000000000000000000000000000000000000000000000612acc565b5f610f4b7ff84827146d9e16fc63c72d4a27583ebb2f2726d3b140bfed25057169c3fe0d328585612b85565b5f8181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155915191825291925084359173ffffffffffffffffffffffffffffffffffffffff8716917fe289a4b26869e106511766a87e935346f235fe5b13e033fba7c3d115922cbd8e910161091d565b610fdd836129e9565b801561107a5773ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090206110149060070183612a83565b1561080c578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167faefb6f9f05049db3265cf48d39b4b367dd297c6c53b6a7393285fb009807623d83604051610803911515815260200190565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090206110149060070183612aab565b7f0000000000000000000000000000000000000000000000000000000000000000806110f857507fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff165b1561112f576040517ff45b98b000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111587f00000000000000000000000000000000000000000000000000000000000000006138ad565b61118e576040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b0080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556111e0613918565b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020606090610eef90600301613941565b61121e826129e9565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526002602081905260409091209081015490911680158061128657508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b156112bd576040517fe17a15fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000092831681179093556002850180549092169091556040519182528516907fc99dcad3a77cdd640b0ea556cf881f2482cb6b20af93e5f778c7b6cc171beff2906020015b60405180910390a250505050565b611355612cb6565b61135e826129e9565b73ffffffffffffffffffffffffffffffffffffffff8083165f90815260026020526040812060010154909116906113b47f000000000000000000000000000000000000000000000000000000000000000061394d565b6040517f3b83daf70000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff808316602483015284811660448301529192505f9182918291881690633b83daf7906064016060604051808303815f875af1158015611437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061145b9190615740565b9194509250905081156114745761147487848685613b26565b80156114865761148687848784613b26565b5050505050610e396131d8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020606090610eef90600501613941565b5f805f805f80610b047ff84827146d9e16fc63c72d4a27583ebb2f2726d3b140bfed25057169c3fe0d328a8a612b85565b611500836129e9565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600260208190526040909120805490916115479161153f9160ff9091169086613be3565b600484613be3565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff91909116178155604080518415158152831515602082015273ffffffffffffffffffffffffffffffffffffffff8616917f4b66fff10a49d450609bce25ef49a877654e95a44a0ee1c2ac3156cc08d87cd6910161133f565b6115cd612cb6565b5f6115e8610c23610c15610304610c0e610220870187615625565b90505f806115fc610a28602087018761524e565b91509150611614828260030185886020013588613bfc565b61161f828487613f9d565b611630610100850160e0860161524e565b73ffffffffffffffffffffffffffffffffffffffff16631847f3b28385873560208a01356116626102008b018b615625565b6040518763ffffffff1660e01b8152600401611683969594939291906156d4565b5f604051808303815f87803b15801561169a575f80fd5b505af11580156116ac573d5f803e3d5ffd5b50505050505050610e396131d8565b5f611718610c236116fd6116e26103246116d860a0890189615774565b610c0e9080615625565b6116ef60a0880188615774565b610c0e906020810190615625565b61170a60a0870187615774565b610c0e9060c0810190615625565b90506117518161172e606086016040870161524e565b61173b60a0870187615774565b61174c9060a081019060800161524e565b6140da565b60015f611761602086018661524e565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f205460ff166117c0576040517f82735a4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6117ea7f000000000000000000000000000000000000000000000000000000000000000061394d565b905073ffffffffffffffffffffffffffffffffffffffff811615611813576118138484836141be565b5f61185c61182460a0870187615774565b6118359060a081019060800161524e565b611845606088016040890161524e565b8561185360a08a018a615774565b60a00135612e9b565b90505f61186c60a0870187615774565b61187d9060a081019060800161524e565b73ffffffffffffffffffffffffffffffffffffffff1603611988576118a560a0860186615774565b60a0013534146118e1576040517fe07ce87800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6118f2606087016040880161524e565b73ffffffffffffffffffffffffffffffffffffffff16346040515f6040518083038185875af1925050503d805f8114611946576040519150601f19603f3d011682016040523d82523d5f602084013e61194b565b606091505b5050905080611986576040517f36aeb2cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b5f5461ffff1661199e60e0870160c0880161551d565b61ffff168161ffff1611156119df576040517f5fd9ac3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6119ed602088018861524e565b73ffffffffffffffffffffffffffffffffffffffff166303c268e06020890135611a1a60a08b018b615774565b86866040518563ffffffff1660e01b8152600401611a3b9493929190615820565b6020604051808303815f875af1158015611a57573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a7b919061560a565b905073ffffffffffffffffffffffffffffffffffffffff81161580611adb5750611aab606088016040890161524e565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15611b12576040517fd1949e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001611b246080890160608a016159cc565b15611b2d576002175b611b3d60a0890160808a016159cc565b15611b46576004175b73ffffffffffffffffffffffffffffffffffffffff82165f90815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff8316179055611ba260a0890189615774565b611bb5906101408101906101200161524e565b73ffffffffffffffffffffffffffffffffffffffff8381165f90815260026020908152604090912060010180547fffffffffffffffffffffffff00000000000000000000000000000000000000001693909216929092179055611c1a9089018961524e565b73ffffffffffffffffffffffffffffffffffffffff16611c3d60a08a018a615774565b611c4e9060a081019060800161524e565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fd20239aa1881cf889343ab7940f6c9763c805166c1f02380585f3f76234611dd60405160405180910390a45050505050505050565b611cb9612cb6565b5f611ce37f000000000000000000000000000000000000000000000000000000000000000061394d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161490505f611d3d7f000000000000000000000000000000000000000000000000000000000000000061394d565b90505f5b83811015611ece575f858583818110611d5c57611d5c6159e7565b9050602002016020810190611d71919061524e565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526002602052604090206001810154929350911685611df4573373ffffffffffffffffffffffffffffffffffffffff821614611df4576040517f28e12d9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff255527800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015282811660248301525f91829182919087169063f2555278906044016060604051808303815f875af1158015611e6e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e929190615740565b919450925090508115611eab57611eab86848a85613b26565b8015611ebd57611ebd86848684613b26565b505050505050806001019050611d41565b505050610e396131d8565b5f805f805f80610b047f32bef578f3163409ece0dcb42bdc8ef1a50a6e97eeb7dfb7b1aacb7c04d0a61d8a8a612b85565b611f337f000000000000000000000000000000000000000000000000000000000000000061394d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611f97576040517f28e12d9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f8181526001602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527fe7c944d2b90ee92d33a0a0a415d6627e5fc30b9dbc0979227a4aed5e00646ed4910160405180910390a25050565b6120497f000000000000000000000000000000000000000000000000000000000000000061394d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146120ad576040517f28e12d9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61271061ffff821611156120ed576040517f5fd9ac3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83169081179091556040519081527f5aae10d742f3cdf67ed0303d4252cce7e6659535101255cad9d3f8de3f096ad09060200160405180910390a150565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020606090610eef90600701613941565b6121b0837f3c6581d000000000000000000000000000000000000000000000000000000000612acc565b5f6121dc7f32bef578f3163409ece0dcb42bdc8ef1a50a6e97eeb7dfb7b1aacb7c04d0a61d8585612b85565b5f8181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155915191825291925084359173ffffffffffffffffffffffffffffffffffffffff8716917fb5d8b866115f3ad5af89970a02a0004621427127009ae1ba2619e629b92d0ae1910161091d565b61226d612cb6565b5f6122786064612d8b565b90505f61228b610a28602085018561524e565b509050612299818385613f9d565b5050610ad06131d8565b6122ab612cb6565b5f6122e4610c236122d66122c86103e4610c0e6080880188615625565b610c0e610220880188615625565b610c0e610200870187615625565b90505f806122f8610a28602088018861524e565b915091505f8273ffffffffffffffffffffffffffffffffffffffff1663c1345fcc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612346573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061236a919061560a565b90505f8061237b602088018861524e565b73ffffffffffffffffffffffffffffffffffffffff16036123ad576123a68285878b60400135612e9b565b90506123be565b6123bb8583868b8b8b614214565b90505b5f806123d48686600301898d602001358d6144ed565b915091506123e586888585886130a5565b801561247e576123fc6101008a0160e08b0161524e565b73ffffffffffffffffffffffffffffffffffffffff1663de69399387898c5f0135868e80610200019061242f9190615625565b6040518763ffffffff1660e01b8152600401612450969594939291906156d4565b5f604051808303815f87803b158015612467575f80fd5b505af1158015612479573d5f803e3d5ffd5b505050505b5050505050505061080c6131d8565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146124fc576040517fbedae83200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7fba783d0f337aa315f54f5ed7ca2c2d311b62a50e6c2536aa37414989987635c15f938452602052506040909120805467ffffffffffffffff4263ffffffff7c010000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9096167fffffffffffffffffffffffff0000000000000000000000000000000000000000851681179690960416011674010000000000000000000000000000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909116909217919091179055565b6125ed836129e9565b801561268a5773ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090206126249060090183612a83565b1561080c578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f1a4871e9efff6fda48e55034e859a248a2a78790a5dc20a97819c695f789e5c483604051610803911515815260200190565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090206126249060090183612aab565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020606090610eef90600901613941565b6126f6612cb6565b6126ff836129e9565b73ffffffffffffffffffffffffffffffffffffffff8084165f90815260026020526040812060010154909116906127557f000000000000000000000000000000000000000000000000000000000000000061394d565b6040517fc747300300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015260248201869052808316604483015284811660648301529192505f91829182918291908a169063c7473003906084016080604051808303815f875af11580156127e3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128079190615a14565b93509350935093505f8311156128235761282389858a86613b26565b81156128355761283589858785613b26565b80156128475761284789858884613b26565b50505050505061080c6131d8565b73ffffffffffffffffffffffffffffffffffffffff8083165f90815260026020526040902060018101549091163381146128bb576040517f28e12d9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff858116918217909255604051908152908516907f15b8b688cfaa9d33aad24fafaa4b2222541e0048b2f2d3e0bce6e6e59f4100f09060200161133f565b80825d5050565b5c90565b5f815d50565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129775780825d5050565b9055565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129ab57505c90565b5080545b919050565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129e4575f815d50565b5f9055565b73ffffffffffffffffffffffffffffffffffffffff81163303612a095750565b5f612a13826148c4565b50905073ffffffffffffffffffffffffffffffffffffffff81163303612a37575050565b5f612a4383823361490c565b5090508015612a5157505050565b6040517f196afcf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612aa48373ffffffffffffffffffffffffffffffffffffffff8416614978565b9392505050565b5f612aa48373ffffffffffffffffffffffffffffffffffffffff84166149c4565b73ffffffffffffffffffffffffffffffffffffffff82163303612aed575050565b5f612af7836148c4565b50905073ffffffffffffffffffffffffffffffffffffffff81163303612b1c57505050565b5f612b2884823361490c565b5090508015612b375750505050565b5f612b4385853361490c565b5090508015612b53575050505050565b6040517fd188e4d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612cae612c3d85843573ffffffffffffffffffffffffffffffffffffffff8716612bb6604088016020890161524e565b73ffffffffffffffffffffffffffffffffffffffff16612bdc6060890160408a0161524e565b73ffffffffffffffffffffffffffffffffffffffff16606089013560808a013560a08b013560408051610160810182529889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e082015290565b60c0840135612c53610100860160e0870161524e565b73ffffffffffffffffffffffffffffffffffffffff16612c7b6101808701610160880161524e565b73ffffffffffffffffffffffffffffffffffffffff16610100840192909252610120830152610140820152610160902090565b949350505050565b6002612d057feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb8905007f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b03612d3c576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111e07feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb89050060027f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b3336828103908314612ddc5780601414612dd1576040517fcd7868d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612dd9614aa7565b91505b50919050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020805482919060ff811690600116612e49576040517fe8670fe200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002811615612e9557612e5f6005830133614b97565b612e95576040517f2cf00d3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50915091565b3473ffffffffffffffffffffffffffffffffffffffff851615612cae573415612ef0576040517f0d92818600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301525f91908716906370a0823190602401602060405180830381865afa158015612f5d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f819190615a50565b90505f612f9087868887614bc5565b90508015612fca576040517f8891813700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301525f91908916906370a0823190602401602060405180830381865afa158015613037573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061305b9190615a50565b905082811015613097576040517f8891813700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919091039695505050505050565b6040517fd2395dcd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015260248201859052604482018490525f91829188169063d2395dcd903490606401604080518083038185885af1158015613123573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906131489190615a67565b9092509050801561315f5761315f87848884613b26565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167ffa04dacd647c6f4bdcf015f976434bd24d44a32fdce775268f13be35ec27e86586856040516131c7929190918252602082015260400190565b60405180910390a350505050505050565b6111e07feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb89050060017f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5f60ff82351115613264576040517f8bd2b8ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f600161327085614c3a565b604080515f815260208082018084529390935260ff87351681830152918601356060830152850135608082015260a0016020604051602081039080840390855afa1580156132c0573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191506132f690508582614b97565b95945050505050565b5f428260200135101561333e576040517f1b0107aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff6040830135111561337d576040517f8bd2b8ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c080820183527f1f339a1d08c106eea6fd9baad6936fe44e1a0c1f9f79cb10ebbf5dd2292c883982528535602083810191909152808701358385015292860135606083015291840135608082015273ffffffffffffffffffffffffffffffffffffffff861660a0820152205f906133fd90614c3a565b614c3a565b905061340c602084018461524e565b73ffffffffffffffffffffffffffffffffffffffff166001828560400135866060013587608001356040515f8152602001604052604051613469949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015613489573d5f803e3d5ffd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff16149150509392505050565b5f63ffffffff8211156134f3576040517fcd7868d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b5f80428360c00135101561355d576040517fbcf7256800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6135957f65549d51d8dfff0328fddb86e5cd1955c5deb61b381c98611d77ae032a5b098461358f602088018861524e565b86612b85565b90506135a687828661010001613227565b6135dc576040517f4a4dc21200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6135ef6101808601610160870161524e565b73ffffffffffffffffffffffffffffffffffffffff16146136535761361d86856101000186610160016132ff565b613653576040517f29f75ed400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208501359150613668826060860135615ab6565b92505f61367b604086016020870161524e565b73ffffffffffffffffffffffffffffffffffffffff1614613754576136a6604085016020860161524e565b73ffffffffffffffffffffffffffffffffffffffff1663d611669f6002886136d160208a018a61524e565b6136e160608a0160408b0161524e565b886136f06102208c018c615625565b6040518863ffffffff1660e01b81526004016137129796959493929190615acd565b602060405180830381865afa15801561372d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137519190615a50565b92505b5f818152600360205260409020805460ff161561379d576040517fa67ff36b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a0850135156137fe575f8382600101546137b89190615b27565b90508560a001358111156137f8576040517f410ff87000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201555b6080850135156138a25773ffffffffffffffffffffffffffffffffffffffff87165f90815260028201602052604081205461383a908590615b27565b9050856080013581111561387a576040517fcde4897e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff88165f9081526002830160205260409020555b505094509492505050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600a5a6138d29190615b3a565b6040515f8181818686fa925050503d805f811461390a576040519150601f19603f3d011682016040523d82523d5f602084013e61390f565b606091505b50909392505050565b6111e07feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb890500614c81565b60605f612aa483614ce4565b5f8181527fba783d0f337aa315f54f5ed7ca2c2d311b62a50e6c2536aa37414989987635c160205260409020805473ffffffffffffffffffffffffffffffffffffffff81169190427401000000000000000000000000000000000000000090910467ffffffffffffffff161015612ddc576040517f663e4335000000000000000000000000000000000000000000000000000000008152600481018490527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063663e433590602401602060405180830381865afa158015613a47573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a6b919061560a565b81547fffffffff00000000000000000000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff8316908117740100000000000000000000000000000000000000007c01000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffff00000000000000000000000000000000000000009094169092179290920463ffffffff16420167ffffffffffffffff16021790915592915050565b5f613b3384868585614bc5565b90508015613bdc578473ffffffffffffffffffffffffffffffffffffffff166379e32c7b6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015613b80575f80fd5b505af1158015613b92573d5f803e3d5ffd5b50505050613ba284868585614bc5565b90508015613bdc576040517f8891813700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b5f8115613bf35750828217612aa4565b505060ff031690565b428160c001351015613c3a576040517fbcf7256800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613c667f32bef578f3163409ece0dcb42bdc8ef1a50a6e97eeb7dfb7b1aacb7c04d0a61d8784612b85565b9050613c7785828461010001613227565b613cad576040517f4a4dc21200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613cc06101808401610160850161524e565b73ffffffffffffffffffffffffffffffffffffffff1614613d2457613cee84836101000184610160016132ff565b613d24576040517f29f75ed400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608201355f613d3a604085016020860161524e565b73ffffffffffffffffffffffffffffffffffffffff1614613e0b57613d65604084016020850161524e565b73ffffffffffffffffffffffffffffffffffffffff1663d611669f6001878a613d946060890160408a0161524e565b6060890135613da76102208b018b615625565b6040518863ffffffff1660e01b8152600401613dc99796959493929190615acd565b602060405180830381865afa158015613de4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e089190615a50565b90505b80841015613e45576040517f43212e0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600360205260409020805460ff1615613e8e576040517fa67ff36b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a084013515613eef575f858260010154613ea99190615b27565b90508460a00135811115613ee9576040517f410ff87000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201555b608084013515613f935773ffffffffffffffffffffffffffffffffffffffff86165f908152600282016020526040812054613f2b908790615b27565b90508460800135811115613f6b576040517fcde4897e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87165f9081526002830160205260409020555b5050505050505050565b604080517fe4e57b9e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602084013560248301529183013560448201525f918291829187169063e4e57b9e906064016060604051808303815f875af1158015614022573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140469190615740565b9250925092508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f40c0a04f5aa39bf3bb355f059b5b9ff0f3279927e49d151cea7b028125ba9fc68660200135856040516140b8929190918252602082015260400190565b60405180910390a380156140d2576140d286848784613b26565b505050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526002602081905260409091208054909160ff82169116156141535761411d6005830133614b97565b614153576040517f2cf00d3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004811615613bdc576141668584614d3d565b613bdc576141776007830186614b97565b613bdc576141886009830185614b97565b613bdc576040517f2b88b7de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6141cb6133f885614dd9565b90506141d8818484614ebe565b61420e576040517f04987b1900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff8616614262576040517fa2e319a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301525f91908816906370a0823190602401602060405180830381865afa1580156142cf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142f39190615a50565b90505f614303602085018561524e565b73ffffffffffffffffffffffffffffffffffffffff16634be52a89898660200135876040013588606001358e8d8d6040013561433f8f8f614f8e565b7f36fabc7b52b93a3d4148cea549fc324d118a329831e5ea98e3694dd53093bc848e80608001906143709190615625565b6040518c63ffffffff1660e01b81526004016143969b9a99989796959493929190615b72565b6020604051808303815f875af11580156143b2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143d69190615725565b90508015614410576040517f4a9d52ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301525f91908a16906370a0823190602401602060405180830381865afa15801561447d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144a19190615a50565b9050828110156144dd576040517f8891813700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9190910398975050505050505050565b815f80614501610100850160e0860161524e565b73ffffffffffffffffffffffffffffffffffffffff1614801591506148ba57428360c00135101561455e576040517fbcf7256800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61458a7ff84827146d9e16fc63c72d4a27583ebb2f2726d3b140bfed25057169c3fe0d328986612b85565b905061459b87828661010001613227565b6145d1576040517f4a4dc21200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6145e46101808601610160870161524e565b73ffffffffffffffffffffffffffffffffffffffff16146146485761461286856101000186610160016132ff565b614648576040517f29f75ed400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608401355f61465e604087016020880161524e565b73ffffffffffffffffffffffffffffffffffffffff161461472e57614689604086016020870161524e565b73ffffffffffffffffffffffffffffffffffffffff1663d611669f5f898c6146b760608b0160408c0161524e565b60608b01356146ca6102208d018d615625565b6040518863ffffffff1660e01b81526004016146ec9796959493929190615acd565b602060405180830381865afa158015614707573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061472b9190615a50565b90505b80841015614768576040517f43212e0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600360205260409020805460ff16156147b1576040517fa67ff36b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a086013515614812575f8582600101546147cc9190615b27565b90508660a0013581111561480c576040517f410ff87000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201555b6080860135156148b65773ffffffffffffffffffffffffffffffffffffffff88165f90815260028201602052604081205461484e908790615b27565b9050866080013581111561488e576040517fcde4897e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89165f9081526002830160205260409020555b5050505b9550959350505050565b5f806148fa565b638da5cb5b5f525f8060205f6004601c865afa60203d101516156148f2575f519150915091565b509160019150565b614903836148cb565b91509150915091565b5f80614961565b5f80604051606081016040526391d14854815284816020015285816040015260205f6044601c8401875afa60203d10151615614953575f51925050614959565b50600190505b935093915050565b61496c838587614913565b91509150935093915050565b5f8181526001830160205260408120546149bd57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610eef565b505f610eef565b5f8181526001830160205260408120548015614a9e575f6149e6600183615bec565b85549091505f906149f990600190615bec565b9050808214614a58575f865f018281548110614a1757614a176159e7565b905f5260205f200154905080875f018481548110614a3757614a376159e7565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080614a6957614a69615bff565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610eef565b5f915050610eef565b6040517f572b6c050000000000000000000000000000000000000000000000000000000081523360048201525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063572b6c0590602401602060405180830381865afa158015614b31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614b559190615725565b15614b8d5760143610614b8d57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c90565b503390565b905090565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526001830160205260408120541515612aa4565b5f614c2e565b5f604051608081016040526323b872dd81528381602001528481604001528581606001525f806064601c84015f875af115614c225760203d1015614c13575050803b15612cae565b60205f803e50505f5115612cae565b50600195945050505050565b6132f682848688614bcb565b5f610eef614c46615068565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615614cb2578054815d50565b6040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060815f01805480602002602001604051908101604052809291908181526020018280548015614d3157602002820191905f5260205f20905b815481526020019060010190808311614d1d575b50505050509050919050565b5f8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603614d7957506001610eef565b5f614d83836148c4565b5090508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603614dc3576001915050610eef565b5f614dcf84828761490c565b5095945050505050565b5f610eef7f1859bb357b9cf600b5309096fb870e7e7516c667fc2c8d80ce139d7610462934614e0b602085018561524e565b73ffffffffffffffffffffffffffffffffffffffff166020850135614e36606087016040880161524e565b73ffffffffffffffffffffffffffffffffffffffff16614e5c60808801606089016159cc565b614e66575f614e69565b60015b60ff16614e7c60a0890160808a016159cc565b614e86575f614e89565b60015b60ff166040805160c0808201835297815260208101969096528501939093526060840191909152608083015260a08201522090565b5f60ff83351115614efb576040517f8bd2b8ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080515f8152602081810180845287905260ff86351682840152850135606082015290840135608082015260019060a0016020604051602081039080840390855afa158015614f4d573d5f803e3d5ffd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161490509392505050565b5f612aa46150547f21cb3dab0ae1a1d86be87b4c5e2d64effa64142020577b4a8381b3249476ee73614fc3602087018761524e565b73ffffffffffffffffffffffffffffffffffffffff16602087013560408801358735614ff66101008a0160e08b0161524e565b73ffffffffffffffffffffffffffffffffffffffff166101008a01356101208b013560408051610120810182529889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e082015290565b610140840135610100820152610120902090565b5f7f000000000000000000000000000000000000000000000000000000000000000046036150b557507f000000000000000000000000000000000000000000000000000000000000000090565b614b92604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b73ffffffffffffffffffffffffffffffffffffffff81168114610ad0575f80fd5b80356129af8161515c565b8015158114610ad0575f80fd5b80356129af81615188565b5f805f606084860312156151b2575f80fd5b83356151bd8161515c565b925060208401356151cd8161515c565b915060408401356151dd81615188565b809150509250925092565b5f6102408284031215612ddc575f80fd5b5f805f6060848603121561520b575f80fd5b83356152168161515c565b9250602084013567ffffffffffffffff811115615231575f80fd5b61523d868287016151e8565b92505060408401356151dd81615188565b5f6020828403121561525e575f80fd5b8135612aa48161515c565b5f60608284031215612ddc575f80fd5b5f60608284031215615289575f80fd5b612aa48383615269565b5f602082840312156152a3575f80fd5b5035919050565b5f805f606084860312156152bc575f80fd5b83356152c78161515c565b9250602084013567ffffffffffffffff8111156152e2575f80fd5b6152ee868287016151e8565b92505060408401356151dd8161515c565b5f8060808385031215615310575f80fd5b61531a8484615269565b9150606083013567ffffffffffffffff811115615335575f80fd5b615341858286016151e8565b9150509250929050565b602080825282518282018190525f9190848201906040850190845b8181101561539857835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101615366565b50909695505050505050565b5f80604083850312156153b5575f80fd5b82356153c08161515c565b915060208301356153d08161515c565b809150509250929050565b5f80604083850312156153ec575f80fd5b82356153f78161515c565b946020939093013593505050565b5f805f60608486031215615417575f80fd5b83356154228161515c565b925060208401356151cd81615188565b5f8060808385031215615443575f80fd5b823567ffffffffffffffff811115615459575f80fd5b830160e0818603121561546a575f80fd5b91506154798460208501615269565b90509250929050565b5f8060208385031215615493575f80fd5b823567ffffffffffffffff808211156154aa575f80fd5b818501915085601f8301126154bd575f80fd5b8135818111156154cb575f80fd5b8660208260051b85010111156154df575f80fd5b60209290920196919550909350505050565b5f8060408385031215615502575f80fd5b823561550d8161515c565b915060208301356153d081615188565b5f6020828403121561552d575f80fd5b813561ffff81168114612aa4575f80fd5b5f805f60a08486031215615550575f80fd5b61555a8585615269565b9250606084013567ffffffffffffffff80821115615576575f80fd5b615582878388016151e8565b93506080860135915080821115615597575f80fd5b50840160a081870312156151dd575f80fd5b5f80604083850312156155ba575f80fd5b8235915060208301356153d08161515c565b5f805f606084860312156155de575f80fd5b83356155e98161515c565b925060208401356155f98161515c565b929592945050506040919091013590565b5f6020828403121561561a575f80fd5b8151612aa48161515c565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615658575f80fd5b83018035915067ffffffffffffffff821115615672575f80fd5b602001915036819003821315615686575f80fd5b9250929050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a0608083015261571960a08301848661568d565b98975050505050505050565b5f60208284031215615735575f80fd5b8151612aa481615188565b5f805f60608486031215615752575f80fd5b835161575d8161515c565b602085015160409095015190969495509392505050565b5f82357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18336030181126157a6575f80fd5b9190910192915050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126157e3575f80fd5b830160208101925035905067ffffffffffffffff811115615802575f80fd5b803603821315615686575f80fd5b803560ff811681146129af575f80fd5b848152608060208201525f61583585866157b0565b61016080608086015261584d6101e08601838561568d565b925061585c60208901896157b0565b92507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808786030160a088015261589485858461568d565b94506158a260408b01615810565b60ff811660c089015293506158b960608b0161517d565b73ffffffffffffffffffffffffffffffffffffffff811660e089015293506158e360808b0161517d565b9350610100915061590b8288018573ffffffffffffffffffffffffffffffffffffffff169052565b610120935060a08a01358488015261592660c08b018b6157b0565b610140838a890301818b015261593d88838561568d565b975061594b60e08e0161517d565b73ffffffffffffffffffffffffffffffffffffffff81168b8801529350615973858e01615195565b8015156101808c01529550615989878e0161517d565b73ffffffffffffffffffffffffffffffffffffffff166101a08b01528c01356101c08a01525050505060408501879052505061ffff8416606084015290506132f6565b5f602082840312156159dc575f80fd5b8135612aa481615188565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f805f8060808587031215615a27575f80fd5b8451615a328161515c565b60208601516040870151606090970151919890975090945092505050565b5f60208284031215615a60575f80fd5b5051919050565b5f8060408385031215615a78575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082028115828204841417610eef57610eef615a89565b8781525f73ffffffffffffffffffffffffffffffffffffffff8089166020840152808816604084015280871660608401525084608083015260c060a0830152615b1a60c08301848661568d565b9998505050505050505050565b80820180821115610eef57610eef615a89565b5f82615b6d577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f61014073ffffffffffffffffffffffffffffffffffffffff808f1684528d60208501528c60408501528b6060850152808b166080850152808a1660a0850152508760c08401528660e08401528561010084015280610120840152615bda818401858761568d565b9e9d5050505050505050505050505050565b81810381811115610eef57610eef615a89565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212207cae73b79dc90cd174a99f75d535d37855c1458da313e1a09b872b7a98efbebc64736f6c6343000818003302e481a6d68a937191a7130aa2606d3b2b9877012867537cca9f6797c8c231bcdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b002f097bc6c188e7bc2a6d388a0e3e06653b55843c9fcf3d8dbd94cdb88b1f6f11b48cfd53b97752d680deb111c7652f4dfe83be5c6ca32a40d6b05933ad304dd20c8f53213d5eba3e8e496f5a9a7d0bf26b7583f9cdc230c1338eefd4429ae4bf00000000000000000000000000000000d7b37203f54e165fb204b57c30d15835755567e1f0e12dc4d7f3efea8a543338d6d0b9d983517c6bed1224aac0f0ba63000000000000000000000000ff0000b6c4352714cce809000d0cd30a0e0c8dce

Deployed Bytecode

0x608060405260043610610229575f3560e01c80639fbd6b2d11610131578063ddfda6ad116100ac578063fa5375fd1161007c578063fc86e5d711610062578063fc86e5d714610700578063fe2cd4ea1461071f578063febab7fa1461073e575f80fd5b8063fa5375fd146106c2578063fa61569c146106e1575f80fd5b8063ddfda6ad14610652578063dfb7091614610671578063ebd3744a14610690578063f856bd20146106af575f80fd5b8063a82f4d0211610101578063d05126f0116100e7578063d05126f0146105e6578063d74c76ba14610614578063dbd0138914610633575f80fd5b8063a82f4d021461059b578063adc6f0fa146105c7575f80fd5b80639fbd6b2d1461052b578063a03261f01461054a578063a29f4a5614610569578063a697b8c71461057c575f80fd5b8063572b6c05116101c15780637659d70f1161019157806399c565691161017757806399c56569146104ce5780639b95711f146104ed5780639de24cfa1461050c575f80fd5b80637659d70f14610483578063882b90f0146104af575f80fd5b8063572b6c05146104025780636c062a93146104315780636f8a3099146104505780637423eb3c1461046f575f80fd5b8063339d6e2c116101fc578063339d6e2c14610332578063368e8d98146103455780633a2e573e1461039457806350f66444146103e3575f80fd5b8063044792371461022d57806306e1555b1461024e5780631bbfc89e1461026d57806323dddcae14610313575b5f80fd5b348015610238575f80fd5b5061024c6102473660046151a0565b61075d565b005b348015610259575f80fd5b5061024c6102683660046151f9565b610842565b348015610278575f80fd5b506102d061028736600461524e565b73ffffffffffffffffffffffffffffffffffffffff9081165f90815260026020819052604090912080546001918201549181161515949281161515936004909116151592911690565b60408051941515855292151560208501529015159183019190915273ffffffffffffffffffffffffffffffffffffffff1660608201526080015b60405180910390f35b34801561031e575f80fd5b5061024c61032d3660046151a0565b61092b565b61024c610340366004615279565b610a02565b348015610350575f80fd5b5061037d61035f366004615293565b60036020525f90815260409020805460019091015460ff9091169082565b60408051921515835260208301919091520161030a565b34801561039f575f80fd5b506103b36103ae3660046152aa565b610ad3565b6040805195865260208601949094529115159284019290925290151560608301521515608082015260a00161030a565b3480156103ee575f80fd5b5061024c6103fd3660046152ff565b610beb565b34801561040d575f80fd5b5061042161041c36600461524e565b610e3d565b604051901515815260200161030a565b34801561043c575f80fd5b5061024c61044b3660046151f9565b610ef5565b34801561045b575f80fd5b5061024c61046a3660046151a0565b610fd4565b34801561047a575f80fd5b5061024c6110ab565b34801561048e575f80fd5b506104a261049d36600461524e565b6111e2565b60405161030a919061534b565b3480156104ba575f80fd5b5061024c6104c93660046153a4565b611215565b3480156104d9575f80fd5b5061024c6104e83660046153db565b61134d565b3480156104f8575f80fd5b506104a261050736600461524e565b611493565b348015610517575f80fd5b506103b36105263660046152aa565b6114c6565b348015610536575f80fd5b5061024c610545366004615405565b6114f7565b348015610555575f80fd5b5061024c6105643660046152ff565b6115c5565b61024c610577366004615432565b6116bb565b348015610587575f80fd5b5061024c610596366004615482565b611cb1565b3480156105a6575f80fd5b505f546105b49061ffff1681565b60405161ffff909116815260200161030a565b3480156105d2575f80fd5b506103b36105e13660046152aa565b611ed9565b3480156105f1575f80fd5b5061042161060036600461524e565b60016020525f908152604090205460ff1681565b34801561061f575f80fd5b5061024c61062e3660046154f1565b611f0a565b34801561063e575f80fd5b5061024c61064d36600461551d565b612020565b34801561065d575f80fd5b506104a261066c36600461524e565b612153565b34801561067c575f80fd5b5061024c61068b3660046151f9565b612186565b34801561069b575f80fd5b5061024c6106aa366004615279565b612265565b61024c6106bd36600461553e565b6122a3565b3480156106cd575f80fd5b5061024c6106dc3660046155a9565b61248d565b3480156106ec575f80fd5b5061024c6106fb3660046151a0565b6125e4565b34801561070b575f80fd5b506104a261071a36600461524e565b6126bb565b34801561072a575f80fd5b5061024c6107393660046155cc565b6126ee565b348015610749575f80fd5b5061024c6107583660046153a4565b612855565b610766836129e9565b80156108115773ffffffffffffffffffffffffffffffffffffffff83165f90815260026020526040902061079d9060050183612a83565b1561080c578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3de230308d4d0764777a08c77de6f714b8245b04084ff21e69fee482b62eb0183604051610803911515815260200190565b60405180910390a35b505050565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260026020526040902061079d9060050183612aab565b61086c837f3c6581d000000000000000000000000000000000000000000000000000000000612acc565b5f6108987f65549d51d8dfff0328fddb86e5cd1955c5deb61b381c98611d77ae032a5b09848585612b85565b5f8181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155915191825291925084359173ffffffffffffffffffffffffffffffffffffffff8716917f6425e9ae263933832976bbebe0ebdd5c9c4756e0d64e087a886c5b2811f2b17d91015b60405180910390a350505050565b610934836129e9565b80156109d15773ffffffffffffffffffffffffffffffffffffffff83165f90815260026020526040902061096b9060030183612a83565b1561080c578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f9ea48f1b48320f8b799b9e308f92d6c860a4767c0fc9d470bd920692f220258283604051610803911515815260200190565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260026020526040902061096b9060030183612aab565b610a0a612cb6565b5f610a156064612d8b565b90505f610a2d610a28602085018561524e565b612de2565b5090505f8173ffffffffffffffffffffffffffffffffffffffff1663c1345fcc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a9e919061560a565b90505f610ab18284868860400135612e9b565b9050610ac48385838860200135866130a5565b50505050610ad06131d8565b50565b5f805f805f80610b047f65549d51d8dfff0328fddb86e5cd1955c5deb61b381c98611d77ae032a5b09848a8a612b85565b5f8181526003602090815260408083208054600182015473ffffffffffffffffffffffffffffffffffffffff8e16865260028301909452919093205491995090975060ff1695509091504260c08a013510610bde5773ffffffffffffffffffffffffffffffffffffffff8a165f908152600260205260409020610b8f90600301836101008c01613227565b93505f610ba46101808b016101608c0161524e565b73ffffffffffffffffffffffffffffffffffffffff1603610bc85760019250610bde565b610bdb888a610100018b610160016132ff565b92505b5050939792965093509350565b610bf3612cb6565b5f610c28610c23610c15610304610c0e610220870187615625565b90506134b4565b610c0e610200860186615625565b612d8b565b90505f80610c3c610a28602087018761524e565b915091505f80610c518360030186898961351d565b915091508660400135821115610c93576040517fe8a5fc3200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f5dec8ae900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015260248201849052851690635dec8ae9906044015f604051808303815f87803b158015610d00575f80fd5b505af1158015610d12573d5f803e3d5ffd5b505f9250610d2a915050610100880160e0890161524e565b73ffffffffffffffffffffffffffffffffffffffff1614610dd357610d56610100870160e0880161524e565b73ffffffffffffffffffffffffffffffffffffffff166352eea23d8587893585610d846102008d018d615625565b6040518763ffffffff1660e01b8152600401610da5969594939291906156d4565b5f604051808303815f87803b158015610dbc575f80fd5b505af1158015610dce573d5f803e3d5ffd5b505050505b604080518381526020810183905273ffffffffffffffffffffffffffffffffffffffff80881692893592918816917f52a55a521e660b7874a8f400a869c29d6999d07667cebb5fd4ed471a277ca6ca910160405180910390a45050505050610e396131d8565b5050565b6040517f572b6c0500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f000000000000000000000000ff0000b6c4352714cce809000d0cd30a0e0c8dce9091169063572b6c0590602401602060405180830381865afa158015610ecb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eef9190615725565b92915050565b610f1f837f3c6581d000000000000000000000000000000000000000000000000000000000612acc565b5f610f4b7ff84827146d9e16fc63c72d4a27583ebb2f2726d3b140bfed25057169c3fe0d328585612b85565b5f8181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155915191825291925084359173ffffffffffffffffffffffffffffffffffffffff8716917fe289a4b26869e106511766a87e935346f235fe5b13e033fba7c3d115922cbd8e910161091d565b610fdd836129e9565b801561107a5773ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090206110149060070183612a83565b1561080c578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167faefb6f9f05049db3265cf48d39b4b367dd297c6c53b6a7393285fb009807623d83604051610803911515815260200190565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090206110149060070183612aab565b7f0000000000000000000000000000000000000000000000000000000000000001806110f857507fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff165b1561112f576040517ff45b98b000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111587f0000000000000000000000002827cd34523baa618f03cc8ffb9105114f9909526138ad565b61118e576040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b0080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556111e0613918565b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020606090610eef90600301613941565b61121e826129e9565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526002602081905260409091209081015490911680158061128657508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b156112bd576040517fe17a15fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000092831681179093556002850180549092169091556040519182528516907fc99dcad3a77cdd640b0ea556cf881f2482cb6b20af93e5f778c7b6cc171beff2906020015b60405180910390a250505050565b611355612cb6565b61135e826129e9565b73ffffffffffffffffffffffffffffffffffffffff8083165f90815260026020526040812060010154909116906113b47fc23a207f9f3535a857c3870ed9c5eb1b2c95a724ac5e18dec4a9d9f8de96a12261394d565b6040517f3b83daf70000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff808316602483015284811660448301529192505f9182918291881690633b83daf7906064016060604051808303815f875af1158015611437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061145b9190615740565b9194509250905081156114745761147487848685613b26565b80156114865761148687848784613b26565b5050505050610e396131d8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020606090610eef90600501613941565b5f805f805f80610b047ff84827146d9e16fc63c72d4a27583ebb2f2726d3b140bfed25057169c3fe0d328a8a612b85565b611500836129e9565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600260208190526040909120805490916115479161153f9160ff9091169086613be3565b600484613be3565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff91909116178155604080518415158152831515602082015273ffffffffffffffffffffffffffffffffffffffff8616917f4b66fff10a49d450609bce25ef49a877654e95a44a0ee1c2ac3156cc08d87cd6910161133f565b6115cd612cb6565b5f6115e8610c23610c15610304610c0e610220870187615625565b90505f806115fc610a28602087018761524e565b91509150611614828260030185886020013588613bfc565b61161f828487613f9d565b611630610100850160e0860161524e565b73ffffffffffffffffffffffffffffffffffffffff16631847f3b28385873560208a01356116626102008b018b615625565b6040518763ffffffff1660e01b8152600401611683969594939291906156d4565b5f604051808303815f87803b15801561169a575f80fd5b505af11580156116ac573d5f803e3d5ffd5b50505050505050610e396131d8565b5f611718610c236116fd6116e26103246116d860a0890189615774565b610c0e9080615625565b6116ef60a0880188615774565b610c0e906020810190615625565b61170a60a0870187615774565b610c0e9060c0810190615625565b90506117518161172e606086016040870161524e565b61173b60a0870187615774565b61174c9060a081019060800161524e565b6140da565b60015f611761602086018661524e565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f205460ff166117c0576040517f82735a4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6117ea7f69524d80bf8f9dc93874cc5d8a743ae1ed66cd8ec4a017685ae62049a77dbf6161394d565b905073ffffffffffffffffffffffffffffffffffffffff811615611813576118138484836141be565b5f61185c61182460a0870187615774565b6118359060a081019060800161524e565b611845606088016040890161524e565b8561185360a08a018a615774565b60a00135612e9b565b90505f61186c60a0870187615774565b61187d9060a081019060800161524e565b73ffffffffffffffffffffffffffffffffffffffff1603611988576118a560a0860186615774565b60a0013534146118e1576040517fe07ce87800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6118f2606087016040880161524e565b73ffffffffffffffffffffffffffffffffffffffff16346040515f6040518083038185875af1925050503d805f8114611946576040519150601f19603f3d011682016040523d82523d5f602084013e61194b565b606091505b5050905080611986576040517f36aeb2cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b5f5461ffff1661199e60e0870160c0880161551d565b61ffff168161ffff1611156119df576040517f5fd9ac3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6119ed602088018861524e565b73ffffffffffffffffffffffffffffffffffffffff166303c268e06020890135611a1a60a08b018b615774565b86866040518563ffffffff1660e01b8152600401611a3b9493929190615820565b6020604051808303815f875af1158015611a57573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a7b919061560a565b905073ffffffffffffffffffffffffffffffffffffffff81161580611adb5750611aab606088016040890161524e565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15611b12576040517fd1949e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001611b246080890160608a016159cc565b15611b2d576002175b611b3d60a0890160808a016159cc565b15611b46576004175b73ffffffffffffffffffffffffffffffffffffffff82165f90815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff8316179055611ba260a0890189615774565b611bb5906101408101906101200161524e565b73ffffffffffffffffffffffffffffffffffffffff8381165f90815260026020908152604090912060010180547fffffffffffffffffffffffff00000000000000000000000000000000000000001693909216929092179055611c1a9089018961524e565b73ffffffffffffffffffffffffffffffffffffffff16611c3d60a08a018a615774565b611c4e9060a081019060800161524e565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fd20239aa1881cf889343ab7940f6c9763c805166c1f02380585f3f76234611dd60405160405180910390a45050505050505050565b611cb9612cb6565b5f611ce37f904546aa6078183b7a7f51fdbcf69d1f9807ba2640c9680a30eaad08e070a75061394d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161490505f611d3d7fc23a207f9f3535a857c3870ed9c5eb1b2c95a724ac5e18dec4a9d9f8de96a12261394d565b90505f5b83811015611ece575f858583818110611d5c57611d5c6159e7565b9050602002016020810190611d71919061524e565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526002602052604090206001810154929350911685611df4573373ffffffffffffffffffffffffffffffffffffffff821614611df4576040517f28e12d9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff255527800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015282811660248301525f91829182919087169063f2555278906044016060604051808303815f875af1158015611e6e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e929190615740565b919450925090508115611eab57611eab86848a85613b26565b8015611ebd57611ebd86848684613b26565b505050505050806001019050611d41565b505050610e396131d8565b5f805f805f80610b047f32bef578f3163409ece0dcb42bdc8ef1a50a6e97eeb7dfb7b1aacb7c04d0a61d8a8a612b85565b611f337fe147488f91e9e6a3e5aba7277f12c2c3b506c93b76232d4c97e6807b033bfcaa61394d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611f97576040517f28e12d9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f8181526001602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527fe7c944d2b90ee92d33a0a0a415d6627e5fc30b9dbc0979227a4aed5e00646ed4910160405180910390a25050565b6120497fe147488f91e9e6a3e5aba7277f12c2c3b506c93b76232d4c97e6807b033bfcaa61394d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146120ad576040517f28e12d9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61271061ffff821611156120ed576040517f5fd9ac3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83169081179091556040519081527f5aae10d742f3cdf67ed0303d4252cce7e6659535101255cad9d3f8de3f096ad09060200160405180910390a150565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020606090610eef90600701613941565b6121b0837f3c6581d000000000000000000000000000000000000000000000000000000000612acc565b5f6121dc7f32bef578f3163409ece0dcb42bdc8ef1a50a6e97eeb7dfb7b1aacb7c04d0a61d8585612b85565b5f8181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155915191825291925084359173ffffffffffffffffffffffffffffffffffffffff8716917fb5d8b866115f3ad5af89970a02a0004621427127009ae1ba2619e629b92d0ae1910161091d565b61226d612cb6565b5f6122786064612d8b565b90505f61228b610a28602085018561524e565b509050612299818385613f9d565b5050610ad06131d8565b6122ab612cb6565b5f6122e4610c236122d66122c86103e4610c0e6080880188615625565b610c0e610220880188615625565b610c0e610200870187615625565b90505f806122f8610a28602088018861524e565b915091505f8273ffffffffffffffffffffffffffffffffffffffff1663c1345fcc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612346573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061236a919061560a565b90505f8061237b602088018861524e565b73ffffffffffffffffffffffffffffffffffffffff16036123ad576123a68285878b60400135612e9b565b90506123be565b6123bb8583868b8b8b614214565b90505b5f806123d48686600301898d602001358d6144ed565b915091506123e586888585886130a5565b801561247e576123fc6101008a0160e08b0161524e565b73ffffffffffffffffffffffffffffffffffffffff1663de69399387898c5f0135868e80610200019061242f9190615625565b6040518763ffffffff1660e01b8152600401612450969594939291906156d4565b5f604051808303815f87803b158015612467575f80fd5b505af1158015612479573d5f803e3d5ffd5b505050505b5050505050505061080c6131d8565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000d7b37203f54e165fb204b57c30d1583516146124fc576040517fbedae83200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7fba783d0f337aa315f54f5ed7ca2c2d311b62a50e6c2536aa37414989987635c15f938452602052506040909120805467ffffffffffffffff4263ffffffff7c010000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9096167fffffffffffffffffffffffff0000000000000000000000000000000000000000851681179690960416011674010000000000000000000000000000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909116909217919091179055565b6125ed836129e9565b801561268a5773ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090206126249060090183612a83565b1561080c578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f1a4871e9efff6fda48e55034e859a248a2a78790a5dc20a97819c695f789e5c483604051610803911515815260200190565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090206126249060090183612aab565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020606090610eef90600901613941565b6126f6612cb6565b6126ff836129e9565b73ffffffffffffffffffffffffffffffffffffffff8084165f90815260026020526040812060010154909116906127557fc23a207f9f3535a857c3870ed9c5eb1b2c95a724ac5e18dec4a9d9f8de96a12261394d565b6040517fc747300300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015260248201869052808316604483015284811660648301529192505f91829182918291908a169063c7473003906084016080604051808303815f875af11580156127e3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128079190615a14565b93509350935093505f8311156128235761282389858a86613b26565b81156128355761283589858785613b26565b80156128475761284789858884613b26565b50505050505061080c6131d8565b73ffffffffffffffffffffffffffffffffffffffff8083165f90815260026020526040902060018101549091163381146128bb576040517f28e12d9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff858116918217909255604051908152908516907f15b8b688cfaa9d33aad24fafaa4b2222541e0048b2f2d3e0bce6e6e59f4100f09060200161133f565b80825d5050565b5c90565b5f815d50565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129775780825d5050565b9055565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129ab57505c90565b5080545b919050565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156129e4575f815d50565b5f9055565b73ffffffffffffffffffffffffffffffffffffffff81163303612a095750565b5f612a13826148c4565b50905073ffffffffffffffffffffffffffffffffffffffff81163303612a37575050565b5f612a4383823361490c565b5090508015612a5157505050565b6040517f196afcf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612aa48373ffffffffffffffffffffffffffffffffffffffff8416614978565b9392505050565b5f612aa48373ffffffffffffffffffffffffffffffffffffffff84166149c4565b73ffffffffffffffffffffffffffffffffffffffff82163303612aed575050565b5f612af7836148c4565b50905073ffffffffffffffffffffffffffffffffffffffff81163303612b1c57505050565b5f612b2884823361490c565b5090508015612b375750505050565b5f612b4385853361490c565b5090508015612b53575050505050565b6040517fd188e4d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612cae612c3d85843573ffffffffffffffffffffffffffffffffffffffff8716612bb6604088016020890161524e565b73ffffffffffffffffffffffffffffffffffffffff16612bdc6060890160408a0161524e565b73ffffffffffffffffffffffffffffffffffffffff16606089013560808a013560a08b013560408051610160810182529889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e082015290565b60c0840135612c53610100860160e0870161524e565b73ffffffffffffffffffffffffffffffffffffffff16612c7b6101808701610160880161524e565b73ffffffffffffffffffffffffffffffffffffffff16610100840192909252610120830152610140820152610160902090565b949350505050565b6002612d057feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb8905007f0000000000000000000000000000000000000000000000000000050d0000293c63ffffffff16565b03612d3c576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111e07feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb89050060027f000000000000000000000000000000000000000000000000000005060000293563ffffffff16565b3336828103908314612ddc5780601414612dd1576040517fcd7868d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612dd9614aa7565b91505b50919050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260205260409020805482919060ff811690600116612e49576040517fe8670fe200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002811615612e9557612e5f6005830133614b97565b612e95576040517f2cf00d3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50915091565b3473ffffffffffffffffffffffffffffffffffffffff851615612cae573415612ef0576040517f0d92818600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301525f91908716906370a0823190602401602060405180830381865afa158015612f5d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f819190615a50565b90505f612f9087868887614bc5565b90508015612fca576040517f8891813700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301525f91908916906370a0823190602401602060405180830381865afa158015613037573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061305b9190615a50565b905082811015613097576040517f8891813700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919091039695505050505050565b6040517fd2395dcd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015260248201859052604482018490525f91829188169063d2395dcd903490606401604080518083038185885af1158015613123573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906131489190615a67565b9092509050801561315f5761315f87848884613b26565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167ffa04dacd647c6f4bdcf015f976434bd24d44a32fdce775268f13be35ec27e86586856040516131c7929190918252602082015260400190565b60405180910390a350505050505050565b6111e07feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb89050060017f000000000000000000000000000000000000000000000000000005060000293563ffffffff16565b5f60ff82351115613264576040517f8bd2b8ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f600161327085614c3a565b604080515f815260208082018084529390935260ff87351681830152918601356060830152850135608082015260a0016020604051602081039080840390855afa1580156132c0573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191506132f690508582614b97565b95945050505050565b5f428260200135101561333e576040517f1b0107aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff6040830135111561337d576040517f8bd2b8ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c080820183527f1f339a1d08c106eea6fd9baad6936fe44e1a0c1f9f79cb10ebbf5dd2292c883982528535602083810191909152808701358385015292860135606083015291840135608082015273ffffffffffffffffffffffffffffffffffffffff861660a0820152205f906133fd90614c3a565b614c3a565b905061340c602084018461524e565b73ffffffffffffffffffffffffffffffffffffffff166001828560400135866060013587608001356040515f8152602001604052604051613469949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015613489573d5f803e3d5ffd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff16149150509392505050565b5f63ffffffff8211156134f3576040517fcd7868d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b5f80428360c00135101561355d576040517fbcf7256800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6135957f65549d51d8dfff0328fddb86e5cd1955c5deb61b381c98611d77ae032a5b098461358f602088018861524e565b86612b85565b90506135a687828661010001613227565b6135dc576040517f4a4dc21200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6135ef6101808601610160870161524e565b73ffffffffffffffffffffffffffffffffffffffff16146136535761361d86856101000186610160016132ff565b613653576040517f29f75ed400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208501359150613668826060860135615ab6565b92505f61367b604086016020870161524e565b73ffffffffffffffffffffffffffffffffffffffff1614613754576136a6604085016020860161524e565b73ffffffffffffffffffffffffffffffffffffffff1663d611669f6002886136d160208a018a61524e565b6136e160608a0160408b0161524e565b886136f06102208c018c615625565b6040518863ffffffff1660e01b81526004016137129796959493929190615acd565b602060405180830381865afa15801561372d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137519190615a50565b92505b5f818152600360205260409020805460ff161561379d576040517fa67ff36b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a0850135156137fe575f8382600101546137b89190615b27565b90508560a001358111156137f8576040517f410ff87000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201555b6080850135156138a25773ffffffffffffffffffffffffffffffffffffffff87165f90815260028201602052604081205461383a908590615b27565b9050856080013581111561387a576040517fcde4897e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff88165f9081526002830160205260409020555b505094509492505050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600a5a6138d29190615b3a565b6040515f8181818686fa925050503d805f811461390a576040519150601f19603f3d011682016040523d82523d5f602084013e61390f565b606091505b50909392505050565b6111e07feff9701f8ef712cda0f707f0a4f48720f142bf7e1bce9d4747c32b4eeb890500614c81565b60605f612aa483614ce4565b5f8181527fba783d0f337aa315f54f5ed7ca2c2d311b62a50e6c2536aa37414989987635c160205260409020805473ffffffffffffffffffffffffffffffffffffffff81169190427401000000000000000000000000000000000000000090910467ffffffffffffffff161015612ddc576040517f663e4335000000000000000000000000000000000000000000000000000000008152600481018490527f00000000000000000000000000000000d7b37203f54e165fb204b57c30d1583573ffffffffffffffffffffffffffffffffffffffff169063663e433590602401602060405180830381865afa158015613a47573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a6b919061560a565b81547fffffffff00000000000000000000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff8316908117740100000000000000000000000000000000000000007c01000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffff00000000000000000000000000000000000000009094169092179290920463ffffffff16420167ffffffffffffffff16021790915592915050565b5f613b3384868585614bc5565b90508015613bdc578473ffffffffffffffffffffffffffffffffffffffff166379e32c7b6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015613b80575f80fd5b505af1158015613b92573d5f803e3d5ffd5b50505050613ba284868585614bc5565b90508015613bdc576040517f8891813700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b5f8115613bf35750828217612aa4565b505060ff031690565b428160c001351015613c3a576040517fbcf7256800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613c667f32bef578f3163409ece0dcb42bdc8ef1a50a6e97eeb7dfb7b1aacb7c04d0a61d8784612b85565b9050613c7785828461010001613227565b613cad576040517f4a4dc21200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613cc06101808401610160850161524e565b73ffffffffffffffffffffffffffffffffffffffff1614613d2457613cee84836101000184610160016132ff565b613d24576040517f29f75ed400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608201355f613d3a604085016020860161524e565b73ffffffffffffffffffffffffffffffffffffffff1614613e0b57613d65604084016020850161524e565b73ffffffffffffffffffffffffffffffffffffffff1663d611669f6001878a613d946060890160408a0161524e565b6060890135613da76102208b018b615625565b6040518863ffffffff1660e01b8152600401613dc99796959493929190615acd565b602060405180830381865afa158015613de4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e089190615a50565b90505b80841015613e45576040517f43212e0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600360205260409020805460ff1615613e8e576040517fa67ff36b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a084013515613eef575f858260010154613ea99190615b27565b90508460a00135811115613ee9576040517f410ff87000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201555b608084013515613f935773ffffffffffffffffffffffffffffffffffffffff86165f908152600282016020526040812054613f2b908790615b27565b90508460800135811115613f6b576040517fcde4897e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87165f9081526002830160205260409020555b5050505050505050565b604080517fe4e57b9e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602084013560248301529183013560448201525f918291829187169063e4e57b9e906064016060604051808303815f875af1158015614022573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140469190615740565b9250925092508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f40c0a04f5aa39bf3bb355f059b5b9ff0f3279927e49d151cea7b028125ba9fc68660200135856040516140b8929190918252602082015260400190565b60405180910390a380156140d2576140d286848784613b26565b505050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526002602081905260409091208054909160ff82169116156141535761411d6005830133614b97565b614153576040517f2cf00d3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004811615613bdc576141668584614d3d565b613bdc576141776007830186614b97565b613bdc576141886009830185614b97565b613bdc576040517f2b88b7de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6141cb6133f885614dd9565b90506141d8818484614ebe565b61420e576040517f04987b1900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff8616614262576040517fa2e319a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301525f91908816906370a0823190602401602060405180830381865afa1580156142cf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142f39190615a50565b90505f614303602085018561524e565b73ffffffffffffffffffffffffffffffffffffffff16634be52a89898660200135876040013588606001358e8d8d6040013561433f8f8f614f8e565b7f36fabc7b52b93a3d4148cea549fc324d118a329831e5ea98e3694dd53093bc848e80608001906143709190615625565b6040518c63ffffffff1660e01b81526004016143969b9a99989796959493929190615b72565b6020604051808303815f875af11580156143b2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143d69190615725565b90508015614410576040517f4a9d52ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301525f91908a16906370a0823190602401602060405180830381865afa15801561447d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144a19190615a50565b9050828110156144dd576040517f8891813700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9190910398975050505050505050565b815f80614501610100850160e0860161524e565b73ffffffffffffffffffffffffffffffffffffffff1614801591506148ba57428360c00135101561455e576040517fbcf7256800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61458a7ff84827146d9e16fc63c72d4a27583ebb2f2726d3b140bfed25057169c3fe0d328986612b85565b905061459b87828661010001613227565b6145d1576040517f4a4dc21200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6145e46101808601610160870161524e565b73ffffffffffffffffffffffffffffffffffffffff16146146485761461286856101000186610160016132ff565b614648576040517f29f75ed400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608401355f61465e604087016020880161524e565b73ffffffffffffffffffffffffffffffffffffffff161461472e57614689604086016020870161524e565b73ffffffffffffffffffffffffffffffffffffffff1663d611669f5f898c6146b760608b0160408c0161524e565b60608b01356146ca6102208d018d615625565b6040518863ffffffff1660e01b81526004016146ec9796959493929190615acd565b602060405180830381865afa158015614707573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061472b9190615a50565b90505b80841015614768576040517f43212e0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600360205260409020805460ff16156147b1576040517fa67ff36b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a086013515614812575f8582600101546147cc9190615b27565b90508660a0013581111561480c576040517f410ff87000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201555b6080860135156148b65773ffffffffffffffffffffffffffffffffffffffff88165f90815260028201602052604081205461484e908790615b27565b9050866080013581111561488e576040517fcde4897e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89165f9081526002830160205260409020555b5050505b9550959350505050565b5f806148fa565b638da5cb5b5f525f8060205f6004601c865afa60203d101516156148f2575f519150915091565b509160019150565b614903836148cb565b91509150915091565b5f80614961565b5f80604051606081016040526391d14854815284816020015285816040015260205f6044601c8401875afa60203d10151615614953575f51925050614959565b50600190505b935093915050565b61496c838587614913565b91509150935093915050565b5f8181526001830160205260408120546149bd57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610eef565b505f610eef565b5f8181526001830160205260408120548015614a9e575f6149e6600183615bec565b85549091505f906149f990600190615bec565b9050808214614a58575f865f018281548110614a1757614a176159e7565b905f5260205f200154905080875f018481548110614a3757614a376159e7565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080614a6957614a69615bff565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610eef565b5f915050610eef565b6040517f572b6c050000000000000000000000000000000000000000000000000000000081523360048201525f907f000000000000000000000000ff0000b6c4352714cce809000d0cd30a0e0c8dce73ffffffffffffffffffffffffffffffffffffffff169063572b6c0590602401602060405180830381865afa158015614b31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614b559190615725565b15614b8d5760143610614b8d57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c90565b503390565b905090565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526001830160205260408120541515612aa4565b5f614c2e565b5f604051608081016040526323b872dd81528381602001528481604001528581606001525f806064601c84015f875af115614c225760203d1015614c13575050803b15612cae565b60205f803e50505f5115612cae565b50600195945050505050565b6132f682848688614bcb565b5f610eef614c46615068565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615614cb2578054815d50565b6040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060815f01805480602002602001604051908101604052809291908181526020018280548015614d3157602002820191905f5260205f20905b815481526020019060010190808311614d1d575b50505050509050919050565b5f8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603614d7957506001610eef565b5f614d83836148c4565b5090508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603614dc3576001915050610eef565b5f614dcf84828761490c565b5095945050505050565b5f610eef7f1859bb357b9cf600b5309096fb870e7e7516c667fc2c8d80ce139d7610462934614e0b602085018561524e565b73ffffffffffffffffffffffffffffffffffffffff166020850135614e36606087016040880161524e565b73ffffffffffffffffffffffffffffffffffffffff16614e5c60808801606089016159cc565b614e66575f614e69565b60015b60ff16614e7c60a0890160808a016159cc565b614e86575f614e89565b60015b60ff166040805160c0808201835297815260208101969096528501939093526060840191909152608083015260a08201522090565b5f60ff83351115614efb576040517f8bd2b8ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080515f8152602081810180845287905260ff86351682840152850135606082015290840135608082015260019060a0016020604051602081039080840390855afa158015614f4d573d5f803e3d5ffd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161490509392505050565b5f612aa46150547f21cb3dab0ae1a1d86be87b4c5e2d64effa64142020577b4a8381b3249476ee73614fc3602087018761524e565b73ffffffffffffffffffffffffffffffffffffffff16602087013560408801358735614ff66101008a0160e08b0161524e565b73ffffffffffffffffffffffffffffffffffffffff166101008a01356101208b013560408051610120810182529889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e082015290565b610140840135610100820152610120902090565b5f7f000000000000000000000000000000000000000000000000000000000000817346036150b557507ff7650a1627eb1ef55f82a7cccb02a35e29046ee012ffe9cc4621a7790de93af690565b614b92604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527fc1f2138aa012493b3a95abfc19e80a274ab21afb85385bc6b062e697074f86d9918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b73ffffffffffffffffffffffffffffffffffffffff81168114610ad0575f80fd5b80356129af8161515c565b8015158114610ad0575f80fd5b80356129af81615188565b5f805f606084860312156151b2575f80fd5b83356151bd8161515c565b925060208401356151cd8161515c565b915060408401356151dd81615188565b809150509250925092565b5f6102408284031215612ddc575f80fd5b5f805f6060848603121561520b575f80fd5b83356152168161515c565b9250602084013567ffffffffffffffff811115615231575f80fd5b61523d868287016151e8565b92505060408401356151dd81615188565b5f6020828403121561525e575f80fd5b8135612aa48161515c565b5f60608284031215612ddc575f80fd5b5f60608284031215615289575f80fd5b612aa48383615269565b5f602082840312156152a3575f80fd5b5035919050565b5f805f606084860312156152bc575f80fd5b83356152c78161515c565b9250602084013567ffffffffffffffff8111156152e2575f80fd5b6152ee868287016151e8565b92505060408401356151dd8161515c565b5f8060808385031215615310575f80fd5b61531a8484615269565b9150606083013567ffffffffffffffff811115615335575f80fd5b615341858286016151e8565b9150509250929050565b602080825282518282018190525f9190848201906040850190845b8181101561539857835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101615366565b50909695505050505050565b5f80604083850312156153b5575f80fd5b82356153c08161515c565b915060208301356153d08161515c565b809150509250929050565b5f80604083850312156153ec575f80fd5b82356153f78161515c565b946020939093013593505050565b5f805f60608486031215615417575f80fd5b83356154228161515c565b925060208401356151cd81615188565b5f8060808385031215615443575f80fd5b823567ffffffffffffffff811115615459575f80fd5b830160e0818603121561546a575f80fd5b91506154798460208501615269565b90509250929050565b5f8060208385031215615493575f80fd5b823567ffffffffffffffff808211156154aa575f80fd5b818501915085601f8301126154bd575f80fd5b8135818111156154cb575f80fd5b8660208260051b85010111156154df575f80fd5b60209290920196919550909350505050565b5f8060408385031215615502575f80fd5b823561550d8161515c565b915060208301356153d081615188565b5f6020828403121561552d575f80fd5b813561ffff81168114612aa4575f80fd5b5f805f60a08486031215615550575f80fd5b61555a8585615269565b9250606084013567ffffffffffffffff80821115615576575f80fd5b615582878388016151e8565b93506080860135915080821115615597575f80fd5b50840160a081870312156151dd575f80fd5b5f80604083850312156155ba575f80fd5b8235915060208301356153d08161515c565b5f805f606084860312156155de575f80fd5b83356155e98161515c565b925060208401356155f98161515c565b929592945050506040919091013590565b5f6020828403121561561a575f80fd5b8151612aa48161515c565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615658575f80fd5b83018035915067ffffffffffffffff821115615672575f80fd5b602001915036819003821315615686575f80fd5b9250929050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a0608083015261571960a08301848661568d565b98975050505050505050565b5f60208284031215615735575f80fd5b8151612aa481615188565b5f805f60608486031215615752575f80fd5b835161575d8161515c565b602085015160409095015190969495509392505050565b5f82357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18336030181126157a6575f80fd5b9190910192915050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126157e3575f80fd5b830160208101925035905067ffffffffffffffff811115615802575f80fd5b803603821315615686575f80fd5b803560ff811681146129af575f80fd5b848152608060208201525f61583585866157b0565b61016080608086015261584d6101e08601838561568d565b925061585c60208901896157b0565b92507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808786030160a088015261589485858461568d565b94506158a260408b01615810565b60ff811660c089015293506158b960608b0161517d565b73ffffffffffffffffffffffffffffffffffffffff811660e089015293506158e360808b0161517d565b9350610100915061590b8288018573ffffffffffffffffffffffffffffffffffffffff169052565b610120935060a08a01358488015261592660c08b018b6157b0565b610140838a890301818b015261593d88838561568d565b975061594b60e08e0161517d565b73ffffffffffffffffffffffffffffffffffffffff81168b8801529350615973858e01615195565b8015156101808c01529550615989878e0161517d565b73ffffffffffffffffffffffffffffffffffffffff166101a08b01528c01356101c08a01525050505060408501879052505061ffff8416606084015290506132f6565b5f602082840312156159dc575f80fd5b8135612aa481615188565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f805f8060808587031215615a27575f80fd5b8451615a328161515c565b60208601516040870151606090970151919890975090945092505050565b5f60208284031215615a60575f80fd5b5051919050565b5f8060408385031215615a78575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082028115828204841417610eef57610eef615a89565b8781525f73ffffffffffffffffffffffffffffffffffffffff8089166020840152808816604084015280871660608401525084608083015260c060a0830152615b1a60c08301848661568d565b9998505050505050505050565b80820180821115610eef57610eef615a89565b5f82615b6d577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f61014073ffffffffffffffffffffffffffffffffffffffff808f1684528d60208501528c60408501528b6060850152808b166080850152808a1660a0850152508760c08401528660e08401528561010084015280610120840152615bda818401858761568d565b9e9d5050505050505050505050505050565b81810381811115610eef57610eef615a89565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212207cae73b79dc90cd174a99f75d535d37855c1458da313e1a09b872b7a98efbebc64736f6c63430008180033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000d7b37203f54e165fb204b57c30d15835755567e1f0e12dc4d7f3efea8a543338d6d0b9d983517c6bed1224aac0f0ba63000000000000000000000000ff0000b6c4352714cce809000d0cd30a0e0c8dce

-----Decoded View---------------
Arg [0] : roleServer (address): 0x00000000d7b37203F54e165Fb204B57c30d15835
Arg [1] : roleSet (bytes32): 0x755567e1f0e12dc4d7f3efea8a543338d6d0b9d983517c6bed1224aac0f0ba63
Arg [2] : trustedForwarderFactory (address): 0xFF0000B6c4352714cCe809000d0cd30A0E0c8DcE

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000d7b37203f54e165fb204b57c30d15835
Arg [1] : 755567e1f0e12dc4d7f3efea8a543338d6d0b9d983517c6bed1224aac0f0ba63
Arg [2] : 000000000000000000000000ff0000b6c4352714cce809000d0cd30a0e0c8dce


Deployed Bytecode Sourcemap

4520:86520:26:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30214:573;;;;;;;;;;-1:-1:-1;30214:573:26;;;;;:::i;:::-;;:::i;:::-;;37126:525;;;;;;;;;;-1:-1:-1;37126:525:26;;;;;:::i;:::-;;:::i;57187:713::-;;;;;;;;;;-1:-1:-1;57187:713:26;;;;;:::i;:::-;57484:27;;;;57281:26;57484:27;;;:13;:27;;;;;;;;57536:14;;;57865:28;;;;90309:16;;;90308:23;;;90309:16;;;90308:23;;;5684:6:23;90309:16:26;;;90308:23;;;57865:28;;;57187:713;;;;;2618:14:35;;2611:22;2593:41;;2677:14;;2670:22;2665:2;2650:18;;2643:50;2736:14;;2729:22;2709:18;;;2702:50;;;;2800:42;2788:55;2783:2;2768:18;;2761:83;2580:3;2565:19;57187:713:26;;;;;;;;28978:565;;;;;;;;;;-1:-1:-1;28978:565:26;;;;;:::i;:::-;;:::i;8475:586::-;;;;;;:::i;:::-;;:::i;5185:55::-;;;;;;;;;;-1:-1:-1;5185:55:26;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3639:14:35;;3632:22;3614:41;;3686:2;3671:18;;3664:34;;;;3587:18;5185:55:26;3446:258:35;55355:1219:26;;;;;;;;;;-1:-1:-1;55355:1219:26;;;;;:::i;:::-;;:::i;:::-;;;;4595:25:35;;;4651:2;4636:18;;4629:34;;;;4706:14;;4699:22;4679:18;;;4672:50;;;;4765:14;;4758:22;4753:2;4738:18;;4731:50;4825:14;4818:22;4812:3;4797:19;;4790:51;4582:3;4567:19;55355:1219:26;4354:493:35;18877:1491:26;;;;;;;;;;-1:-1:-1;18877:1491:26;;;;;:::i;:::-;;:::i;969:144:8:-;;;;;;;;;;-1:-1:-1;969:144:8;;;;;:::i;:::-;;:::i;:::-;;;5517:14:35;;5510:22;5492:41;;5480:2;5465:18;969:144:8;5352:187:35;34710:515:26;;;;;;;;;;-1:-1:-1;34710:515:26;;;;;:::i;:::-;;:::i;31686:608::-;;;;;;;;;;-1:-1:-1;31686:608:26;;;;;:::i;:::-;;:::i;4954:532:16:-;;;;;;;;;;;;;:::i;58148:190:26:-;;;;;;;;;;-1:-1:-1;58148:190:26;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;43046:800::-;;;;;;;;;;-1:-1:-1;43046:800:26;;;;;:::i;:::-;;:::i;40994:1235::-;;;;;;;;;;-1:-1:-1;40994:1235:26;;;;;:::i;:::-;;:::i;58599:202::-;;;;;;;;;;-1:-1:-1;58599:202:26;;;;;:::i;:::-;;:::i;50852:1163::-;;;;;;;;;;-1:-1:-1;50852:1163:26;;;;;:::i;:::-;;:::i;27495:802::-;;;;;;;;;;-1:-1:-1;27495:802:26;;;;;:::i;:::-;;:::i;16019:1155::-;;;;;;;;;;-1:-1:-1;16019:1155:26;;;;;:::i;:::-;;:::i;23170:3269::-;;;;;;:::i;:::-;;:::i;46082:1648::-;;;;;;;;;;-1:-1:-1;46082:1648:26;;;;;:::i;:::-;;:::i;4802:34::-;;;;;;;;;;-1:-1:-1;4802:34:26;;;;;;;;;;;9447:6:35;9435:19;;;9417:38;;9405:2;9390:18;4802:34:26;9273:188:35;53070:1163:26;;;;;;;;;;-1:-1:-1;53070:1163:26;;;;;:::i;:::-;;:::i;4920:52::-;;;;;;;;;;-1:-1:-1;4920:52:26;;;;;:::i;:::-;;;;;;;;;;;;;;;;48500:243;;;;;;;;;;-1:-1:-1;48500:243:26;;;;;:::i;:::-;;:::i;49214:334::-;;;;;;;;;;-1:-1:-1;49214:334:26;;;;;:::i;:::-;;:::i;59074:230::-;;;;;;;;;;-1:-1:-1;59074:230:26;;;;;:::i;:::-;;:::i;35919:520::-;;;;;;;;;;-1:-1:-1;35919:520:26;;;;;:::i;:::-;;:::i;14059:348::-;;;;;;;;;;-1:-1:-1;14059:348:26;;;;;:::i;:::-;;:::i;11102:2039::-;;;;;;:::i;:::-;;:::i;1011:410:19:-;;;;;;;;;;-1:-1:-1;1011:410:19;;;;;:::i;:::-;;:::i;33375:643:26:-;;;;;;;;;;-1:-1:-1;33375:643:26;;;;;:::i;:::-;;:::i;59625:218::-;;;;;;;;;;-1:-1:-1;59625:218:26;;;;;:::i;:::-;;:::i;38553:1552::-;;;;;;;;;;-1:-1:-1;38553:1552:26;;;;;:::i;:::-;;:::i;44632:570::-;;;;;;;;;;-1:-1:-1;44632:570:26;;;;;:::i;:::-;;:::i;30214:573::-;30325:69;30381:12;30325:55;:69::i;:::-;30409:7;30405:376;;;30436:27;;;;;;;:13;:27;;;;;:56;;:43;;30484:7;30436:47;:56::i;:::-;30432:153;;;30553:7;30517:53;;30539:12;30517:53;;;30562:7;30517:53;;;;5517:14:35;5510:22;5492:41;;5480:2;5465:18;;5352:187;30517:53:26;;;;;;;;30432:153;30214:573;;;:::o;30405:376::-;30619:27;;;;;;;:13;:27;;;;;:59;;:43;;30670:7;30619:50;:59::i;37126:525::-;37247:133;37322:16;3440:43:23;37247:61:26;:133::i;:::-;37391:22;37416:63;1989:240:23;37449:16:26;37467:11;37416:16;:63::i;:::-;37498:29;;;;:13;:29;;;;;;;;;:54;;;;;;;;;;;;;37567:77;;5492:41:35;;;37498:29:26;;-1:-1:-1;37604:29:26;;;37567:77;;;;;;5465:18:35;37567:77:26;;;;;;;;37237:414;37126:525;;;:::o;28978:565::-;29077:73;29133:16;29077:55;:73::i;:::-;29165:7;29161:376;;;29192:31;;;;;;;:13;:31;;;;;:56;;:44;;29241:6;29192:48;:56::i;:::-;29188:153;;;29310:6;29273:53;;29292:16;29273:53;;;29318:7;29273:53;;;;5517:14:35;5510:22;5492:41;;5480:2;5465:18;;5352:187;29161:376:26;29375:31;;;;;;;:13;:31;;;;;:59;;:44;;29427:6;29375:51;:59::i;8475:586::-;1263:21:21;:19;:21::i;:::-;8562:16:26::1;8581:39;3701:3:23;8581:12:26;:39::i;:::-;8562:58:::0;-1:-1:-1;8645:35:26::1;8694:63;8731:25;;::::0;::::1;:8:::0;:25:::1;:::i;:::-;8694:36;:63::i;:::-;8631:126;;;8767:19;8789:16;:29;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8767:53;;8830:21;8854:100;8881:11;8902:16;8921:8;8931;:22;;;8854:26;:100::i;:::-;8830:124;;8965:89;8977:16;8995:8;9005:13;9020:8;:20;;;9042:11;8965;:89::i;:::-;8552:509;;;;1305:20:21::0;:18;:20::i;:::-;8475:586:26;:::o;55355:1219::-;55524:29;55563:35;55608:18;55636:19;55665:21;55703:22;55728:63;1989:240:23;55761:16:26;55779:11;55728:16;:63::i;:::-;55801:31;55835:29;;;:13;:29;;;;;;;;55890:23;;;55947:20;;;56007:38;;;;;:29;;;:38;;;;;;;;55947:20;;-1:-1:-1;56007:38:26;;-1:-1:-1;55890:23:26;;;-1:-1:-1;55703:88:26;;-1:-1:-1;56085:15:26;56059:22;;;;:41;56055:513;;56174:31;;;;;;;:13;:31;;;;;56133:170;;56174:44;;56236:14;56268:21;;;56133:23;:170::i;:::-;56116:187;-1:-1:-1;56363:1:26;56321:30;;;;:23;;;:30;:::i;:::-;:44;;;56317:241;;56404:4;56385:23;;56317:241;;;56466:77;56487:7;56496:11;:21;;56519:11;:23;;56466:20;:77::i;:::-;56447:96;;56317:241;55693:881;;55355:1219;;;;;;;;;:::o;18877:1491::-;1263:21:21;:19;:21::i;:::-;19018:16:26::1;19037:287;19063:251;19104:146;4927:3:23;19198:27:26;;::::0;::::1;:11:::0;:27:::1;:::i;:::-;:34;;19104:23;:146::i;:::-;19268:25;;::::0;::::1;:11:::0;:25:::1;:::i;19063:251::-;19037:12;:287::i;:::-;19018:306:::0;-1:-1:-1;19349:35:26::1;::::0;19441:65:::1;19478:27;;::::0;::::1;:10:::0;:27:::1;:::i;19441:65::-;19335:171;;;;19518:21;19541:18:::0;19563:140:::1;19601:8;:21;;19636:8;19658:10;19682:11;19563:24;:140::i;:::-;19517:186;;;;19734:10;:27;;;19718:13;:43;19714:125;;;19784:44;;;;;;;;;;;;;;19714:125;19849:53;::::0;;;;:28:::1;13009:55:35::0;;;19849:53:26::1;::::0;::::1;12991:74:35::0;13081:18;;;13074:34;;;19849:28:26;::::1;::::0;::::1;::::0;12964:18:35;;19849:53:26::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;19945:1:26::1;::::0;-1:-1:-1;19917:16:26::1;::::0;-1:-1:-1;;19917:16:26;;;::::1;::::0;::::1;;:::i;:::-;:30;;;19913:322;;19985:16;::::0;;;::::1;::::0;::::1;;:::i;:::-;19963:60;;;20049:16:::0;20084:8;20110:29;::::1;20157:10:::0;20185:25:::1;;::::0;::::1;20110:11:::0;20185:25:::1;:::i;:::-;19963:261;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;19913:322;20250:111;::::0;;14238:25:35;;;14294:2;14279:18;;14272:34;;;20250:111:26::1;::::0;;::::1;::::0;20294:29;::::1;::::0;20250:111;;::::1;::::0;::::1;::::0;14211:18:35;20250:111:26::1;;;;;;;19008:1360;;;;;1305:20:21::0;:18;:20::i;:::-;18877:1491:26;;:::o;969:144:8:-;1068:38;;;;;:27;14481:55:35;;;1068:38:8;;;14463:74:35;1045:4:8;;1068:8;:27;;;;;;14436:18:35;;1068:38:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1061:45;969:144;-1:-1:-1;;969:144:8:o;34710:515:26:-;34829:133;34904:16;3440:43:23;34829:61:26;:133::i;:::-;34973:20;34996:61;1348:236:23;35027:16:26;35045:11;34996:16;:61::i;:::-;35076:27;;;;:13;:27;;;;;;;;;:52;;;;;;;;;;;;;35143:75;;5492:41:35;;;35076:27:26;;-1:-1:-1;35178:29:26;;;35143:75;;;;;;5465:18:35;35143:75:26;5352:187:35;31686:608:26;31798:69;31854:12;31798:55;:69::i;:::-;31882:7;31878:410;;;31909:27;;;;;;;:13;:27;;;;;:64;;:50;;31964:8;31909:54;:64::i;:::-;31905:170;;;32042:8;31998:62;;32028:12;31998:62;;;32052:7;31998:62;;;;5517:14:35;5510:22;5492:41;;5480:2;5465:18;;5352:187;31878:410:26;32109:27;;;;;;;:13;:27;;;;;:67;;:50;;32167:8;32109:57;:67::i;4954:532:16:-;5066:21;:61;;;-1:-1:-1;212:66:15;5091:36:16;;;5066:61;5062:123;;;5150:24;;;;;;;;;;;;;;5062:123;5267:30;5278:18;5267:10;:30::i;:::-;5262:89;;5320:20;;;;;;;;;;;;;;5262:89;212:66:15;5398:43:16;;;;5437:4;5398:43;;;5452:27;:25;:27::i;:::-;4954:532::o;58148:190:26:-;58278:31;;;;;;;:13;:31;;;;;58222:29;;58278:53;;:44;;:51;:53::i;43046:800::-;43170:73;43226:16;43170:55;:73::i;:::-;43287:31;;;;43254:30;43287:31;;;:13;:31;;;;;;;;43366:36;;;;43287:31;;43366:36;43429:41;;;:115;;;43517:27;43486:58;;:27;:58;;;;43429:115;43412:212;;;43576:37;;;;;;;;;;;;;;43412:212;43633:28;;;:58;;;;;;;;;;;;;;;43701:36;;;:49;;;;;;;;43766:73;;14463:74:35;;;43766:73:26;;;;;14451:2:35;14436:18;43766:73:26;;;;;;;;43160:686;;43046:800;;:::o;40994:1235::-;1263:21:21;:19;:21::i;:::-;41125:82:26::1;41189:16;41125:55;:82::i;:::-;41256:40;::::0;;::::1;41226:27;41256:40:::0;;;:13:::1;:40;::::0;;;;:60:::1;;::::0;;;::::1;::::0;41363:45:::1;41378:29;41363:14;:45::i;:::-;41573:110;::::0;;;;::::1;::::0;::::1;15000:25:35::0;;;41573:45:26::1;15122:15:35::0;;;15102:18;;;15095:43;15174:15;;;15154:18;;;15147:43;41326:82:26;;-1:-1:-1;41432:19:26::1;::::0;;;;;41573:45;::::1;::::0;::::1;::::0;14973:18:35;;41573:110:26::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;41418:265:::0;;-1:-1:-1;41418:265:26;-1:-1:-1;41418:265:26;-1:-1:-1;41698:40:26;;41694:270:::1;;41754:199;41796:16;41830:11;41859:26;41903:36;41754:24;:199::i;:::-;41978:33:::0;;41974:249:::1;;42027:185;42069:16;42103:11;42132:19;42169:29;42027:24;:185::i;:::-;41115:1114;;;;;1305:20:21::0;:18;:20::i;58599:202:26:-;58738:31;;;;;;;:13;:31;;;;;58676:32;;58738:56;;:47;;:54;:56::i;50852:1163::-;51017:19;51046:25;51081:18;51109:19;51138:21;51176:20;51199:61;1348:236:23;51230:16:26;51248:11;51199:16;:61::i;27495:802::-;27669:69;27725:12;27669:55;:69::i;:::-;27782:27;;;27749:30;27782:27;;;:13;:27;;;;;;;;27905:14;;27782:27;;27849:319;;27875:191;;27905:14;;;;;28010:38;27875:8;:191::i;:::-;5684:6:23;28132:22:26;27849:8;:319::i;:::-;27819:349;;;;;;;;;;;;28192:98;;;15766:14:35;;15759:22;15741:41;;15825:14;;15818:22;15813:2;15798:18;;15791:50;28192:98:26;;;;;;15714:18:35;28192:98:26;15579:268:35;16019:1155:26;1263:21:21;:19;:21::i;:::-;16143:16:26::1;16162:295;16188:259;16229:154;4629:3:23;16331:27:26;;::::0;::::1;:11:::0;:27:::1;:::i;16162:295::-;16143:314:::0;-1:-1:-1;16490:35:26::1;::::0;16582:64:::1;16619:26;;::::0;::::1;:9:::0;:26:::1;:::i;16582:64::-;16476:170;;;;16657:190;16702:16;16733:8;:21;;16768:8;16790:9;:22;;;16826:11;16657:23;:190::i;:::-;16858:51;16871:16;16889:8;16899:9;16858:12;:51::i;:::-;16941:16;::::0;;;::::1;::::0;::::1;;:::i;:::-;16920:58;;;17000:16:::0;17031:8;17053:29;::::1;17096:22;::::0;::::1;;17132:25;;::::0;::::1;17053:11:::0;17132:25:::1;:::i;:::-;16920:247;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;16133:1041;;;1305:20:21::0;:18;:20::i;23170:3269:26:-;23327:16;23346:485;23372:449;23413:312;23458:175;5263:3:23;23567:31:26;;;;:20;:31;:::i;:::-;:36;;;;:::i;23458:175::-;23661:31;;;;:20;:31;:::i;:::-;:38;;;;;;;:::i;23413:312::-;23743:31;;;;:20;:31;:::i;:::-;:57;;;;;;;:::i;23346:485::-;23327:504;-1:-1:-1;23842:171:26;23327:504;23913:33;;;;;;;;:::i;:::-;23960:31;;;;:20;:31;:::i;:::-;:43;;;;;;;;;:::i;:::-;23842:35;:171::i;:::-;24029:19;:54;24049:33;;;;:20;:33;:::i;:::-;24029:54;;;;;;;;;;;;;-1:-1:-1;24029:54:26;;;;24024:136;;24106:43;;;;;;;;;;;;;;24024:136;24170:23;24196:39;24211:23;24196:14;:39::i;:::-;24170:65;-1:-1:-1;24250:29:26;;;;24246:138;;24295:78;24324:20;24346:9;24357:15;24295:28;:78::i;:::-;24394:21;24418:235;24458:31;;;;:20;:31;:::i;:::-;:43;;;;;;;;;:::i;:::-;24515:33;;;;;;;;:::i;:::-;24562:8;24584:31;;;;:20;:31;:::i;:::-;:59;;;24418:26;:235::i;:::-;24394:259;-1:-1:-1;24722:1:26;24667:31;;;;:20;:31;:::i;:::-;:43;;;;;;;;;:::i;:::-;:57;;;24663:458;;24757:31;;;;:20;:31;:::i;:::-;:59;;;24744:9;:72;24740:158;;24843:40;;;;;;;;;;;;;;24740:158;24912:12;24929:33;;;;;;;;:::i;:::-;:38;;24975:9;24929:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24911:78;;;25008:7;25003:108;;25042:54;;;;;;;;;;;;;;25003:108;24726:395;24663:458;25131:28;25162:20;;;25220:44;;;;;;;;:::i;:::-;25196:68;;:21;:68;;;25192:154;;;25287:48;;;;;;;;;;;;;;25192:154;25356:24;25403:33;;;;:20;:33;:::i;:::-;25383:66;;;25463:30;;;;25507:31;;;;25463:20;25507:31;:::i;:::-;25552:13;25579:21;25383:227;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;25356:254;-1:-1:-1;25625:30:26;;;;;:87;;-1:-1:-1;25679:33:26;;;;;;;;:::i;:::-;25659:53;;:16;:53;;;;25625:87;25621:174;;;25735:49;;;;;;;;;;;;;;25621:174;5392:6:23;25861:59:26;;;;;;;;:::i;:::-;25857:146;;;5540:6:23;25936:56:26;25857:146;26016:43;;;;;;;;:::i;:::-;26012:113;;;5684:6:23;26075:39:26;26012:113;26134:31;;;;;;;:13;:31;;;;;:45;;;;;;;;;;26243:31;;;;;;:::i;:::-;:51;;;;;;;;;:::i;:::-;26189:31;;;;;;;;:13;:31;;;;;;;;:51;;:105;;;;;;;;;;;;;;26398:33;;;;;;:::i;:::-;26310:122;;26353:31;;;;:20;:31;:::i;:::-;:43;;;;;;;;;:::i;:::-;26310:122;;26335:16;26310:122;;;;;;;;;;;;23317:3122;;;;;;23170:3269;;:::o;46082:1648::-;1263:21:21;:19;:21::i;:::-;46185:15:26::1;46217:46;46232:30;46217:14;:46::i;:::-;46203:60;;:10;:60;;;46185:78;;46273:34;46310:45;46325:29;46310:14;:45::i;:::-;46273:82;;46370:9;46365:1359;46381:28:::0;;::::1;46365:1359;;;46430:35;46468:17;;46486:1;46468:20;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;46535:40;::::0;;::::1;46502:30;46535:40:::0;;;:13:::1;:40;::::0;;;;46619:28:::1;::::0;::::1;::::0;46430:58;;-1:-1:-1;46535:40:26;46619:28:::1;46667:10:::0;46662:173:::1;;46701:10;:33;::::0;::::1;;46697:124;;46765:37;;;;;;;;;;;;;;46697:124;47032:78;::::0;;;;:29:::1;21137:15:35::0;;;47032:78:26::1;::::0;::::1;21119:34:35::0;21189:15;;;21169:18;;;21162:43;46879:19:26::1;::::0;;;;;47032:29;;::::1;::::0;::::1;::::0;21031:18:35;;47032:78:26::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;46861:249:::0;;-1:-1:-1;46861:249:26;-1:-1:-1;46861:249:26;-1:-1:-1;47129:40:26;;47125:298:::1;;47189:219;47235:16;47273:11;47306:26;47354:36;47189:24;:219::i;:::-;47441:33:::0;;47437:277:::1;;47494:205;47540:16;47578:11;47611:19;47652:29;47494:24;:205::i;:::-;46416:1308;;;;;;46411:3;;;;;46365:1359;;;;46175:1555;;1305:20:21::0;:18;:20::i;53070:1163:26:-;53237:17;53264:23;53297:18;53325:19;53354:21;53392;53416:62;1671:238:23;53448:16:26;53466:11;53416:16;:62::i;48500:243::-;5821:38;5836:22;5821:14;:38::i;:::-;5807:52;;:10;:52;;;5803:127;;5882:37;;;;;;;;;;;;;;5803:127;48628:33:::1;::::0;::::1;;::::0;;;:19:::1;:33;::::0;;;;;;;;:43;;;::::1;::::0;::::1;;::::0;;::::1;::::0;;;48687:49;;5492:41:35;;;48687:49:26::1;::::0;5465:18:35;48687:49:26::1;;;;;;;48500:243:::0;;:::o;49214:334::-;5821:38;5836:22;5821:14;:38::i;:::-;5807:52;;:10;:52;;;5803:127;;5882:37;;;;;;;;;;;;;;5803:127;160:6:23::1;49316:27:26;::::0;::::1;;49312:113;;;49366:48;;;;;;;;;;;;;;49312:113;49435:20;:44:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;49494:47:::1;::::0;9417:38:35;;;49494:47:26::1;::::0;9405:2:35;9390:18;49494:47:26::1;;;;;;;49214:334:::0;:::o;59074:230::-;59234:31;;;;;;;:13;:31;;;;;59158:39;;59234:63;;:54;;:61;:63::i;35919:520::-;36039:133;36114:16;3440:43:23;36039:61:26;:133::i;:::-;36183:21;36207:62;1671:238:23;36239:16:26;36257:11;36207:16;:62::i;:::-;36288:28;;;;:13;:28;;;;;;;;;:53;;;;;;;;;;;;;36356:76;;5492:41:35;;;36288:28:26;;-1:-1:-1;36392:29:26;;;36356:76;;;;;;5465:18:35;36356:76:26;5352:187:35;14059:348:26;1263:21:21;:19;:21::i;:::-;14141:16:26::1;14160:40;4316:3:23;14160:12:26;:40::i;:::-;14141:59:::0;-1:-1:-1;14225:35:26::1;14274:64;14311:26;;::::0;::::1;:9:::0;:26:::1;:::i;14274:64::-;14211:127;;;14349:51;14362:16;14380:8;14390:9;14349:12;:51::i;:::-;14131:276;;1305:20:21::0;:18;:20::i;11102:2039:26:-;1263:21:21;:19;:21::i;:::-;11301:16:26::1;11320:425;11346:389;11387:284;11432:165;4092:3:23;11541:27:26;;::::0;::::1;:14:::0;:27:::1;:::i;11432:165::-;11619:27;;::::0;::::1;:11:::0;:27:::1;:::i;11387:284::-;11689:25;;::::0;::::1;:11:::0;:25:::1;:::i;11320:425::-;11301:444:::0;-1:-1:-1;11770:35:26::1;::::0;11862:63:::1;11899:25;;::::0;::::1;:8:::0;:25:::1;:::i;11862:63::-;11756:169;;;;11935:19;11957:16;:29;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11935:53:::0;-1:-1:-1;11999:21:26::1;::::0;12034:30:::1;;::::0;::::1;:14:::0;:30:::1;:::i;:::-;:44;;::::0;12030:464:::1;;12110:100;12137:11;12158:16;12177:8;12187;:22;;;12110:26;:100::i;:::-;12094:116;;12030:464;;;12258:225;12302:8;12328:11;12365:16;12400:8;12426:11;12455:14;12258:26;:225::i;:::-;12242:241;;12030:464;12505:19;12526:16:::0;12546:187:::1;12590:16;12621:8;:21;;12656:8;12678;:20;;;12712:11;12546:22;:187::i;:::-;12504:229;;;;12744:80;12756:16;12774:8;12784:13;12799:11;12812;12744;:80::i;:::-;12839:11;12835:300;;;12886:16;::::0;;;::::1;::::0;::::1;;:::i;:::-;12866:56;;;12948:16;12983:8;13009:11;:29;;;13056:11;13085;:25;;;;;;;;:::i;:::-;12866:258;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;12835:300;11291:1850;;;;;;;1305:20:21::0;:18;:20::i;1011:410:19:-;1097:10;:34;1119:11;1097:34;;1093:98;;1154:26;;;;;;;;;;;;;;1093:98;1225:25;469:35;1253:31;:37;;;;;-1:-1:-1;1253:37:19;;;;1304:30;;1348:56;1375:15;1393:10;;1304:30;;;;;;;;;1393:10;;;;;1375:28;1348:56;;;;;;;;;;;;;;;;1011:410::o;33375:643:26:-;33494:69;33550:12;33494:55;:69::i;:::-;33578:7;33574:438;;;33605:27;;;;;;;:13;:27;;;;;:71;;:47;;33657:18;33605:51;:71::i;:::-;33601:184;;;33742:18;33701:69;;33728:12;33701:69;;;33762:7;33701:69;;;;5517:14:35;5510:22;5492:41;;5480:2;5465:18;;5352:187;33574:438:26;33819:27;;;;;;;:13;:27;;;;;:74;;:47;;33874:18;33819:54;:74::i;59625:218::-;59776:31;;;;;;;:13;:31;;;;;59706:36;;59776:60;;:51;;:58;:60::i;38553:1552::-;1263:21:21;:19;:21::i;:::-;38696:82:26::1;38760:16;38696:55;:82::i;:::-;38827:40;::::0;;::::1;38797:27;38827:40:::0;;;:13:::1;:40;::::0;;;;:60:::1;;::::0;;;::::1;::::0;38934:45:::1;38949:29;38934:14;:45::i;:::-;39195:114;::::0;;;;:37:::1;21526:15:35::0;;;39195:114:26::1;::::0;::::1;21508:34:35::0;21558:18;;;21551:34;;;21621:15;;;21601:18;;;21594:43;21673:15;;;21653:18;;;21646:43;38897:82:26;;-1:-1:-1;39003:19:26::1;::::0;;;;;;;39195:37;;::::1;::::0;::::1;::::0;21419:19:35;;39195:114:26::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;38989:320;;;;;;;;39356:1;39324:29;:33;39320:240;;;39373:176;39415:16;39449:11;39478:10;39506:29;39373:24;:176::i;:::-;39574:40:::0;;39570:270:::1;;39630:199;39672:16;39706:11;39735:26;39779:36;39630:24;:199::i;:::-;39854:33:::0;;39850:249:::1;;39903:185;39945:16;39979:11;40008:19;40045:29;39903:24;:185::i;:::-;38686:1419;;;;;;1305:20:21::0;:18;:20::i;44632:570:26:-;44804:31;;;;44771:30;44804:31;;;:13;:31;;;;;44875:28;;;;44804:31;;44875:28;44918:10;:33;;44914:108;;44974:37;;;;;;;;;;;;;;44914:108;45040:36;;;:66;;;;;;;;;;;;;;45121:74;;14463::35;;;45121::26;;;;;;14451:2:35;14436:18;45121:74:26;14317:226:35;5818:140:16;5936:5;5923:11;5916:26;5818:140;;:::o;6999:169::-;7134:18;;6999:169::o;8171:123::-;8276:1;8263:11;8256:22;8171:123;:::o;6333:331::-;212:66:15;6432:36:16;;;6428:230;;;6531:5;6518:11;6511:26;18877:1491:26;;:::o;6428:230:16:-;6608:26;;6333:331::o;7546:360::-;7643:13;212:66:15;7672:36:16;;;7668:232;;;-1:-1:-1;7760:18:16;;7546:360::o;7668:232::-;-1:-1:-1;7858:18:16;;7668:232;7546:360;;;:::o;8602:310::-;212:66:15;8688:36:16;;;8684:222;;;8787:1;8774:11;8767:22;8475:586:26;:::o;8684:222:16:-;8880:1;8860:22;;8602:310::o;666:544:34:-;768:26;;;:10;:26;764:63;;666:544;:::o;764:63::-;838:21;864:23;874:12;864:9;:23::i;:::-;-1:-1:-1;837:50:34;-1:-1:-1;901:27:34;;;:10;:27;897:64;;944:7;666:544;:::o;897:64::-;972:26;1003:72;1015:12;972:26;1064:10;1003:11;:72::i;:::-;971:104;;;1089:21;1085:58;;;1126:7;;666:544;:::o;1085:58::-;1160:43;;;;;;;;;;;;;;8110:150:22;8180:4;8203:50;8208:3;8228:23;;;8203:4;:50::i;:::-;8196:57;8110:150;-1:-1:-1;;;8110:150:22:o;8428:156::-;8501:4;8524:53;8532:3;8552:23;;;8524:7;:53::i;2527:715:34:-;2657:26;;;:10;:26;2653:63;;2527:715;;:::o;2653:63::-;2727:21;2753:23;2763:12;2753:9;:23::i;:::-;-1:-1:-1;2726:50:34;-1:-1:-1;2790:27:34;;;:10;:27;2786:64;;2833:7;2527:715;;:::o;2786:64::-;2861:26;2892:72;2904:12;2861:26;2953:10;2892:11;:72::i;:::-;2860:104;;;2978:21;2974:58;;;3015:7;;2527:715;;:::o;2974:58::-;3043:18;3066:43;3078:12;3092:4;3098:10;3066:11;:43::i;:::-;3042:67;;;3123:13;3119:50;;;3152:7;;;2527:715;;:::o;3119:50::-;3186:49;;;;;;;;;;;;;;79566:912:26;79723:17;79764:707;79816:472;79872:8;79898:29;;79953:34;;;80030:29;;;;;;;;:::i;:::-;80014:47;;80104:21;;;;;;;;:::i;:::-;80088:39;;80154:21;;;;80202:24;;;;80253:20;;;;15956:4:14;15950:11;;15996:5;15987:15;;15974:29;;16017:19;;;16065:4;16056:14;;16049:30;;;;16099:14;;;16092:30;;;;16151:4;16142:14;;16135:30;;;;16194:4;16185:14;;16178:30;16237:4;16228:14;;16221:30;16280:4;16271:14;;16264:30;16323:4;16314:14;;16307:30;15950:11;15675:678;79816:472:26;80310:22;;;;80371:16;;;;;;;;:::i;:::-;80355:34;;80428:30;;;;:23;;;:30;:::i;:::-;80412:48;;16908:5:14;16899:15;;16892:31;;;;16952:5;16943:15;;16936:32;16997:5;16988:15;;16981:32;17050:5;17035:21;;;16688:384;79764:707:26;79752:719;79566:912;-1:-1:-1;;;;79566:912:26:o;1338:368:21:-;599:1;1465:38;445:66;1465:12;:38;;:::i;:::-;:49;1461:117;;1537:30;;;;;;;;;;;;;;1461:117;1652:47;445:66;599:1;1652:12;:47;;:::i;86666:445:26:-;86894:10;86833:8;:36;;;;86922:22;;86918:177;;86968:18;86990:2;86968:24;86964:75;;87001:38;;;;;;;;;;;;;;86964:75;87068:12;:10;:12::i;:::-;87057:23;;86918:177;86780:325;86666:445;;;:::o;60477:712::-;60719:20;;;60575:35;60719:20;;;:13;:20;;;;;60764:14;;60719:20;;;60764:14;;;;;90309:16;60788:136;;60863:50;;;;;;;;;;;;;;60788:136;5540:6:23;90309:16:26;;90308:23;60933:250;;61024:45;:24;;;61058:10;61024:33;:45::i;:::-;61019:154;;61096:62;;;;;;;;;;;;;;61019:154;60644:545;60477:712;;;:::o;63212:1111::-;63442:9;63465:25;;;;63461:856;;63510:9;:13;63506:108;;63550:49;;;;;;;;;;;;;;63506:108;63657:56;;;;;:29;14481:55:35;;;63657:56:26;;;14463:74:35;63627:27:26;;63657:29;;;;;;14436:18:35;;63657:56:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63627:86;;63727:12;63742:92;63769:11;63782:8;63800:16;63819:14;63742:26;:92::i;:::-;63727:107;;63852:7;63848:101;;;63886:48;;;;;;;;;;;;;;63848:101;63991:56;;;;;:29;14481:55:35;;;63991:56:26;;;14463:74:35;63962:26:26;;63991:29;;;;;;14436:18:35;;63991:56:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63962:85;;64086:19;64065:18;:40;64061:134;;;64132:48;;;;;;;;;;;;;;64061:134;64252:40;;;;;63212:1111;-1:-1:-1;;;;;;63212:1111:26:o;67205:702::-;67497:82;;;;;:26;22549:55:35;;;67497:82:26;;;22531:74:35;22621:18;;;22614:34;;;22664:18;;;22657:34;;;67425:17:26;;;;67497:26;;;;;67531:9;;22504:18:35;;67497:82:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67411:168;;-1:-1:-1;67411:168:26;-1:-1:-1;67594:24:26;;67590:220;;67634:165;67676:16;67710:11;67739:8;67765:20;67634:24;:165::i;:::-;67867:8;67825:75;;67848:16;67825:75;;;67877:11;67890:9;67825:75;;;;;;14238:25:35;;;14294:2;14279:18;;14272:34;14226:2;14211:18;;14064:248;67825:75:26;;;;;;;;67401:506;;67205:702;;;;;:::o;1712:106:21:-;1760:51;445:66;557:1;1760:12;:51;;:::i;82091:480:26:-;82278:12;82320:15;82306:11;;:29;82302:93;;;82358:26;;;;;;;;;;;;;;82302:93;82413:14;82430:84;82440:27;82457:9;82440:16;:27::i;:::-;82502:11;82430:84;;82475:11;82430:84;;82489:11;82430:84;;;;;;23179:25:35;;;;23252:4;82475:11:26;;23240:17:35;23220:18;;;23213:45;82489:11:26;;;;23274:18:35;;;23267:34;82502:11:26;;;23317:18:35;;;23310:34;23151:19;;82430:84:26;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;82430:84:26;;;;;;-1:-1:-1;82535:29:26;;-1:-1:-1;82535:12:26;82430:84;82535:21;:29::i;:::-;82525:39;82091:480;-1:-1:-1;;;;;82091:480:26:o;84012:896::-;84182:12;84235:15;84210:11;:22;;;:40;84206:117;;;84273:39;;;;;;;;;;;;;;84206:117;84352:15;84336:13;;;;:31;84332:95;;;84390:26;;;;;;;;;;;;;;84332:95;84643:11;8912::14;;8958:4;8949:14;;;8936:28;;2315:89:23;8978:19:14;;84584:11:26;;84614;9017:14:14;;;9010:30;;;;84614:11:26;;;;9060:14:14;;;9053:30;84643:11:26;;;;9112:4:14;9103:14;;9096:30;84680:22:26;;;;9155:4:14;9146:14;;9139:30;84729:26:26;;;9198:4:14;9189:14;;9182:30;9246:20;84437:23:26;;84463:317;;:16;:317::i;84493:277::-;84463:16;:317::i;:::-;84437:343;-1:-1:-1;84883:18:26;;;;:11;:18;:::i;:::-;84801:100;;:78;84811:15;84834:11;:13;;;84850:11;:13;;;84865:11;:13;;;84801:78;;;;;;;;;;;;;;;;;23179:25:35;;;23252:4;23240:17;;;;23235:2;23220:18;;23213:45;23289:2;23274:18;;23267:34;23332:2;23317:18;;23310:34;23166:3;23151:19;;22952:398;84801:78:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:100;;;84791:110;;84196:712;84012:896;;;;;:::o;87605:360::-;87709:19;87758:16;87744:30;;87740:106;;;87797:38;;;;;;;;;;;;;;87740:106;-1:-1:-1;87944:2:26;87915:16;87935:12;87914:33;87893:55;;87605:360::o;76875:2274::-;77096:29;77127:18;77186:15;77161:11;:22;;;:40;77157:111;;;77224:33;;;;;;;;;;;;;;77157:111;77277:22;77302:74;1989:240:23;77335:27:26;;;;:10;:27;:::i;:::-;77364:11;77302:16;:74::i;:::-;77277:99;;77392:76;77416:12;77430:14;77446:11;:21;;77392:23;:76::i;:::-;77387:159;;77491:44;;;;;;;;;;;;;;77387:159;77601:1;77559:30;;;;:23;;;:30;:::i;:::-;:44;;;77555:238;;77624:78;77645:8;77655:11;:21;;77678:11;:23;;77624:20;:78::i;:::-;77619:164;;77729:39;;;;;;;;;;;;;;77619:164;77816:21;;;;;-1:-1:-1;77871:34:26;77816:21;77871;;;;:34;:::i;:::-;77847:58;-1:-1:-1;77960:1:26;77919:29;;;;;;;;:::i;:::-;:43;;;77915:414;;78021:29;;;;;;;;:::i;:::-;78002:61;;;6852:1:23;78128:8:26;78154:27;;;;:10;:27;:::i;:::-;78199:21;;;;;;;;:::i;:::-;78238;78277:27;;;;:11;:27;:::i;:::-;78002:316;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;77978:340;;77915:414;78339:31;78373:29;;;:13;:29;;;;;78416:23;;;;78412:95;;;78462:34;;;;;;;;;;;;;;78412:95;78520:20;;;;:24;78516:284;;78560:16;78602:10;78579:9;:20;;;:33;;;;:::i;:::-;78560:52;;78641:11;:20;;;78630:8;:31;78626:119;;;78688:42;;;;;;;;;;;;;;78626:119;78758:20;;;:31;78516:284;78813:24;;;;:28;78809:334;;78876:39;;;78857:16;78876:39;;;:29;;;:39;;;;;;:52;;78918:10;;78876:52;:::i;:::-;78857:71;;78957:11;:24;;;78946:8;:35;78942:127;;;79008:46;;;;;;;;;;;;;;78942:127;79082:39;;;;;;;:29;;;:39;;;;;:50;78809:334;77147:2002;;76875:2274;;;;;;;:::o;10291:407:16:-;10374:7;10636:17;:28;;10683:2;10671:9;:14;;;;:::i;:::-;10636:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;10627:64:16;;10291:407;-1:-1:-1;;;10291:407:16:o;1824:133:21:-;1897:53;445:66;1897:27;:53::i;10064:300:22:-;10127:16;10155:22;10180:19;10188:3;10180:7;:19::i;1427:482:19:-;1483:18;1541:37;;;469:35;1541:37;;;;;1601:17;;;;;;1541:37;1677:15;1657:17;;;;;;:35;1653:240;;;1725:31;;;;;;;;24968:25:35;;;1725:11:19;:25;;;;;24941:18:35;;1725:31:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1774:30;;1822:56;;;1774:30;;;1822:56;;;;1867:10;1774:30;;;;;;;1867:10;;;;;;1849:15;:28;1822:56;;;;;;;1774:30;1427:482;-1:-1:-1;;1427:482:19:o;85547:722:26:-;85724:12;85739:78;85766:11;85787:16;85806:2;85810:6;85739:26;:78::i;:::-;85724:93;;85831:7;85827:436;;;85993:16;:41;;;:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86060:78;86087:11;86108:16;86127:2;86131:6;86060:26;:78::i;:::-;86050:88;;86156:7;86152:101;;;86190:48;;;;;;;;;;;;;;86152:101;85714:555;85547:722;;;;:::o;90762:276::-;90846:5;90867:7;90863:169;;;-1:-1:-1;90898:16:26;;;90890:25;;90863:169;-1:-1:-1;;90995:3:26;:10;90982:24;;90762:276::o;72601:2257::-;72875:15;72850:11;:22;;;:40;72846:111;;;72913:33;;;;;;;;;;;;;;72846:111;72966:17;72986:62;1671:238:23;73018:16:26;73036:11;72986:16;:62::i;:::-;72966:82;;73064:71;73088:12;73102:9;73113:11;:21;;73064:23;:71::i;:::-;73059:154;;73158:44;;;;;;;;;;;;;;73059:154;73268:1;73226:30;;;;:23;;;:30;:::i;:::-;:44;;;73222:238;;73291:78;73312:8;73322:11;:21;;73345:11;:23;;73291:20;:78::i;:::-;73286:164;;73396:39;;;;;;;;;;;;;;73286:164;73494:21;;;;73470;73529:29;;;;;;;;:::i;:::-;:43;;;73525:394;;73623:29;;;;;;;;:::i;:::-;73604:61;;;6690:1:23;73729:8:26;73755:16;73789:21;;;;;;;;:::i;:::-;73828;;;;73867:27;;;;73828:11;73867:27;:::i;:::-;73604:304;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;73588:320;;73525:394;73948:13;73933:12;:28;73929:110;;;73984:44;;;;;;;;;;;;;;73929:110;74049:31;74083:24;;;:13;:24;;;;;74121:23;;;;74117:95;;;74167:34;;;;;;;;;;;;;;74117:95;74225:20;;;;:24;74221:286;;74265:16;74307:12;74284:9;:20;;;:35;;;;:::i;:::-;74265:54;;74348:11;:20;;;74337:8;:31;74333:119;;;74395:42;;;;;;;;;;;;;;74333:119;74465:20;;;:31;74221:286;74520:24;;;;:28;74516:336;;74583:39;;;74564:16;74583:39;;;:29;;;:39;;;;;;:54;;74625:12;;74583:54;:::i;:::-;74564:73;;74666:11;:24;;;74655:8;:35;74651:127;;;74717:46;;;;;;;;;;;;;;74651:127;74791:39;;;;;;;:29;;;:39;;;;;:50;74516:336;72836:2022;;;72601:2257;;;;;:::o;75130:712::-;75473:20;75411:83;;;;;:27;22549:55:35;;;75411:83:26;;;22531:74:35;75449:22:26;;;;22621:18:35;;;22614:34;75473:20:26;;;;22664:18:35;;;22657:34;75300:19:26;;;;;;75411:27;;;;;22504:18:35;;75411:83:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;75286:208;;;;;;75553:8;75510:91;;75534:16;75510:91;;;75563:9;:22;;;75587:13;75510:91;;;;;;14238:25:35;;;14294:2;14279:18;;14272:34;14226:2;14211:18;;14064:248;75510:91:26;;;;;;;;75616:26;;75612:224;;75658:167;75700:16;75734:11;75763:8;75789:22;75658:24;:167::i;:::-;75276:566;;;75130:712;;;:::o;61359:982::-;61552:26;;;61519:30;61552:26;;;:13;:26;;;;;;;;61603:14;;61552:26;;61603:14;;;;90309:16;90308:23;61627:250;;61718:45;:24;;;61752:10;61718:33;:45::i;:::-;61713:154;;61790:62;;;;;;;;;;;;;;61713:154;5684:6:23;90309:16:26;;90308:23;61886:449;;61960:71;62009:8;62019:11;61960:48;:71::i;:::-;61955:370;;62056:50;:31;;;62097:8;62056:40;:50::i;:::-;62051:260;;62135:51;:28;;;62173:12;62135:37;:51::i;:::-;62130:163;;62221:49;;;;;;;;;;;;;;88457:482;88665:14;88682:87;88712:47;88738:20;88712:25;:47::i;88682:87::-;88665:104;;88785:67;88813:6;88821:9;88832:19;88785:27;:67::i;:::-;88780:153;;88875:47;;;;;;;;;;;;;;88780:153;88655:284;88457:482;;;:::o;65368:1453::-;65643:21;65680:25;;;65676:118;;65728:55;;;;;;;;;;;;;;65676:118;65834:47;;;;;:29;14481:55:35;;;65834:47:26;;;14463:74:35;65804:27:26;;65834:29;;;;;;14436:18:35;;65834:47:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65804:77;-1:-1:-1;65892:12:26;65916:30;;;;:14;:30;:::i;:::-;65907:82;;;66003:11;66028:14;:20;;;66062:14;:27;;;66103:14;:25;;;66142:8;66164:16;66194:8;:22;;;66230:54;66262:8;66272:11;66230:31;:54::i;:::-;2531:417:23;66359:14:26;:27;;;;;;;;:::i;:::-;65907:489;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65892:504;;66410:7;66406:86;;;66440:41;;;;;;;;;;;;;;66406:86;66531:47;;;;;:29;14481:55:35;;;66531:47:26;;;14463:74:35;66502:26:26;;66531:29;;;;;;14436:18:35;;66531:47:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66502:76;;66613:19;66592:18;:40;66588:126;;;66655:48;;;;;;;;;;;;;;66588:126;66764:40;;;;;65368:1453;-1:-1:-1;;;;;;;;65368:1453:26:o;69046:2607::-;69356:16;69293:19;;69396:16;;;;;;;;:::i;:::-;:30;;;;;;-1:-1:-1;69436:2211:26;;69496:15;69471:11;:22;;;:40;69467:119;;;69538:33;;;;;;;;;;;;;;69467:119;69599:17;69619:61;1348:236:23;69650:16:26;69668:11;69619:16;:61::i;:::-;69599:81;;69700:71;69724:12;69738:9;69749:11;:21;;69700:23;:71::i;:::-;69695:162;;69798:44;;;;;;;;;;;;;;69695:162;69916:1;69874:30;;;;:23;;;:30;:::i;:::-;:44;;;69870:254;;69943:78;69964:8;69974:11;:21;;69997:11;:23;;69943:20;:78::i;:::-;69938:172;;70052:39;;;;;;;;;;;;;;69938:172;70161:21;;;;70138:20;70200:29;;;;;;;;:::i;:::-;:43;;;70196:428;;70297:29;;;;;;;;:::i;:::-;70278:61;;;6530:1:23;70410:8:26;70440:16;70478:21;;;;;;;;:::i;:::-;70521;;;;70564:27;;;;70521:11;70564:27;:::i;:::-;70278:331;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70263:346;;70196:428;70656:12;70642:11;:26;70638:116;;;70695:44;;;;;;;;;;;;;;70638:116;70768:31;70802:24;;;:13;:24;;;;;70844:23;;;;70840:103;;;70894:34;;;;;;;;;;;;;;70840:103;70960:20;;;;:24;70956:309;;71004:16;71046:11;71023:9;:20;;;:34;;;;:::i;:::-;71004:53;;71090:11;:20;;;71079:8;:31;71075:127;;;71141:42;;;;;;;;;;;;;;71075:127;71219:20;;;:31;70956:309;71282:24;;;;:28;71278:359;;71349:39;;;71330:16;71349:39;;;:29;;;:39;;;;;;:53;;71391:11;;71349:53;:::i;:::-;71330:72;;71435:11;:24;;;71424:8;:35;71420:135;;;71490:46;;;;;;;;;;;;;;71420:135;71572:39;;;;;;;:29;;;:39;;;;;:50;71278:359;69453:2194;;;69436:2211;69046:2607;;;;;;;;:::o;3816:574:34:-;3892:13;3907:12;3970:349;;;4056:10;4050:4;4043:24;4008:6;4016:8;4178:4;4172;4166;4160;4145:13;4138:5;4127:56;4119:4;4101:16;4098:26;4091:34;4087:97;4084:188;;;4223:4;4217:11;4207:21;;3970:349;;;:::o;4084:188::-;-1:-1:-1;3970:349:34;4301:4;;-1:-1:-1;3970:349:34:o;:::-;4350:24;4361:12;4350:24;:::i;:::-;4332:42;;;;3816:574;;;:::o;5172:852::-;5297:12;5311;5374:560;;;5431:8;5441;5485:4;5479:11;5529:4;5524:3;5520:14;5514:4;5507:28;5564:10;5559:3;5552:23;5615:5;5609:3;5603:4;5599:14;5592:29;5661:8;5655:3;5649:4;5645:14;5638:32;5791:4;5785;5779;5772;5767:3;5763:14;5748:13;5741:5;5730:66;5722:4;5704:16;5701:26;5694:34;5690:107;5687:200;;;5838:4;5832:11;5820:23;;5864:5;;;5687:200;;5916:4;5904:16;;5374:560;;;;;;;:::o;:::-;5967:41;6000:7;5994:4;5980:12;5967:41;:::i;:::-;5947:61;;;;5172:852;;;;;;:::o;2035:406:22:-;2098:4;4154:21;;;:14;;;:21;;;;;;2114:321;;-1:-1:-1;2156:23:22;;;;;;;;:11;:23;;;;;;;;;;;;;2338:18;;2314:21;;;:14;;;:21;;;;;;:42;;;;2370:11;;2114:321;-1:-1:-1;2419:5:22;2412:12;;2609:1368;2675:4;2804:21;;;:14;;;:21;;;;;;2840:13;;2836:1135;;3207:18;3228:12;3239:1;3228:8;:12;:::i;:::-;3274:18;;3207:33;;-1:-1:-1;3254:17:22;;3274:22;;3295:1;;3274:22;:::i;:::-;3254:42;;3329:9;3315:10;:23;3311:378;;3358:17;3378:3;:11;;3390:9;3378:22;;;;;;;;:::i;:::-;;;;;;;;;3358:42;;3525:9;3499:3;:11;;3511:10;3499:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;3638:25;;;:14;;;:25;;;;;:36;;;3311:378;3767:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;3870:3;:14;;:21;3885:5;3870:21;;;;;;;;;;;3863:28;;;3913:4;3906:11;;;;;;;2836:1135;3955:5;3948:12;;;;;1119:596:8;1211:39;;;;;1239:10;1211:39;;;14463:74:35;1181:14:8;;1211:8;:27;;;;;14436:18:35;;1211:39:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1207:502;;;1289:2;1270:8;:21;1266:377;;-1:-1:-1;1522:23:8;1526:14;1522:23;1509:37;1505:2;1501:46;1119:596;:::o;1266:377::-;-1:-1:-1;719:10:3;;1119:596:8:o;1610:18::-;1603:25;;1119:596;:::o;8665:165:22:-;8798:23;;;8745:4;4154:21;;;:14;;;:21;;;;;;:26;;8768:55;4058:129;1992:1075:12;2137:12;2184:794;;;2250:8;2294:4;2288:11;2338:4;2333:3;2329:14;2323:4;2316:28;2373:10;2368:3;2361:23;2424:5;2418:3;2412:4;2408:14;2401:29;2470:3;2464;2458:4;2454:14;2447:27;2514:7;2508:3;2502:4;2498:14;2491:31;2600:4;2594;2588;2581;2576:3;2572:14;2569:1;2554:13;2547:5;2542:63;2539:392;;;2652:4;2634:16;2631:26;2628:154;;;-1:-1:-1;;2703:26:12;;2696:34;2755:5;;2628:154;2830:4;2824;2818;2803:32;-1:-1:-1;;2881:4:12;2875:11;2868:19;2908:5;;2539:392;-1:-1:-1;2960:4:12;;2184:794;-1:-1:-1;;;;;2184:794:12:o;:::-;3002:49;3044:6;3040:2;3034:4;3020:12;3002:49;:::i;4292:165:2:-;4369:7;4395:55;4417:20;:18;:20::i;:::-;4439:10;8536:4:5;8530:11;8566:10;8554:23;;8606:4;8597:14;;8590:39;;;;8658:4;8649:14;;8642:34;8712:4;8697:20;;;8336:397;9120:287:16;212:66:15;9201:36:16;;;9197:204;;;9306:11;9300:18;9287:11;9280:39;8475:586:26;:::o;9197:204:16:-;9370:20;;;;;;;;;;;;;;5375:109:22;5431:16;5466:3;:11;;5459:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5375:109;;;:::o;1638:518:34:-;1766:24;1816:12;1806:22;;:6;:22;;;1802:64;;-1:-1:-1;1851:4:34;1844:11;;1802:64;1877:21;1903:23;1913:12;1903:9;:23::i;:::-;1876:50;;;1950:13;1940:23;;:6;:23;;;1936:65;;1986:4;1979:11;;;;;1936:65;2012:26;2043:68;2055:12;2012:26;2104:6;2043:11;:68::i;:::-;-1:-1:-1;2011:100:34;1638:518;-1:-1:-1;;;;;1638:518:34:o;89246:592:26:-;89356:12;89387:444;1097:166:23;89485:33:26;;;;:20;:33;:::i;:::-;89469:51;;89535:30;;;;89603:33;;;;;;;;:::i;:::-;89587:51;;89669:59;;;;;;;;:::i;:::-;:67;;89735:1;89669:67;;;89731:1;89669:67;89661:76;;89768:43;;;;;;;;:::i;:::-;:51;;89818:1;89768:51;;;89814:1;89768:51;89760:60;;8918:4:14;8912:11;;8958:4;8949:14;;;8936:28;;8978:19;;;9026:4;9017:14;;9010:30;;;;9060:14;;9053:30;;;;9112:4;9103:14;;9096:30;;;;9155:4;9146:14;;9139:30;9198:4;9189:14;;9182:30;9246:20;;8675:607;83119:380:26;83279:12;83321:15;83307:11;;:29;83303:93;;;83359:26;;;;;;;;;;;;;;83303:93;83480:11;83429:63;;83453:11;83429:63;;83467:11;83429:63;;;;;;23179:25:35;;;23252:4;83453:11:26;;23240:17:35;23220:18;;;23213:45;83467:11:26;;;23274:18:35;;;23267:34;83480:11:26;;;;23317:18:35;;;23310:34;83429:63:26;;23151:19:35;;83429:63:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83416:76;;:9;:76;;;83406:86;;83119:380;;;;;:::o;80771:746::-;80918:12;80949:561;80999:464;3087:218:23;81126:25:26;;;;:8;:25;:::i;:::-;81110:43;;81180:20;;;;81227:22;;;;81268:29;;81339:16;;;;;;;;:::i;:::-;81323:34;;81384:21;;;:23;81426;;;;12377:4:14;12371:11;;12417:5;12408:15;;12395:29;;12438:19;;;12486:4;12477:14;;12470:30;;;;12520:14;;;12513:30;;;;12572:4;12563:14;;12556:30;;;;12615:4;12606:14;;12599:30;12658:4;12649:14;;12642:30;12701:4;12692:14;;12685:30;12744:4;12735:14;;12728:30;12371:11;12098:676;80999:464:26;81477:23;;;;13207:5:14;13198:15;;13191:31;13259:5;13244:21;;;13023:258;3251:230:2;3304:7;3344:14;3327:13;:31;3323:152;;-1:-1:-1;3381:22:2;;3251:230::o;3323:152::-;3441:23;3578:81;;;1857:95;3578:81;;;26591:25:35;3601:11:2;26632:18:35;;;26625:34;;;;3614:14:2;26675:18:35;;;26668:34;3630:13:2;26718:18:35;;;26711:34;3653:4:2;26761:19:35;;;26754:84;3542:7:2;;26563:19:35;;3578:81:2;;;;;;;;;;;;3568:92;;;;;;3561:99;;3487:180;:::o;14:154:35:-;100:42;93:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;173:134;241:20;;270:31;241:20;270:31;:::i;312:118::-;398:5;391:13;384:21;377:5;374:32;364:60;;420:1;417;410:12;435:128;500:20;;529:28;500:20;529:28;:::i;568:523::-;642:6;650;658;711:2;699:9;690:7;686:23;682:32;679:52;;;727:1;724;717:12;679:52;766:9;753:23;785:31;810:5;785:31;:::i;:::-;835:5;-1:-1:-1;892:2:35;877:18;;864:32;905:33;864:32;905:33;:::i;:::-;957:7;-1:-1:-1;1016:2:35;1001:18;;988:32;1029:30;988:32;1029:30;:::i;:::-;1078:7;1068:17;;;568:523;;;;;:::o;1096:160::-;1160:5;1205:3;1196:6;1191:3;1187:16;1183:26;1180:46;;;1222:1;1219;1212:12;1261:634;1366:6;1374;1382;1435:2;1423:9;1414:7;1410:23;1406:32;1403:52;;;1451:1;1448;1441:12;1403:52;1490:9;1477:23;1509:31;1534:5;1509:31;:::i;:::-;1559:5;-1:-1:-1;1615:2:35;1600:18;;1587:32;1642:18;1631:30;;1628:50;;;1674:1;1671;1664:12;1628:50;1697:71;1760:7;1751:6;1740:9;1736:22;1697:71;:::i;:::-;1687:81;;;1820:2;1809:9;1805:18;1792:32;1833:30;1855:7;1833:30;:::i;1900:247::-;1959:6;2012:2;2000:9;1991:7;1987:23;1983:32;1980:52;;;2028:1;2025;2018:12;1980:52;2067:9;2054:23;2086:31;2111:5;2086:31;:::i;2855:156::-;2916:5;2961:2;2952:6;2947:3;2943:16;2939:25;2936:45;;;2977:1;2974;2967:12;3016:240;3103:6;3156:2;3144:9;3135:7;3131:23;3127:32;3124:52;;;3172:1;3169;3162:12;3124:52;3195:55;3242:7;3231:9;3195:55;:::i;3261:180::-;3320:6;3373:2;3361:9;3352:7;3348:23;3344:32;3341:52;;;3389:1;3386;3379:12;3341:52;-1:-1:-1;3412:23:35;;3261:180;-1:-1:-1;3261:180:35:o;3709:640::-;3817:6;3825;3833;3886:2;3874:9;3865:7;3861:23;3857:32;3854:52;;;3902:1;3899;3892:12;3854:52;3941:9;3928:23;3960:31;3985:5;3960:31;:::i;:::-;4010:5;-1:-1:-1;4066:2:35;4051:18;;4038:32;4093:18;4082:30;;4079:50;;;4125:1;4122;4115:12;4079:50;4148:71;4211:7;4202:6;4191:9;4187:22;4148:71;:::i;:::-;4138:81;;;4271:2;4260:9;4256:18;4243:32;4284:33;4309:7;4284:33;:::i;4852:495::-;4981:6;4989;5042:3;5030:9;5021:7;5017:23;5013:33;5010:53;;;5059:1;5056;5049:12;5010:53;5082:55;5129:7;5118:9;5082:55;:::i;:::-;5072:65;;5188:2;5177:9;5173:18;5160:32;5215:18;5207:6;5204:30;5201:50;;;5247:1;5244;5237:12;5201:50;5270:71;5333:7;5324:6;5313:9;5309:22;5270:71;:::i;:::-;5260:81;;;4852:495;;;;;:::o;5544:681::-;5715:2;5767:21;;;5837:13;;5740:18;;;5859:22;;;5686:4;;5715:2;5938:15;;;;5912:2;5897:18;;;5686:4;5981:218;5995:6;5992:1;5989:13;5981:218;;;6060:13;;6075:42;6056:62;6044:75;;6174:15;;;;6139:12;;;;6017:1;6010:9;5981:218;;;-1:-1:-1;6216:3:35;;5544:681;-1:-1:-1;;;;;;5544:681:35:o;6230:388::-;6298:6;6306;6359:2;6347:9;6338:7;6334:23;6330:32;6327:52;;;6375:1;6372;6365:12;6327:52;6414:9;6401:23;6433:31;6458:5;6433:31;:::i;:::-;6483:5;-1:-1:-1;6540:2:35;6525:18;;6512:32;6553:33;6512:32;6553:33;:::i;:::-;6605:7;6595:17;;;6230:388;;;;;:::o;6623:342::-;6718:6;6726;6779:2;6767:9;6758:7;6754:23;6750:32;6747:52;;;6795:1;6792;6785:12;6747:52;6834:9;6821:23;6853:31;6878:5;6853:31;:::i;:::-;6903:5;6955:2;6940:18;;;;6927:32;;-1:-1:-1;;;6623:342:35:o;6970:517::-;7041:6;7049;7057;7110:2;7098:9;7089:7;7085:23;7081:32;7078:52;;;7126:1;7123;7116:12;7078:52;7165:9;7152:23;7184:31;7209:5;7184:31;:::i;:::-;7234:5;-1:-1:-1;7291:2:35;7276:18;;7263:32;7304:30;7263:32;7304:30;:::i;7991:535::-;8133:6;8141;8194:3;8182:9;8173:7;8169:23;8165:33;8162:53;;;8211:1;8208;8201:12;8162:53;8251:9;8238:23;8284:18;8276:6;8273:30;8270:50;;;8316:1;8313;8306:12;8270:50;8339:22;;8395:3;8377:16;;;8373:26;8370:46;;;8412:1;8409;8402:12;8370:46;8435:2;-1:-1:-1;8456:64:35;8512:7;8507:2;8492:18;;8456:64;:::i;:::-;8446:74;;7991:535;;;;;:::o;8531:642::-;8644:6;8652;8705:2;8693:9;8684:7;8680:23;8676:32;8673:52;;;8721:1;8718;8711:12;8673:52;8761:9;8748:23;8790:18;8831:2;8823:6;8820:14;8817:34;;;8847:1;8844;8837:12;8817:34;8885:6;8874:9;8870:22;8860:32;;8930:7;8923:4;8919:2;8915:13;8911:27;8901:55;;8952:1;8949;8942:12;8901:55;8992:2;8979:16;9018:2;9010:6;9007:14;9004:34;;;9034:1;9031;9024:12;9004:34;9087:7;9082:2;9072:6;9069:1;9065:14;9061:2;9057:23;9053:32;9050:45;9047:65;;;9108:1;9105;9098:12;9047:65;9139:2;9131:11;;;;;9161:6;;-1:-1:-1;8531:642:35;;-1:-1:-1;;;;8531:642:35:o;9466:382::-;9531:6;9539;9592:2;9580:9;9571:7;9567:23;9563:32;9560:52;;;9608:1;9605;9598:12;9560:52;9647:9;9634:23;9666:31;9691:5;9666:31;:::i;:::-;9716:5;-1:-1:-1;9773:2:35;9758:18;;9745:32;9786:30;9745:32;9786:30;:::i;9853:272::-;9911:6;9964:2;9952:9;9943:7;9939:23;9935:32;9932:52;;;9980:1;9977;9970:12;9932:52;10019:9;10006:23;10069:6;10062:5;10058:18;10051:5;10048:29;10038:57;;10091:1;10088;10081:12;10376:787;10546:6;10554;10562;10615:3;10603:9;10594:7;10590:23;10586:33;10583:53;;;10632:1;10629;10622:12;10583:53;10655:55;10702:7;10691:9;10655:55;:::i;:::-;10645:65;;10761:2;10750:9;10746:18;10733:32;10784:18;10825:2;10817:6;10814:14;10811:34;;;10841:1;10838;10831:12;10811:34;10864:71;10927:7;10918:6;10907:9;10903:22;10864:71;:::i;:::-;10854:81;;10988:3;10977:9;10973:19;10960:33;10944:49;;11018:2;11008:8;11005:16;11002:36;;;11034:1;11031;11024:12;11002:36;-1:-1:-1;11057:24:35;;11115:3;11097:16;;;11093:26;11090:46;;;11132:1;11129;11122:12;11168:315;11236:6;11244;11297:2;11285:9;11276:7;11272:23;11268:32;11265:52;;;11313:1;11310;11303:12;11265:52;11349:9;11336:23;11326:33;;11409:2;11398:9;11394:18;11381:32;11422:31;11447:5;11422:31;:::i;11488:483::-;11592:6;11600;11608;11661:2;11649:9;11640:7;11636:23;11632:32;11629:52;;;11677:1;11674;11667:12;11629:52;11716:9;11703:23;11735:31;11760:5;11735:31;:::i;:::-;11785:5;-1:-1:-1;11842:2:35;11827:18;;11814:32;11855:33;11814:32;11855:33;:::i;:::-;11488:483;;11907:7;;-1:-1:-1;;;11961:2:35;11946:18;;;;11933:32;;11488:483::o;11976:251::-;12046:6;12099:2;12087:9;12078:7;12074:23;12070:32;12067:52;;;12115:1;12112;12105:12;12067:52;12147:9;12141:16;12166:31;12191:5;12166:31;:::i;12232:580::-;12309:4;12315:6;12375:11;12362:25;12465:66;12454:8;12438:14;12434:29;12430:102;12410:18;12406:127;12396:155;;12547:1;12544;12537:12;12396:155;12574:33;;12626:20;;;-1:-1:-1;12669:18:35;12658:30;;12655:50;;;12701:1;12698;12691:12;12655:50;12734:4;12722:17;;-1:-1:-1;12765:14:35;12761:27;;;12751:38;;12748:58;;;12802:1;12799;12792:12;12748:58;12232:580;;;;;:::o;13119:325::-;13207:6;13202:3;13195:19;13259:6;13252:5;13245:4;13240:3;13236:14;13223:43;;13311:1;13304:4;13295:6;13290:3;13286:16;13282:27;13275:38;13177:3;13433:4;13363:66;13358:2;13350:6;13346:15;13342:88;13337:3;13333:98;13329:109;13322:116;;13119:325;;;;:::o;13449:610::-;13681:4;13710:42;13791:2;13783:6;13779:15;13768:9;13761:34;13843:2;13835:6;13831:15;13826:2;13815:9;13811:18;13804:43;;13883:6;13878:2;13867:9;13863:18;13856:34;13926:6;13921:2;13910:9;13906:18;13899:34;13970:3;13964;13953:9;13949:19;13942:32;13991:62;14048:3;14037:9;14033:19;14025:6;14017;13991:62;:::i;:::-;13983:70;13449:610;-1:-1:-1;;;;;;;;13449:610:35:o;14548:245::-;14615:6;14668:2;14656:9;14647:7;14643:23;14639:32;14636:52;;;14684:1;14681;14674:12;14636:52;14716:9;14710:16;14735:28;14757:5;14735:28;:::i;15201:373::-;15289:6;15297;15305;15358:2;15346:9;15337:7;15333:23;15329:32;15326:52;;;15374:1;15371;15364:12;15326:52;15406:9;15400:16;15425:31;15450:5;15425:31;:::i;:::-;15520:2;15505:18;;15499:25;15564:2;15549:18;;;15543:25;15475:5;;15499:25;;-1:-1:-1;15543:25:35;15201:373;-1:-1:-1;;;15201:373:35:o;15852:400::-;15962:4;16020:11;16007:25;16110:66;16099:8;16083:14;16079:29;16075:102;16055:18;16051:127;16041:155;;16192:1;16189;16182:12;16041:155;16213:33;;;;;15852:400;-1:-1:-1;;15852:400:35:o;17053:560::-;17112:5;17119:6;17179:3;17166:17;17261:66;17250:8;17234:14;17230:29;17226:102;17206:18;17202:127;17192:155;;17343:1;17340;17333:12;17192:155;17371:33;;17475:4;17462:18;;;-1:-1:-1;17423:21:35;;-1:-1:-1;17503:18:35;17492:30;;17489:50;;;17535:1;17532;17525:12;17489:50;17582:6;17566:14;17562:27;17555:5;17551:39;17548:59;;;17603:1;17600;17593:12;17618:156;17684:20;;17744:4;17733:16;;17723:27;;17713:55;;17764:1;17761;17754:12;17859:2306;18157:6;18146:9;18139:25;18200:3;18195:2;18184:9;18180:18;18173:31;18120:4;18247:47;18287:6;18279;18247:47;:::i;:::-;18313:6;18356:2;18350:3;18339:9;18335:19;18328:31;18382:74;18451:3;18440:9;18436:19;18422:12;18408;18382:74;:::i;:::-;18368:88;;18503:56;18555:2;18547:6;18543:15;18535:6;18503:56;:::i;:::-;18465:94;;18578:66;18709:2;18697:9;18689:6;18685:22;18681:31;18675:3;18664:9;18660:19;18653:60;18736:65;18794:6;18778:14;18762;18736:65;:::i;:::-;18722:79;;18832:35;18861:4;18853:6;18849:17;18832:35;:::i;:::-;17846:4;17835:16;;18924:3;18909:19;;17823:29;18810:57;-1:-1:-1;18960:37:35;18991:4;18983:6;18979:17;18960:37;:::i;:::-;2325:42;2314:54;;19056:3;19041:19;;2302:67;18938:59;-1:-1:-1;19092:36:35;19123:3;19115:6;19111:16;19092:36;:::i;:::-;19070:58;;19147:3;19137:13;;19159:54;19209:2;19198:9;19194:18;19178:14;2325:42;2314:54;2302:67;;2248:127;19159:54;19232:3;19222:13;;19296:3;19288:6;19284:16;19271:30;19266:2;19255:9;19251:18;19244:58;19349:57;19401:3;19393:6;19389:16;19381:6;19349:57;:::i;:::-;19425:3;19492:2;19480:9;19472:6;19468:22;19464:31;19459:2;19448:9;19444:18;19437:59;19519:65;19577:6;19561:14;19545;19519:65;:::i;:::-;19505:79;;19615:36;19646:3;19638:6;19634:16;19615:36;:::i;:::-;2325:42;2314:54;;19695:18;;;2302:67;19593:58;-1:-1:-1;19745:32:35;19773:2;19765:6;19761:15;19745:32;:::i;:::-;2222:13;;2215:21;19833:3;19818:19;;2203:34;19723:54;-1:-1:-1;19869:35:35;19900:2;19892:6;19888:15;19869:35;:::i;:::-;2325:42;2314:54;19963:3;19948:19;;2302:67;20018:15;;20005:29;19999:3;19984:19;;19977:58;-1:-1:-1;;;;20089:4:35;20074:20;;20067:36;;;-1:-1:-1;;9254:6:35;9243:18;;20153:4;20138:20;;9231:31;20052:6;-1:-1:-1;20112:47:35;9178:90;20170:241;20226:6;20279:2;20267:9;20258:7;20254:23;20250:32;20247:52;;;20295:1;20292;20285:12;20247:52;20334:9;20321:23;20353:28;20375:5;20353:28;:::i;20416:184::-;20468:77;20465:1;20458:88;20565:4;20562:1;20555:15;20589:4;20586:1;20579:15;21700:435;21797:6;21805;21813;21821;21874:3;21862:9;21853:7;21849:23;21845:33;21842:53;;;21891:1;21888;21881:12;21842:53;21923:9;21917:16;21942:31;21967:5;21942:31;:::i;:::-;22037:2;22022:18;;22016:25;22081:2;22066:18;;22060:25;22125:2;22110:18;;;22104:25;21992:5;;22016:25;;-1:-1:-1;22104:25:35;;-1:-1:-1;21700:435:35;-1:-1:-1;;;21700:435:35:o;22140:184::-;22210:6;22263:2;22251:9;22242:7;22238:23;22234:32;22231:52;;;22279:1;22276;22269:12;22231:52;-1:-1:-1;22302:16:35;;22140:184;-1:-1:-1;22140:184:35:o;22702:245::-;22781:6;22789;22842:2;22830:9;22821:7;22817:23;22813:32;22810:52;;;22858:1;22855;22848:12;22810:52;-1:-1:-1;;22881:16:35;;22937:2;22922:18;;;22916:25;22881:16;;22916:25;;-1:-1:-1;22702:245:35:o;23355:184::-;23407:77;23404:1;23397:88;23504:4;23501:1;23494:15;23528:4;23525:1;23518:15;23544:168;23617:9;;;23648;;23665:15;;;23659:22;;23645:37;23635:71;;23686:18;;:::i;23717:691::-;24014:6;24003:9;23996:25;23977:4;24040:42;24130:2;24122:6;24118:15;24113:2;24102:9;24098:18;24091:43;24182:2;24174:6;24170:15;24165:2;24154:9;24150:18;24143:43;24234:2;24226:6;24222:15;24217:2;24206:9;24202:18;24195:43;;24275:6;24269:3;24258:9;24254:19;24247:35;24319:3;24313;24302:9;24298:19;24291:32;24340:62;24397:3;24386:9;24382:19;24374:6;24366;24340:62;:::i;:::-;24332:70;23717:691;-1:-1:-1;;;;;;;;;23717:691:35:o;24413:125::-;24478:9;;;24499:10;;;24496:36;;;24512:18;;:::i;24543:274::-;24583:1;24609;24599:189;;24644:77;24641:1;24634:88;24745:4;24742:1;24735:15;24773:4;24770:1;24763:15;24599:189;-1:-1:-1;24802:9:35;;24543:274::o;25004:1001::-;25377:4;25406:3;25428:42;25509:2;25501:6;25497:15;25486:9;25479:34;25549:6;25544:2;25533:9;25529:18;25522:34;25592:6;25587:2;25576:9;25572:18;25565:34;25635:6;25630:2;25619:9;25615:18;25608:34;25691:2;25683:6;25679:15;25673:3;25662:9;25658:19;25651:44;25744:2;25736:6;25732:15;25726:3;25715:9;25711:19;25704:44;;25785:6;25779:3;25768:9;25764:19;25757:35;25829:6;25823:3;25812:9;25808:19;25801:35;25873:6;25867:3;25856:9;25852:19;25845:35;25917:2;25911:3;25900:9;25896:19;25889:31;25937:62;25995:2;25984:9;25980:18;25971:7;25963:6;25937:62;:::i;:::-;25929:70;25004:1001;-1:-1:-1;;;;;;;;;;;;;;25004:1001:35:o;26010:128::-;26077:9;;;26098:11;;;26095:37;;;26112:18;;:::i;26143:184::-;26195:77;26192:1;26185:88;26292:4;26289:1;26282:15;26316:4;26313:1;26306:15

Swarm Source

ipfs://7cae73b79dc90cd174a99f75d535d37855c1458da313e1a09b872b7a98efbebc

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.