ETH Price: $3,007.42 (-4.07%)
 

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Send Reserved To...378736162025-11-07 17:29:3910 days ago1762536579IN
Juicebox: Controller (Deprecated) V4
0 ETH0.00000150.00807795
Send Reserved To...375179182025-10-30 11:53:0318 days ago1761825183IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000001540.00936624
Send Reserved To...375178832025-10-30 11:51:5318 days ago1761825113IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000001610.00937482
Send Reserved To...375178662025-10-30 11:51:1918 days ago1761825079IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000002030.01077921
Send Reserved To...375176542025-10-30 11:44:1518 days ago1761824655IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000001160.00678223
Send Reserved To...370720572025-10-20 4:11:0128 days ago1760933461IN
Juicebox: Controller (Deprecated) V4
0 ETH0.00000050.00296708
Set Split Groups...370713622025-10-20 3:47:5128 days ago1760932071IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000080.00118542
Set Uri Of368489932025-10-15 0:15:3334 days ago1760487333IN
Juicebox: Controller (Deprecated) V4
0 ETH0.00000020.00464244
Send Reserved To...363662542025-10-03 20:04:1545 days ago1759521855IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000490.00326985
Send Reserved To...362386242025-09-30 21:09:5548 days ago1759266595IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000002690.01313655
Set Uri Of357951912025-09-20 14:48:4958 days ago1758379729IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000350.00794111
Send Reserved To...357218472025-09-18 22:04:0160 days ago1758233041IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000660.00300183
Set Uri Of355570632025-09-15 2:31:1363 days ago1757903473IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000450.01029294
Launch Project F...354537692025-09-12 17:08:0566 days ago1757696885IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000004480.00780897
Send Reserved To...353721432025-09-10 19:47:1368 days ago1757533633IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000001340.00660831
Send Reserved To...353709392025-09-10 19:07:0568 days ago1757531225IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000090.00409887
Send Reserved To...353708952025-09-10 19:05:3768 days ago1757531137IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000720.00423364
Send Reserved To...342803802025-08-16 13:15:0793 days ago1755350107IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000580.00296537
Queue Rulesets O...342192832025-08-15 3:18:3394 days ago1755227913IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000430.00326874
Set Uri Of341525342025-08-13 14:13:3596 days ago1755094415IN
Juicebox: Controller (Deprecated) V4
0 ETH0.00000090.01999392
Send Reserved To...340088372025-08-10 6:23:4199 days ago1754807021IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000001160.00625868
Send Reserved To...339916792025-08-09 20:51:45100 days ago1754772705IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000003050.02062614
Set Uri Of337243792025-08-03 16:21:45106 days ago1754238105IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000080.00197278
Set Uri Of335512832025-07-30 16:11:53110 days ago1753891913IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000000570.01261459
Launch Project F...335504432025-07-30 15:43:53110 days ago1753890233IN
Juicebox: Controller (Deprecated) V4
0 ETH0.000008260.01434642
View all transactions

Latest 1 internal transaction

Parent Transaction Hash Block From To
264850172025-02-17 2:29:41273 days ago1739759381  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
JBController

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 58 : JBController.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {JBPermissionIds} from "@bananapus/permission-ids/src/JBPermissionIds.sol";
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {mulDiv} from "@prb/math/src/Common.sol";

import {JBPermissioned} from "./abstract/JBPermissioned.sol";
import {JBApprovalStatus} from "./enums/JBApprovalStatus.sol";
import {IJBController} from "./interfaces/IJBController.sol";
import {IJBDirectory} from "./interfaces/IJBDirectory.sol";
import {IJBDirectoryAccessControl} from "./interfaces/IJBDirectoryAccessControl.sol";
import {IJBFundAccessLimits} from "./interfaces/IJBFundAccessLimits.sol";
import {IJBMigratable} from "./interfaces/IJBMigratable.sol";
import {IJBPermissioned} from "./interfaces/IJBPermissioned.sol";
import {IJBPermissions} from "./interfaces/IJBPermissions.sol";
import {IJBPriceFeed} from "./interfaces/IJBPriceFeed.sol";
import {IJBPrices} from "./interfaces/IJBPrices.sol";
import {IJBProjects} from "./interfaces/IJBProjects.sol";
import {IJBProjectUriRegistry} from "./interfaces/IJBProjectUriRegistry.sol";
import {IJBRulesetDataHook} from "./interfaces/IJBRulesetDataHook.sol";
import {IJBRulesets} from "./interfaces/IJBRulesets.sol";
import {IJBSplitHook} from "./interfaces/IJBSplitHook.sol";
import {IJBSplits} from "./interfaces/IJBSplits.sol";
import {IJBTerminal} from "./interfaces/IJBTerminal.sol";
import {IJBToken} from "./interfaces/IJBToken.sol";
import {IJBTokens} from "./interfaces/IJBTokens.sol";
import {JBConstants} from "./libraries/JBConstants.sol";
import {JBRulesetMetadataResolver} from "./libraries/JBRulesetMetadataResolver.sol";
import {JBSplitGroupIds} from "./libraries/JBSplitGroupIds.sol";
import {JBRuleset} from "./structs/JBRuleset.sol";
import {JBRulesetConfig} from "./structs/JBRulesetConfig.sol";
import {JBRulesetMetadata} from "./structs/JBRulesetMetadata.sol";
import {JBRulesetWithMetadata} from "./structs/JBRulesetWithMetadata.sol";
import {JBSplit} from "./structs/JBSplit.sol";
import {JBSplitGroup} from "./structs/JBSplitGroup.sol";
import {JBSplitHookContext} from "./structs/JBSplitHookContext.sol";
import {JBTerminalConfig} from "./structs/JBTerminalConfig.sol";

/// @notice `JBController` coordinates rulesets and project tokens, and is the entry point for most operations related
/// to rulesets and project tokens.
contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigratable {
    // A library that parses packed ruleset metadata into a friendlier format.
    using JBRulesetMetadataResolver for JBRuleset;

    // A library that adds default safety checks to ERC20 functionality.
    using SafeERC20 for IERC20;

    //*********************************************************************//
    // --------------------------- custom errors ------------------------- //
    //*********************************************************************//

    error JBController_AddingPriceFeedNotAllowed();
    error JBController_CreditTransfersPaused();
    error JBController_InvalidCashOutTaxRate(uint256 rate, uint256 limit);
    error JBController_InvalidReservedPercent(uint256 percent, uint256 limit);
    error JBController_MintNotAllowedAndNotTerminalOrHook();
    error JBController_NoReservedTokens();
    error JBController_OnlyDirectory(address sender, IJBDirectory directory);
    error JBController_RulesetsAlreadyLaunched();
    error JBController_RulesetsArrayEmpty();
    error JBController_RulesetSetTokenNotAllowed();
    error JBController_ZeroTokensToBurn();
    error JBController_ZeroTokensToMint();

    //*********************************************************************//
    // --------------- public immutable stored properties ---------------- //
    //*********************************************************************//

    /// @notice The directory of terminals and controllers for projects.
    IJBDirectory public immutable override DIRECTORY;

    /// @notice A contract that stores fund access limits for each project.
    IJBFundAccessLimits public immutable override FUND_ACCESS_LIMITS;

    /// @notice A contract that stores prices for each project.
    IJBPrices public immutable override PRICES;

    /// @notice Mints ERC-721s that represent project ownership and transfers.
    IJBProjects public immutable override PROJECTS;

    /// @notice The contract storing and managing project rulesets.
    IJBRulesets public immutable override RULESETS;

    /// @notice The contract that stores splits for each project.
    IJBSplits public immutable override SPLITS;

    /// @notice The contract that manages token minting and burning.
    IJBTokens public immutable override TOKENS;

    //*********************************************************************//
    // --------------------- public stored properties -------------------- //
    //*********************************************************************//

    /// @notice A project's unrealized reserved token balance (i.e. reserved tokens which haven't been sent out to the
    /// reserved token split group yet).
    /// @custom:param projectId The ID of the project to get the pending reserved token balance of.
    mapping(uint256 projectId => uint256) public override pendingReservedTokenBalanceOf;

    /// @notice The metadata URI for each project. This is typically an IPFS hash, optionally with an `ipfs://` prefix.
    /// @custom:param projectId The ID of the project to get the metadata URI of.
    mapping(uint256 projectId => string) public override uriOf;

    //*********************************************************************//
    // ---------------------------- constructor -------------------------- //
    //*********************************************************************//

    /// @param directory A contract storing directories of terminals and controllers for each project.
    /// @param fundAccessLimits A contract that stores fund access limits for each project.
    /// @param permissions A contract storing permissions.
    /// @param prices A contract that stores prices for each project.
    /// @param projects A contract which mints ERC-721s that represent project ownership and transfers.
    /// @param rulesets A contract storing and managing project rulesets.
    /// @param splits A contract that stores splits for each project.
    /// @param tokens A contract that manages token minting and burning.
    /// @param trustedForwarder The trusted forwarder for the ERC2771Context.
    constructor(
        IJBDirectory directory,
        IJBFundAccessLimits fundAccessLimits,
        IJBPermissions permissions,
        IJBPrices prices,
        IJBProjects projects,
        IJBRulesets rulesets,
        IJBSplits splits,
        IJBTokens tokens,
        address trustedForwarder
    )
        JBPermissioned(permissions)
        ERC2771Context(trustedForwarder)
    {
        DIRECTORY = directory;
        FUND_ACCESS_LIMITS = fundAccessLimits;
        PRICES = prices;
        PROJECTS = projects;
        RULESETS = rulesets;
        SPLITS = splits;
        TOKENS = tokens;
    }

    //*********************************************************************//
    // ------------------------- external views -------------------------- //
    //*********************************************************************//

    /// @notice Get an array of a project's rulesets (with metadata) up to a maximum array size, sorted from latest to
    /// earliest.
    /// @param projectId The ID of the project to get the rulesets of.
    /// @param startingId The ID of the ruleset to begin with. This will be the latest ruleset in the result. If the
    /// `startingId` is 0, passed, the project's latest ruleset will be used.
    /// @param size The maximum number of rulesets to return.
    /// @return rulesets The array of rulesets with their metadata.
    function allRulesetsOf(
        uint256 projectId,
        uint256 startingId,
        uint256 size
    )
        external
        view
        override
        returns (JBRulesetWithMetadata[] memory rulesets)
    {
        // Get the rulesets (without metadata).
        JBRuleset[] memory baseRulesets = RULESETS.allOf(projectId, startingId, size);

        // Keep a reference to the number of rulesets.
        uint256 numberOfRulesets = baseRulesets.length;

        // Initialize the array being returned.
        rulesets = new JBRulesetWithMetadata[](numberOfRulesets);

        // Populate the array with rulesets AND their metadata.
        for (uint256 i; i < numberOfRulesets; i++) {
            // Set the ruleset being iterated on.
            JBRuleset memory baseRuleset = baseRulesets[i];

            // Set the returned value.
            rulesets[i] = JBRulesetWithMetadata({ruleset: baseRuleset, metadata: baseRuleset.expandMetadata()});
        }
    }

    /// @notice A project's currently active ruleset and its metadata.
    /// @param projectId The ID of the project to get the current ruleset of.
    /// @return ruleset The current ruleset's struct.
    /// @return metadata The current ruleset's metadata.
    function currentRulesetOf(uint256 projectId)
        external
        view
        override
        returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
    {
        ruleset = _currentRulesetOf(projectId);
        metadata = ruleset.expandMetadata();
    }

    /// @notice Get the `JBRuleset` and `JBRulesetMetadata` corresponding to the specified `rulesetId`.
    /// @param projectId The ID of the project the ruleset belongs to.
    /// @return ruleset The ruleset's struct.
    /// @return metadata The ruleset's metadata.
    function getRulesetOf(
        uint256 projectId,
        uint256 rulesetId
    )
        external
        view
        override
        returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
    {
        ruleset = RULESETS.getRulesetOf(projectId, rulesetId);
        metadata = ruleset.expandMetadata();
    }

    /// @notice Gets the latest ruleset queued for a project, its approval status, and its metadata.
    /// @dev The 'latest queued ruleset' is the ruleset initialized furthest in the future (at the end of the ruleset
    /// queue).
    /// @param projectId The ID of the project to get the latest ruleset of.
    /// @return ruleset The struct for the project's latest queued ruleset.
    /// @return metadata The ruleset's metadata.
    /// @return approvalStatus The ruleset's approval status.
    function latestQueuedRulesetOf(uint256 projectId)
        external
        view
        override
        returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata, JBApprovalStatus approvalStatus)
    {
        (ruleset, approvalStatus) = RULESETS.latestQueuedOf(projectId);
        metadata = ruleset.expandMetadata();
    }

    /// @notice Check whether the project's terminals can currently be set.
    /// @param projectId The ID of the project to check.
    /// @return A `bool` which is true if the project allows terminals to be set.
    function setTerminalsAllowed(uint256 projectId) external view returns (bool) {
        return _currentRulesetOf(projectId).expandMetadata().allowSetTerminals;
    }

    /// @notice Check whether the project's controller can currently be set.
    /// @param projectId The ID of the project to check.
    /// @return A `bool` which is true if the project allows controllers to be set.
    function setControllerAllowed(uint256 projectId) external view returns (bool) {
        return _currentRulesetOf(projectId).expandMetadata().allowSetController;
    }

    /// @notice Gets the a project token's total supply, including pending reserved tokens.
    /// @param projectId The ID of the project to get the total token supply of.
    /// @return The total supply of the project's token, including pending reserved tokens.
    function totalTokenSupplyWithReservedTokensOf(uint256 projectId) external view override returns (uint256) {
        // Add the reserved tokens to the total supply.
        return TOKENS.totalSupplyOf(projectId) + pendingReservedTokenBalanceOf[projectId];
    }

    /// @notice A project's next ruleset along with its metadata.
    /// @dev If an upcoming ruleset isn't found, returns an empty ruleset with all properties set to 0.
    /// @param projectId The ID of the project to get the next ruleset of.
    /// @return ruleset The upcoming ruleset's struct.
    /// @return metadata The upcoming ruleset's metadata.
    function upcomingRulesetOf(uint256 projectId)
        external
        view
        override
        returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
    {
        ruleset = _upcomingRulesetOf(projectId);
        metadata = ruleset.expandMetadata();
    }

    //*********************************************************************//
    // -------------------------- public views --------------------------- //
    //*********************************************************************//

    /// @notice Indicates whether this contract adheres to the specified interface.
    /// @dev See {IERC165-supportsInterface}.
    /// @param interfaceId The ID of the interface to check for adherence to.
    /// @return A flag indicating if the provided interface ID is supported.
    function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
        return interfaceId == type(IJBController).interfaceId || interfaceId == type(IJBProjectUriRegistry).interfaceId
            || interfaceId == type(IJBDirectoryAccessControl).interfaceId || interfaceId == type(IJBMigratable).interfaceId
            || interfaceId == type(IJBPermissioned).interfaceId || interfaceId == type(IERC165).interfaceId;
    }

    //*********************************************************************//
    // -------------------------- internal views ------------------------- //
    //*********************************************************************//

    /// @dev `ERC-2771` specifies the context as being a single address (20 bytes).
    function _contextSuffixLength() internal view override(ERC2771Context, Context) returns (uint256) {
        return super._contextSuffixLength();
    }

    /// @notice The project's current ruleset.
    /// @param projectId The ID of the project to check.
    /// @return The project's current ruleset.
    function _currentRulesetOf(uint256 projectId) internal view returns (JBRuleset memory) {
        return RULESETS.currentOf(projectId);
    }

    /// @notice Indicates whether the provided address is a terminal for the project.
    /// @param projectId The ID of the project to check.
    /// @param terminal The address to check.
    /// @return A flag indicating if the provided address is a terminal for the project.
    function _isTerminalOf(uint256 projectId, address terminal) internal view returns (bool) {
        return DIRECTORY.isTerminalOf(projectId, IJBTerminal(terminal));
    }

    /// @notice Indicates whether the provided address has mint permission for the project byway of the data hook.
    /// @param projectId The ID of the project to check.
    /// @param ruleset The ruleset to check.
    /// @param addrs The address to check.
    /// @return A flag indicating if the provided address has mint permission for the project.
    function _hasDataHookMintPermissionFor(
        uint256 projectId,
        JBRuleset memory ruleset,
        address addrs
    )
        internal
        view
        returns (bool)
    {
        return ruleset.dataHook() != address(0)
            && IJBRulesetDataHook(ruleset.dataHook()).hasMintPermissionFor(projectId, addrs);
    }

    /// @notice The calldata. Preferred to use over `msg.data`.
    /// @return calldata The `msg.data` of this call.
    function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
        return ERC2771Context._msgData();
    }

    /// @notice The message's sender. Preferred to use over `msg.sender`.
    /// @return sender The address which sent this call.
    function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
        return ERC2771Context._msgSender();
    }

    /// @notice The project's upcoming ruleset.
    /// @param projectId The ID of the project to check.
    /// @return The project's upcoming ruleset.
    function _upcomingRulesetOf(uint256 projectId) internal view returns (JBRuleset memory) {
        return RULESETS.upcomingOf(projectId);
    }

    //*********************************************************************//
    // --------------------- external transactions ----------------------- //
    //*********************************************************************//

    /// @notice Add a price feed for a project.
    /// @dev Can only be called by the project's owner or an address with the owner's permission to `ADD_PRICE_FEED`.
    /// @param projectId The ID of the project to add the feed for.
    /// @param pricingCurrency The currency the feed's output price is in terms of.
    /// @param unitCurrency The currency being priced by the feed.
    /// @param feed The address of the price feed to add.
    function addPriceFeed(
        uint256 projectId,
        uint256 pricingCurrency,
        uint256 unitCurrency,
        IJBPriceFeed feed
    )
        external
        override
    {
        // Enforce permissions.
        _requirePermissionFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.ADD_PRICE_FEED
        });

        JBRuleset memory ruleset = _currentRulesetOf(projectId);

        // Make sure the project's ruleset allows adding price feeds.
        if (!ruleset.allowAddPriceFeed()) revert JBController_AddingPriceFeedNotAllowed();

        PRICES.addPriceFeedFor({
            projectId: projectId,
            pricingCurrency: pricingCurrency,
            unitCurrency: unitCurrency,
            feed: feed
        });
    }

    /// @notice Burns a project's tokens or credits from the specific holder's balance.
    /// @dev Can only be called by the holder, an address with the holder's permission to `BURN_TOKENS`, or a project's
    /// terminal.
    /// @param holder The address whose tokens are being burned.
    /// @param projectId The ID of the project whose tokens are being burned.
    /// @param tokenCount The number of tokens to burn.
    /// @param memo A memo to pass along to the emitted event.
    function burnTokensOf(
        address holder,
        uint256 projectId,
        uint256 tokenCount,
        string calldata memo
    )
        external
        override
    {
        // Enforce permissions.
        _requirePermissionAllowingOverrideFrom({
            account: holder,
            projectId: projectId,
            permissionId: JBPermissionIds.BURN_TOKENS,
            alsoGrantAccessIf: _isTerminalOf(projectId, _msgSender())
        });

        // There must be tokens to burn.
        if (tokenCount == 0) revert JBController_ZeroTokensToBurn();

        emit BurnTokens({holder: holder, projectId: projectId, tokenCount: tokenCount, memo: memo, caller: _msgSender()});

        // Burn the tokens.
        TOKENS.burnFrom({holder: holder, projectId: projectId, count: tokenCount});
    }

    /// @notice Redeem credits to claim tokens into a `beneficiary`'s account.
    /// @dev Can only be called by the credit holder or an address with the holder's permission to `CLAIM_TOKENS`.
    /// @param holder The address to redeem credits from.
    /// @param projectId The ID of the project whose tokens are being claimed.
    /// @param tokenCount The number of tokens to claim.
    /// @param beneficiary The account the claimed tokens will go to.
    function claimTokensFor(
        address holder,
        uint256 projectId,
        uint256 tokenCount,
        address beneficiary
    )
        external
        override
    {
        // Enforce permissions.
        _requirePermissionFrom({account: holder, projectId: projectId, permissionId: JBPermissionIds.CLAIM_TOKENS});

        TOKENS.claimTokensFor({holder: holder, projectId: projectId, count: tokenCount, beneficiary: beneficiary});
    }

    /// @notice Deploys an ERC-20 token for a project. It will be used when claiming tokens (with credits).
    /// @dev Deploys the project's ERC-20 contract.
    /// @dev Can only be called by the project's owner or an address with the owner's permission to `DEPLOY_ERC20`.
    /// @param projectId The ID of the project to deploy the ERC-20 for.
    /// @param name The ERC-20's name.
    /// @param symbol The ERC-20's symbol.
    /// @param salt The salt used for ERC-1167 clone deployment. Pass a non-zero salt for deterministic deployment based
    /// on `msg.sender` and the `TOKEN` implementation address.
    /// @return token The address of the token that was deployed.
    function deployERC20For(
        uint256 projectId,
        string calldata name,
        string calldata symbol,
        bytes32 salt
    )
        external
        override
        returns (IJBToken token)
    {
        // Enforce permissions.
        _requirePermissionFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.DEPLOY_ERC20
        });

        if (salt != bytes32(0)) salt = keccak256(abi.encodePacked(_msgSender(), salt));

        return TOKENS.deployERC20For({projectId: projectId, name: name, symbol: symbol, salt: salt});
    }

    /// @notice When a project receives reserved tokens, if it has a terminal for the token, this is used to pay the
    /// terminal.
    /// @dev Can only be called by this controller.
    /// @param terminal The terminal to pay.
    /// @param projectId The ID of the project being paid.
    /// @param token The token being paid with.
    /// @param splitTokenCount The number of tokens being paid.
    /// @param beneficiary The payment's beneficiary.
    /// @param metadata The pay metadata sent to the terminal.
    function executePayReservedTokenToTerminal(
        IJBTerminal terminal,
        uint256 projectId,
        IJBToken token,
        uint256 splitTokenCount,
        address beneficiary,
        bytes calldata metadata
    )
        external
    {
        // Can only be called by this contract.
        require(msg.sender == address(this));

        // Approve the tokens being paid.
        IERC20(address(token)).forceApprove(address(terminal), splitTokenCount);

        // slither-disable-next-line unused-return
        terminal.pay({
            projectId: projectId,
            token: address(token),
            amount: splitTokenCount,
            beneficiary: beneficiary,
            minReturnedTokens: 0,
            memo: "",
            metadata: metadata
        });

        // Make sure that the terminal received the tokens.
        assert(IERC20(address(token)).allowance(address(this), address(terminal)) == 0);
    }

    /// @notice Creates a project.
    /// @dev This will mint the project's ERC-721 to the `owner`'s address, queue the specified rulesets, and set up the
    /// specified splits and terminals. Each operation within this transaction can be done in sequence separately.
    /// @dev Anyone can deploy a project to any `owner`'s address.
    /// @param owner The project's owner. The project ERC-721 will be minted to this address.
    /// @param projectUri The project's metadata URI. This is typically an IPFS hash, optionally with the `ipfs://`
    /// prefix. This can be updated by the project's owner.
    /// @param rulesetConfigurations The rulesets to queue.
    /// @param terminalConfigurations The terminals to set up for the project.
    /// @param memo A memo to pass along to the emitted event.
    /// @return projectId The project's ID.
    function launchProjectFor(
        address owner,
        string calldata projectUri,
        JBRulesetConfig[] calldata rulesetConfigurations,
        JBTerminalConfig[] calldata terminalConfigurations,
        string calldata memo
    )
        external
        override
        returns (uint256 projectId)
    {
        // Mint the project ERC-721 into the owner's wallet.
        // slither-disable-next-line reentrancy-benign
        projectId = PROJECTS.createFor(owner);

        // If provided, set the project's metadata URI.
        if (bytes(projectUri).length > 0) {
            uriOf[projectId] = projectUri;
        }

        // Set this contract as the project's controller in the directory.
        DIRECTORY.setControllerOf(projectId, IERC165(this));

        // Configure the terminals.
        _configureTerminals(projectId, terminalConfigurations);

        // Queue the rulesets.
        // slither-disable-next-line reentrancy-events
        uint256 rulesetId = _queueRulesets(projectId, rulesetConfigurations);

        emit LaunchProject({
            rulesetId: rulesetId,
            projectId: projectId,
            projectUri: projectUri,
            memo: memo,
            caller: _msgSender()
        });
    }

    /// @notice Queue a project's initial rulesets and set up terminals for it. Projects which already have rulesets
    /// should use `queueRulesetsOf(...)`.
    /// @dev Each operation within this transaction can be done in sequence separately.
    /// @dev Can only be called by the project's owner or an address with the owner's permission to `QUEUE_RULESETS`.
    /// @param projectId The ID of the project to launch rulesets for.
    /// @param rulesetConfigurations The rulesets to queue.
    /// @param terminalConfigurations The terminals to set up.
    /// @param memo A memo to pass along to the emitted event.
    /// @return rulesetId The ID of the last successfully queued ruleset.
    function launchRulesetsFor(
        uint256 projectId,
        JBRulesetConfig[] calldata rulesetConfigurations,
        JBTerminalConfig[] calldata terminalConfigurations,
        string calldata memo
    )
        external
        override
        returns (uint256 rulesetId)
    {
        // Make sure there are rulesets being queued.
        if (rulesetConfigurations.length == 0) revert JBController_RulesetsArrayEmpty();

        // Enforce permissions.
        _requirePermissionFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.QUEUE_RULESETS
        });

        // Enforce permissions.
        _requirePermissionFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.SET_TERMINALS
        });

        // If the project has already had rulesets, use `queueRulesetsOf(...)` instead.
        if (RULESETS.latestRulesetIdOf(projectId) > 0) {
            revert JBController_RulesetsAlreadyLaunched();
        }

        // Set this contract as the project's controller in the directory.
        DIRECTORY.setControllerOf(projectId, IERC165(this));

        // Configure the terminals.
        _configureTerminals(projectId, terminalConfigurations);

        // Queue the first ruleset.
        // slither-disable-next-line reentrancy-events
        rulesetId = _queueRulesets(projectId, rulesetConfigurations);

        emit LaunchRulesets({rulesetId: rulesetId, projectId: projectId, memo: memo, caller: _msgSender()});
    }

    /// @notice Migrate a project from this controller to another one.
    /// @dev Can only be called by the directory.
    /// @param projectId The ID of the project to migrate.
    /// @param to The controller to migrate the project to.
    function migrate(uint256 projectId, IERC165 to) external override {
        // Make sure this is being called by the directory.
        if (msg.sender != address(DIRECTORY)) revert JBController_OnlyDirectory(msg.sender, DIRECTORY);

        emit Migrate({projectId: projectId, to: to, caller: msg.sender});

        // Mint any pending reserved tokens before migrating.
        if (pendingReservedTokenBalanceOf[projectId] != 0) {
            _sendReservedTokensToSplitsOf(projectId);
        }
    }

    /// @notice Add new project tokens or credits to the specified beneficiary's balance. Optionally, reserve a portion
    /// according to the ruleset's reserved percent.
    /// @dev Can only be called by the project's owner, an address with the owner's permission to `MINT_TOKENS`, one of
    /// the project's terminals, or the project's data hook.
    /// @dev If the ruleset's metadata has `allowOwnerMinting` set to `false`, this function can only be called by the
    /// project's terminals or data hook.
    /// @param projectId The ID of the project whose tokens are being minted.
    /// @param tokenCount The number of tokens to mint, including any reserved tokens.
    /// @param beneficiary The address which will receive the (non-reserved) tokens.
    /// @param memo A memo to pass along to the emitted event.
    /// @param useReservedPercent Whether to apply the ruleset's reserved percent.
    /// @return beneficiaryTokenCount The number of tokens minted for the `beneficiary`.
    function mintTokensOf(
        uint256 projectId,
        uint256 tokenCount,
        address beneficiary,
        string calldata memo,
        bool useReservedPercent
    )
        external
        override
        returns (uint256 beneficiaryTokenCount)
    {
        // There should be tokens to mint.
        if (tokenCount == 0) revert JBController_ZeroTokensToMint();

        // Keep a reference to the reserved percent.
        uint256 reservedPercent;

        // Get a reference to the project's ruleset.
        JBRuleset memory ruleset = _currentRulesetOf(projectId);

        // Minting is restricted to: the project's owner, addresses with permission to `MINT_TOKENS`, the project's
        // terminals, and the project's data hook.
        _requirePermissionAllowingOverrideFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.MINT_TOKENS,
            alsoGrantAccessIf: _isTerminalOf(projectId, _msgSender()) || _msgSender() == ruleset.dataHook()
                || _hasDataHookMintPermissionFor(projectId, ruleset, _msgSender())
        });

        // If the message sender is not the project's terminal or data hook, the ruleset must have `allowOwnerMinting`
        // set to `true`.
        if (
            ruleset.id != 0 && !ruleset.allowOwnerMinting() && !_isTerminalOf(projectId, _msgSender())
                && _msgSender() != address(ruleset.dataHook())
                && !_hasDataHookMintPermissionFor(projectId, ruleset, _msgSender())
        ) revert JBController_MintNotAllowedAndNotTerminalOrHook();

        // Determine the reserved percent to use.
        reservedPercent = useReservedPercent ? ruleset.reservedPercent() : 0;

        if (reservedPercent != JBConstants.MAX_RESERVED_PERCENT) {
            // Calculate the number of (non-reserved) tokens that will be minted to the beneficiary.
            beneficiaryTokenCount =
                mulDiv(tokenCount, JBConstants.MAX_RESERVED_PERCENT - reservedPercent, JBConstants.MAX_RESERVED_PERCENT);

            // Mint the tokens.
            // slither-disable-next-line reentrancy-benign,reentrancy-events,unused-return
            TOKENS.mintFor({holder: beneficiary, projectId: projectId, count: beneficiaryTokenCount});
        }

        emit MintTokens({
            beneficiary: beneficiary,
            projectId: projectId,
            tokenCount: tokenCount,
            beneficiaryTokenCount: beneficiaryTokenCount,
            memo: memo,
            reservedPercent: reservedPercent,
            caller: _msgSender()
        });

        // Add any reserved tokens to the pending reserved token balance.
        if (reservedPercent > 0) {
            pendingReservedTokenBalanceOf[projectId] += tokenCount - beneficiaryTokenCount;
        }
    }

    /// @notice Add one or more rulesets to the end of a project's ruleset queue. Rulesets take effect after the
    /// previous ruleset in the queue ends, and only if they are approved by the previous ruleset's approval hook.
    /// @dev Can only be called by the project's owner or an address with the owner's permission to `QUEUE_RULESETS`.
    /// @param projectId The ID of the project to queue rulesets for.
    /// @param rulesetConfigurations The rulesets to queue.
    /// @param memo A memo to pass along to the emitted event.
    /// @return rulesetId The ID of the last ruleset which was successfully queued.
    function queueRulesetsOf(
        uint256 projectId,
        JBRulesetConfig[] calldata rulesetConfigurations,
        string calldata memo
    )
        external
        override
        returns (uint256 rulesetId)
    {
        // Make sure there are rulesets being queued.
        if (rulesetConfigurations.length == 0) revert JBController_RulesetsArrayEmpty();

        // Enforce permissions.
        _requirePermissionFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.QUEUE_RULESETS
        });

        // Queue the rulesets.
        // slither-disable-next-line reentrancy-events
        rulesetId = _queueRulesets(projectId, rulesetConfigurations);

        emit QueueRulesets({rulesetId: rulesetId, projectId: projectId, memo: memo, caller: _msgSender()});
    }

    /// @notice Prepares this controller to receive a project being migrated from another controller.
    /// @dev This controller should not be the project's controller yet.
    /// @param from The controller being migrated from.
    /// @param projectId The ID of the project that will migrate to this controller.
    function beforeReceiveMigrationFrom(IERC165 from, uint256 projectId) external override {
        // Keep a reference to the sender.
        address sender = _msgSender();

        // Make sure the sender is the expected source controller.
        if (sender != address(DIRECTORY)) revert JBController_OnlyDirectory(sender, DIRECTORY);

        // If the sending controller is an `IJBProjectUriRegistry`, copy the project's metadata URI.
        if (from.supportsInterface(type(IJBProjectUriRegistry).interfaceId)) {
            uriOf[projectId] = IJBProjectUriRegistry(address(from)).uriOf(projectId);
        }
    }

    /// @notice Sends a project's pending reserved tokens to its reserved token splits.
    /// @dev If the project has no reserved token splits, or if they don't add up to 100%, leftover tokens are sent to
    /// the project's owner.
    /// @param projectId The ID of the project to send reserved tokens for.
    /// @return The amount of reserved tokens minted and sent.
    function sendReservedTokensToSplitsOf(uint256 projectId) external override returns (uint256) {
        return _sendReservedTokensToSplitsOf(projectId);
    }

    /// @notice Sets a project's split groups. The new split groups must include any current splits which are locked.
    /// @dev Can only be called by the project's owner or an address with the owner's permission to `SET_SPLIT_GROUPS`.
    /// @param projectId The ID of the project to set the split groups of.
    /// @param rulesetId The ID of the ruleset the split groups should be active in. Use a `rulesetId` of 0 to set the
    /// default split groups, which are used when a ruleset has no splits set. If there are no default splits and no
    /// splits are set, all splits are sent to the project's owner.
    /// @param splitGroups An array of split groups to set.
    function setSplitGroupsOf(
        uint256 projectId,
        uint256 rulesetId,
        JBSplitGroup[] calldata splitGroups
    )
        external
        override
    {
        // Enforce permissions.
        _requirePermissionFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.SET_SPLIT_GROUPS
        });

        // Set the split groups.
        SPLITS.setSplitGroupsOf({projectId: projectId, rulesetId: rulesetId, splitGroups: splitGroups});
    }

    /// @notice Set a project's token. If the project's token is already set, this will revert.
    /// @dev Can only be called by the project's owner or an address with the owner's permission to `SET_TOKEN`.
    /// @param projectId The ID of the project to set the token of.
    /// @param token The new token's address.
    function setTokenFor(uint256 projectId, IJBToken token) external override {
        // Enforce permissions.
        _requirePermissionFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.SET_TOKEN
        });

        // Get a reference to the current ruleset.
        JBRuleset memory ruleset = _currentRulesetOf(projectId);

        // If there's no current ruleset, get a reference to the upcoming one.
        if (ruleset.id == 0) ruleset = _upcomingRulesetOf(projectId);

        // If owner minting is disabled for the ruleset, the owner cannot change the token.
        if (!ruleset.allowSetCustomToken()) revert JBController_RulesetSetTokenNotAllowed();

        TOKENS.setTokenFor({projectId: projectId, token: token});
    }

    /// @notice Set a project's metadata URI.
    /// @dev This is typically an IPFS hash, optionally with an `ipfs://` prefix.
    /// @dev Can only be called by the project's owner or an address with the owner's permission to
    /// `SET_PROJECT_URI`.
    /// @param projectId The ID of the project to set the metadata URI of.
    /// @param uri The metadata URI to set.
    function setUriOf(uint256 projectId, string calldata uri) external override {
        // Enforce permissions.
        _requirePermissionFrom({
            account: PROJECTS.ownerOf(projectId),
            projectId: projectId,
            permissionId: JBPermissionIds.SET_PROJECT_URI
        });

        // Set the project's metadata URI.
        uriOf[projectId] = uri;

        emit SetUri({projectId: projectId, uri: uri, caller: _msgSender()});
    }

    /// @notice Allows a credit holder to transfer credits to another address.
    /// @dev Can only be called by the credit holder or an address with the holder's permission to `TRANSFER_CREDITS`.
    /// @param holder The address to transfer credits from.
    /// @param projectId The ID of the project whose credits are being transferred.
    /// @param recipient The address to transfer credits to.
    /// @param creditCount The number of credits to transfer.
    function transferCreditsFrom(
        address holder,
        uint256 projectId,
        address recipient,
        uint256 creditCount
    )
        external
        override
    {
        // Enforce permissions.
        _requirePermissionFrom({account: holder, projectId: projectId, permissionId: JBPermissionIds.TRANSFER_CREDITS});

        // Get a reference to the project's ruleset.
        JBRuleset memory ruleset = _currentRulesetOf(projectId);

        // Credit transfers must not be paused.
        if (ruleset.pauseCreditTransfers()) revert JBController_CreditTransfersPaused();

        TOKENS.transferCreditsFrom({holder: holder, projectId: projectId, recipient: recipient, count: creditCount});
    }

    //*********************************************************************//
    // ------------------------ internal functions ----------------------- //
    //*********************************************************************//

    /// @notice Set up a project's terminals.
    /// @param projectId The ID of the project to set up terminals for.
    /// @param terminalConfigs The terminals to set up.
    function _configureTerminals(uint256 projectId, JBTerminalConfig[] calldata terminalConfigs) internal {
        // Initialize an array of terminals to populate.
        IJBTerminal[] memory terminals = new IJBTerminal[](terminalConfigs.length);

        for (uint256 i; i < terminalConfigs.length; i++) {
            // Set the terminal configuration being iterated on.
            JBTerminalConfig memory terminalConfig = terminalConfigs[i];

            // Add the accounting contexts for the specified tokens.
            terminalConfig.terminal.addAccountingContextsFor({
                projectId: projectId,
                accountingContexts: terminalConfig.accountingContextsToAccept
            });

            // Add the terminal.
            terminals[i] = terminalConfig.terminal;
        }

        // Set the terminals in the directory.
        if (terminalConfigs.length > 0) {
            DIRECTORY.setTerminalsOf({projectId: projectId, terminals: terminals});
        }
    }

    /// @notice Queues one or more rulesets and stores information pertinent to the configuration.
    /// @param projectId The ID of the project to queue rulesets for.
    /// @param rulesetConfigurations The rulesets being queued.
    /// @return rulesetId The ID of the last ruleset that was successfully queued.
    function _queueRulesets(
        uint256 projectId,
        JBRulesetConfig[] calldata rulesetConfigurations
    )
        internal
        returns (uint256 rulesetId)
    {
        for (uint256 i; i < rulesetConfigurations.length; i++) {
            // Get a reference to the ruleset config being iterated on.
            JBRulesetConfig memory rulesetConfig = rulesetConfigurations[i];

            // Make sure its reserved percent is valid.
            if (rulesetConfig.metadata.reservedPercent > JBConstants.MAX_RESERVED_PERCENT) {
                revert JBController_InvalidReservedPercent(
                    rulesetConfig.metadata.reservedPercent, JBConstants.MAX_RESERVED_PERCENT
                );
            }

            // Make sure its cash out tax rate is valid.
            if (rulesetConfig.metadata.cashOutTaxRate > JBConstants.MAX_CASH_OUT_TAX_RATE) {
                revert JBController_InvalidCashOutTaxRate(
                    rulesetConfig.metadata.cashOutTaxRate, JBConstants.MAX_CASH_OUT_TAX_RATE
                );
            }

            // Queue its ruleset.
            JBRuleset memory ruleset = RULESETS.queueFor({
                projectId: projectId,
                duration: rulesetConfig.duration,
                weight: rulesetConfig.weight,
                weightCutPercent: rulesetConfig.weightCutPercent,
                approvalHook: rulesetConfig.approvalHook,
                metadata: JBRulesetMetadataResolver.packRulesetMetadata(rulesetConfig.metadata),
                mustStartAtOrAfter: rulesetConfig.mustStartAtOrAfter
            });

            // Set its split groups.
            SPLITS.setSplitGroupsOf({
                projectId: projectId,
                rulesetId: ruleset.id,
                splitGroups: rulesetConfig.splitGroups
            });

            // Set its fund access limits.
            FUND_ACCESS_LIMITS.setFundAccessLimitsFor({
                projectId: projectId,
                rulesetId: ruleset.id,
                fundAccessLimitGroups: rulesetConfig.fundAccessLimitGroups
            });

            // If this is the last configuration being queued, return the ruleset's ID.
            if (i == rulesetConfigurations.length - 1) {
                rulesetId = ruleset.id;
            }
        }
    }

    /// @notice Sends pending reserved tokens to the project's reserved token splits.
    /// @dev If the project has no reserved token splits, or if they don't add up to 100%, leftover tokens are sent to
    /// the project's owner.
    /// @param projectId The ID of the project to send reserved tokens for.
    /// @return tokenCount The amount of reserved tokens minted and sent.
    function _sendReservedTokensToSplitsOf(uint256 projectId) internal returns (uint256 tokenCount) {
        // Get a reference to the number of tokens that need to be minted.
        tokenCount = pendingReservedTokenBalanceOf[projectId];

        // Revert if there are no pending reserved tokens
        if (tokenCount == 0) revert JBController_NoReservedTokens();

        // Get the ruleset to read the reserved percent from.
        JBRuleset memory ruleset = _currentRulesetOf(projectId);

        // Get a reference to the project's owner.
        address owner = PROJECTS.ownerOf(projectId);

        // Reset the pending reserved token balance.
        pendingReservedTokenBalanceOf[projectId] = 0;

        // Mint the tokens to this contract.
        IJBToken token = TOKENS.mintFor({holder: address(this), projectId: projectId, count: tokenCount});

        // Send reserved tokens to splits and get a reference to the amount left after the splits have all been paid.
        uint256 leftoverTokenCount = tokenCount == 0
            ? 0
            : _sendReservedTokensToSplitGroupOf({
                projectId: projectId,
                rulesetId: ruleset.id,
                groupId: JBSplitGroupIds.RESERVED_TOKENS,
                tokenCount: tokenCount,
                token: token
            });

        // Mint any leftover tokens to the project owner.
        if (leftoverTokenCount > 0) {
            _sendTokens({projectId: projectId, tokenCount: leftoverTokenCount, recipient: owner, token: token});
        }

        emit SendReservedTokensToSplits({
            rulesetId: ruleset.id,
            rulesetCycleNumber: ruleset.cycleNumber,
            projectId: projectId,
            owner: owner,
            tokenCount: tokenCount,
            leftoverAmount: leftoverTokenCount,
            caller: _msgSender()
        });
    }

    /// @notice Send project tokens to a split group.
    /// @dev This is used to send reserved tokens to the reserved token split group.
    /// @param projectId The ID of the project the splits belong to.
    /// @param rulesetId The ID of the split group's ruleset.
    /// @param groupId The ID of the split group.
    /// @param tokenCount The number of tokens to send.
    /// @param token The token to send.
    /// @return leftoverTokenCount If the split percents don't add up to 100%, the leftover amount is returned.
    function _sendReservedTokensToSplitGroupOf(
        uint256 projectId,
        uint256 rulesetId,
        uint256 groupId,
        uint256 tokenCount,
        IJBToken token
    )
        internal
        returns (uint256 leftoverTokenCount)
    {
        // Set the leftover amount to the initial amount.
        leftoverTokenCount = tokenCount;

        // Get a reference to the split group.
        JBSplit[] memory splits = SPLITS.splitsOf({projectId: projectId, rulesetId: rulesetId, groupId: groupId});

        // Keep a reference to the number of splits being iterated on.
        uint256 numberOfSplits = splits.length;

        // Send the tokens to the splits.
        for (uint256 i; i < numberOfSplits; i++) {
            // Get a reference to the split being iterated on.
            JBSplit memory split = splits[i];

            // Calculate the amount to send to the split.
            uint256 splitTokenCount = mulDiv(tokenCount, split.percent, JBConstants.SPLITS_TOTAL_PERCENT);

            // Mints tokens for the split if needed.
            if (splitTokenCount > 0) {
                // 1. If the split has a `hook`, call the hook's `processSplitWith` function.
                // 2. Otherwise, if the split has a `projectId`, try to pay the project using the split's `beneficiary`,
                // or the `_msgSender()` if the split has no beneficiary.
                // 3. Otherwise, if the split has a beneficiary, send the tokens to the split's beneficiary.
                // 4. Otherwise, send the tokens to the `_msgSender()`.

                // If the split has a hook, call its `processSplitWith` function.
                if (split.hook != IJBSplitHook(address(0))) {
                    // Send the tokens to the split hook.
                    // slither-disable-next-line reentrancy-events
                    _sendTokens({
                        projectId: projectId,
                        tokenCount: splitTokenCount,
                        recipient: address(split.hook),
                        token: token
                    });

                    // slither-disable-next-line reentrancy-events
                    split.hook.processSplitWith(
                        JBSplitHookContext({
                            token: address(token),
                            amount: splitTokenCount,
                            decimals: 18, // Hard-coded in `JBTokens`.
                            projectId: projectId,
                            groupId: groupId,
                            split: split
                        })
                    );
                    // If the split has a project ID, try to pay the project. If that fails, pay the beneficiary.
                } else {
                    // Pay the project using the split's beneficiary if one was provided. Otherwise, use the message
                    // sender.
                    address beneficiary = split.beneficiary != address(0) ? split.beneficiary : _msgSender();

                    if (split.projectId != 0) {
                        // Get a reference to the receiving project's primary payment terminal for the token.
                        IJBTerminal terminal = token == IJBToken(address(0))
                            ? IJBTerminal(address(0))
                            : DIRECTORY.primaryTerminalOf({projectId: split.projectId, token: address(token)});

                        // If the project doesn't have a token, or if the receiving project doesn't have a terminal
                        // which accepts the token, send the tokens to the beneficiary.
                        if (address(token) == address(0) || address(terminal) == address(0)) {
                            // Mint the tokens to the beneficiary.
                            // slither-disable-next-line reentrancy-events
                            _sendTokens({
                                projectId: projectId,
                                tokenCount: splitTokenCount,
                                recipient: beneficiary,
                                token: token
                            });
                        } else {
                            // Use the `projectId` in the pay metadata.
                            // slither-disable-next-line reentrancy-events
                            bytes memory metadata = bytes(abi.encodePacked(projectId));

                            // Try to fulfill the payment.
                            try this.executePayReservedTokenToTerminal({
                                projectId: split.projectId,
                                terminal: terminal,
                                token: token,
                                splitTokenCount: splitTokenCount,
                                beneficiary: beneficiary,
                                metadata: metadata
                            }) {} catch (bytes memory reason) {
                                emit ReservedDistributionReverted({
                                    projectId: projectId,
                                    split: split,
                                    tokenCount: splitTokenCount,
                                    reason: reason,
                                    caller: _msgSender()
                                });

                                // If it fails, transfer the tokens from this contract to the beneficiary.
                                IERC20(address(token)).safeTransfer(beneficiary, splitTokenCount);
                            }
                        }
                    } else if (beneficiary == address(0xdead)) {
                        // If the split has no project ID, and the beneficiary is 0xdead, burn.
                        TOKENS.burnFrom({holder: address(this), projectId: projectId, count: splitTokenCount});
                    } else {
                        // If the split has no project Id, send to beneficiary.
                        _sendTokens({
                            projectId: projectId,
                            tokenCount: splitTokenCount,
                            recipient: beneficiary,
                            token: token
                        });
                    }
                }

                // Subtract the amount sent from the leftover.
                leftoverTokenCount -= splitTokenCount;
            }

            emit SendReservedTokensToSplit({
                projectId: projectId,
                rulesetId: rulesetId,
                groupId: groupId,
                split: split,
                tokenCount: splitTokenCount,
                caller: _msgSender()
            });
        }
    }

    /// @notice Send tokens from this contract to a recipient.
    /// @param projectId The ID of the project the tokens belong to.
    /// @param tokenCount The number of tokens to send.
    /// @param recipient The address to send the tokens to.
    /// @param token The token to send, if one exists
    function _sendTokens(uint256 projectId, uint256 tokenCount, address recipient, IJBToken token) internal {
        if (token != IJBToken(address(0))) {
            IERC20(address(token)).safeTransfer({to: recipient, value: tokenCount});
        } else {
            TOKENS.transferCreditsFrom({
                holder: address(this),
                projectId: projectId,
                recipient: recipient,
                count: tokenCount
            });
        }
    }
}

File 2 of 58 : JBPermissionIds.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Permission IDs for `JBPermissions`, used throughout the Bananapus ecosystem. See
/// [`JBPermissions`](https://github.com/Bananapus/nana-core/blob/main/src/JBPermissions.sol)
/// @dev `JBPermissions` allows one address to grant another address permission to call functions in Juicebox contracts
/// on their behalf. Each ID in `JBPermissionIds` grants access to a specific set of these functions.
library JBPermissionIds {
    uint8 internal constant ROOT = 1; // All permissions across every contract. Very dangerous. BE CAREFUL!

    /* Used by `nana-core`: https://github.com/Bananapus/nana-core */
    uint8 internal constant QUEUE_RULESETS = 2; // Permission to call `JBController.queueRulesetsOf` and
        // `JBController.launchRulesetsFor`.
    uint8 internal constant CASH_OUT_TOKENS = 3; // Permission to call `JBMultiTerminal.cashOutTokensOf`.
    uint8 internal constant SEND_PAYOUTS = 4; // Permission to call `JBMultiTerminal.sendPayoutsOf`.
    uint8 internal constant MIGRATE_TERMINAL = 5; // Permission to call `JBMultiTerminal.migrateBalanceOf`.
    uint8 internal constant SET_PROJECT_URI = 6; // Permission to call `JBController.setUriOf`.
    uint8 internal constant DEPLOY_ERC20 = 7; // Permission to call `JBController.deployERC20For`.
    uint8 internal constant SET_TOKEN = 8; // Permission to call `JBController.setTokenFor`.
    uint8 internal constant MINT_TOKENS = 9; // Permission to call `JBController.mintTokensOf`.
    uint8 internal constant BURN_TOKENS = 10; // Permission to call `JBController.burnTokensOf`.
    uint8 internal constant CLAIM_TOKENS = 11; // Permission to call `JBController.claimTokensFor`.
    uint8 internal constant TRANSFER_CREDITS = 12; // Permission to call `JBController.transferCreditsFrom`.
    uint8 internal constant SET_CONTROLLER = 13; // Permission to call `JBDirectory.setControllerOf`.
    uint8 internal constant SET_TERMINALS = 14; // Permission to call `JBDirectory.setTerminalsOf`.
    // Be careful - `SET_TERMINALS` can be used to remove the primary terminal.
    uint8 internal constant SET_PRIMARY_TERMINAL = 15; // Permission to call `JBDirectory.setPrimaryTerminalOf`.
    uint8 internal constant USE_ALLOWANCE = 16; // Permission to call `JBMultiTerminal.useAllowanceOf`.
    uint8 internal constant SET_SPLIT_GROUPS = 17; // Permission to call `JBController.setSplitGroupsOf`.
    uint8 internal constant ADD_PRICE_FEED = 18; // Permission to call `JBPrices.addPriceFeedFor`.
    uint8 internal constant ADD_ACCOUNTING_CONTEXTS = 19; // Permission to call
        // `JBMultiTerminal.addAccountingContextsFor`.

    /* Used by `nana-721-hook`: https://github.com/Bananapus/nana-721-hook */
    uint8 internal constant ADJUST_721_TIERS = 20; // Permission to call `JB721TiersHook.adjustTiers`.
    uint8 internal constant SET_721_METADATA = 21; // Permission to call `JB721TiersHook.setMetadata`.
    uint8 internal constant MINT_721 = 22; // Permission to call `JB721TiersHook.mintFor`.
    uint8 internal constant SET_721_DISCOUNT_PERCENT = 23; // Permission to call `JB721TiersHook.setDiscountPercentOf`.

    /* Used by `nana-buyback-hook`: https://github.com/Bananapus/nana-buyback-hook */
    uint8 internal constant SET_BUYBACK_TWAP = 24; // Permission to call `JBBuybackHook.setTwapWindowOf` and
        // `JBBuybackHook.setTwapSlippageToleranceOf`.
    uint8 internal constant SET_BUYBACK_POOL = 25; // Permission to call `JBBuybackHook.setPoolFor`.

    /* Used by `nana-swap-terminal`: https://github.com/Bananapus/nana-swap-terminal */
    uint8 internal constant ADD_SWAP_TERMINAL_POOL = 26; // Permission to call `JBSwapTerminal.addDefaultPool`.
    uint8 internal constant ADD_SWAP_TERMINAL_TWAP_PARAMS = 27; // Permission to call
        // `JBSwapTerminal.addTwapParamsFor`.

    /* Used by `nana-suckers`: https://github.com/Bananapus/nana-suckers */
    uint8 internal constant MAP_SUCKER_TOKEN = 28; // Permission to call `BPSucker.mapToken`.
    uint8 internal constant DEPLOY_SUCKERS = 29; // Permission to call `BPSuckerRegistry.deploySuckersFor`.
    uint8 internal constant SUCKER_SAFETY = 30; // Permission to call `BPSucker.enableEmergencyHatchFor` and
        // `BPSucker.setDeprecation`.
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

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

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

File 4 of 58 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 5 of 58 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (metatx/ERC2771Context.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Context variant with ERC-2771 support.
 *
 * WARNING: Avoid using this pattern in contracts that rely in a specific calldata length as they'll
 * be affected by any forwarder whose `msg.data` is suffixed with the `from` address according to the ERC-2771
 * specification adding the address size in bytes (20) to the calldata size. An example of an unexpected
 * behavior could be an unintended fallback (or another function) invocation while trying to invoke the `receive`
 * function only accessible if `msg.data.length == 0`.
 *
 * WARNING: The usage of `delegatecall` in this contract is dangerous and may result in context corruption.
 * Any forwarded request to this contract triggering a `delegatecall` to itself will result in an invalid {_msgSender}
 * recovery.
 */
abstract contract ERC2771Context is Context {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable _trustedForwarder;

    /**
     * @dev Initializes the contract with a trusted forwarder, which will be able to
     * invoke functions on this contract on behalf of other accounts.
     *
     * NOTE: The trusted forwarder can be replaced by overriding {trustedForwarder}.
     */
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor(address trustedForwarder_) {
        _trustedForwarder = trustedForwarder_;
    }

    /**
     * @dev Returns the address of the trusted forwarder.
     */
    function trustedForwarder() public view virtual returns (address) {
        return _trustedForwarder;
    }

    /**
     * @dev Indicates whether any particular address is the trusted forwarder.
     */
    function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
        return forwarder == trustedForwarder();
    }

    /**
     * @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever
     * a call is not performed by the trusted forwarder or the calldata length is less than
     * 20 bytes (an address length).
     */
    function _msgSender() internal view virtual override returns (address) {
        uint256 calldataLength = msg.data.length;
        uint256 contextSuffixLength = _contextSuffixLength();
        if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
            return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
        } else {
            return super._msgSender();
        }
    }

    /**
     * @dev Override for `msg.data`. Defaults to the original `msg.data` whenever
     * a call is not performed by the trusted forwarder or the calldata length is less than
     * 20 bytes (an address length).
     */
    function _msgData() internal view virtual override returns (bytes calldata) {
        uint256 calldataLength = msg.data.length;
        uint256 contextSuffixLength = _contextSuffixLength();
        if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
            return msg.data[:calldataLength - contextSuffixLength];
        } else {
            return super._msgData();
        }
    }

    /**
     * @dev ERC-2771 specifies the context as being a single address (20 bytes).
     */
    function _contextSuffixLength() internal view virtual override returns (uint256) {
        return 20;
    }
}

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

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

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

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC-721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC-721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 12 of 58 : Common.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

// Common.sol
//
// Common mathematical functions used in both SD59x18 and UD60x18. Note that these global functions do not
// always operate with SD59x18 and UD60x18 numbers.

/*//////////////////////////////////////////////////////////////////////////
                                CUSTOM ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when the resultant value in {mulDiv} overflows uint256.
error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);

/// @notice Thrown when the resultant value in {mulDiv18} overflows uint256.
error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);

/// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`.
error PRBMath_MulDivSigned_InputTooSmall();

/// @notice Thrown when the resultant value in {mulDivSigned} overflows int256.
error PRBMath_MulDivSigned_Overflow(int256 x, int256 y);

/*//////////////////////////////////////////////////////////////////////////
                                    CONSTANTS
//////////////////////////////////////////////////////////////////////////*/

/// @dev The maximum value a uint128 number can have.
uint128 constant MAX_UINT128 = type(uint128).max;

/// @dev The maximum value a uint40 number can have.
uint40 constant MAX_UINT40 = type(uint40).max;

/// @dev The maximum value a uint64 number can have.
uint64 constant MAX_UINT64 = type(uint64).max;

/// @dev The unit number, which the decimal precision of the fixed-point types.
uint256 constant UNIT = 1e18;

/// @dev The unit number inverted mod 2^256.
uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;

/// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant
/// bit in the binary representation of `UNIT`.
uint256 constant UNIT_LPOTD = 262144;

/*//////////////////////////////////////////////////////////////////////////
                                    FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Calculates the binary exponent of x using the binary fraction method.
/// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693.
/// @param x The exponent as an unsigned 192.64-bit fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
/// @custom:smtchecker abstract-function-nondet
function exp2(uint256 x) pure returns (uint256 result) {
    unchecked {
        // Start from 0.5 in the 192.64-bit fixed-point format.
        result = 0x800000000000000000000000000000000000000000000000;

        // The following logic multiplies the result by $\sqrt{2^{-i}}$ when the bit at position i is 1. Key points:
        //
        // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65.
        // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing
        // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1,
        // we know that `x & 0xFF` is also 1.
        if (x & 0xFF00000000000000 > 0) {
            if (x & 0x8000000000000000 > 0) {
                result = (result * 0x16A09E667F3BCC909) >> 64;
            }
            if (x & 0x4000000000000000 > 0) {
                result = (result * 0x1306FE0A31B7152DF) >> 64;
            }
            if (x & 0x2000000000000000 > 0) {
                result = (result * 0x1172B83C7D517ADCE) >> 64;
            }
            if (x & 0x1000000000000000 > 0) {
                result = (result * 0x10B5586CF9890F62A) >> 64;
            }
            if (x & 0x800000000000000 > 0) {
                result = (result * 0x1059B0D31585743AE) >> 64;
            }
            if (x & 0x400000000000000 > 0) {
                result = (result * 0x102C9A3E778060EE7) >> 64;
            }
            if (x & 0x200000000000000 > 0) {
                result = (result * 0x10163DA9FB33356D8) >> 64;
            }
            if (x & 0x100000000000000 > 0) {
                result = (result * 0x100B1AFA5ABCBED61) >> 64;
            }
        }

        if (x & 0xFF000000000000 > 0) {
            if (x & 0x80000000000000 > 0) {
                result = (result * 0x10058C86DA1C09EA2) >> 64;
            }
            if (x & 0x40000000000000 > 0) {
                result = (result * 0x1002C605E2E8CEC50) >> 64;
            }
            if (x & 0x20000000000000 > 0) {
                result = (result * 0x100162F3904051FA1) >> 64;
            }
            if (x & 0x10000000000000 > 0) {
                result = (result * 0x1000B175EFFDC76BA) >> 64;
            }
            if (x & 0x8000000000000 > 0) {
                result = (result * 0x100058BA01FB9F96D) >> 64;
            }
            if (x & 0x4000000000000 > 0) {
                result = (result * 0x10002C5CC37DA9492) >> 64;
            }
            if (x & 0x2000000000000 > 0) {
                result = (result * 0x1000162E525EE0547) >> 64;
            }
            if (x & 0x1000000000000 > 0) {
                result = (result * 0x10000B17255775C04) >> 64;
            }
        }

        if (x & 0xFF0000000000 > 0) {
            if (x & 0x800000000000 > 0) {
                result = (result * 0x1000058B91B5BC9AE) >> 64;
            }
            if (x & 0x400000000000 > 0) {
                result = (result * 0x100002C5C89D5EC6D) >> 64;
            }
            if (x & 0x200000000000 > 0) {
                result = (result * 0x10000162E43F4F831) >> 64;
            }
            if (x & 0x100000000000 > 0) {
                result = (result * 0x100000B1721BCFC9A) >> 64;
            }
            if (x & 0x80000000000 > 0) {
                result = (result * 0x10000058B90CF1E6E) >> 64;
            }
            if (x & 0x40000000000 > 0) {
                result = (result * 0x1000002C5C863B73F) >> 64;
            }
            if (x & 0x20000000000 > 0) {
                result = (result * 0x100000162E430E5A2) >> 64;
            }
            if (x & 0x10000000000 > 0) {
                result = (result * 0x1000000B172183551) >> 64;
            }
        }

        if (x & 0xFF00000000 > 0) {
            if (x & 0x8000000000 > 0) {
                result = (result * 0x100000058B90C0B49) >> 64;
            }
            if (x & 0x4000000000 > 0) {
                result = (result * 0x10000002C5C8601CC) >> 64;
            }
            if (x & 0x2000000000 > 0) {
                result = (result * 0x1000000162E42FFF0) >> 64;
            }
            if (x & 0x1000000000 > 0) {
                result = (result * 0x10000000B17217FBB) >> 64;
            }
            if (x & 0x800000000 > 0) {
                result = (result * 0x1000000058B90BFCE) >> 64;
            }
            if (x & 0x400000000 > 0) {
                result = (result * 0x100000002C5C85FE3) >> 64;
            }
            if (x & 0x200000000 > 0) {
                result = (result * 0x10000000162E42FF1) >> 64;
            }
            if (x & 0x100000000 > 0) {
                result = (result * 0x100000000B17217F8) >> 64;
            }
        }

        if (x & 0xFF000000 > 0) {
            if (x & 0x80000000 > 0) {
                result = (result * 0x10000000058B90BFC) >> 64;
            }
            if (x & 0x40000000 > 0) {
                result = (result * 0x1000000002C5C85FE) >> 64;
            }
            if (x & 0x20000000 > 0) {
                result = (result * 0x100000000162E42FF) >> 64;
            }
            if (x & 0x10000000 > 0) {
                result = (result * 0x1000000000B17217F) >> 64;
            }
            if (x & 0x8000000 > 0) {
                result = (result * 0x100000000058B90C0) >> 64;
            }
            if (x & 0x4000000 > 0) {
                result = (result * 0x10000000002C5C860) >> 64;
            }
            if (x & 0x2000000 > 0) {
                result = (result * 0x1000000000162E430) >> 64;
            }
            if (x & 0x1000000 > 0) {
                result = (result * 0x10000000000B17218) >> 64;
            }
        }

        if (x & 0xFF0000 > 0) {
            if (x & 0x800000 > 0) {
                result = (result * 0x1000000000058B90C) >> 64;
            }
            if (x & 0x400000 > 0) {
                result = (result * 0x100000000002C5C86) >> 64;
            }
            if (x & 0x200000 > 0) {
                result = (result * 0x10000000000162E43) >> 64;
            }
            if (x & 0x100000 > 0) {
                result = (result * 0x100000000000B1721) >> 64;
            }
            if (x & 0x80000 > 0) {
                result = (result * 0x10000000000058B91) >> 64;
            }
            if (x & 0x40000 > 0) {
                result = (result * 0x1000000000002C5C8) >> 64;
            }
            if (x & 0x20000 > 0) {
                result = (result * 0x100000000000162E4) >> 64;
            }
            if (x & 0x10000 > 0) {
                result = (result * 0x1000000000000B172) >> 64;
            }
        }

        if (x & 0xFF00 > 0) {
            if (x & 0x8000 > 0) {
                result = (result * 0x100000000000058B9) >> 64;
            }
            if (x & 0x4000 > 0) {
                result = (result * 0x10000000000002C5D) >> 64;
            }
            if (x & 0x2000 > 0) {
                result = (result * 0x1000000000000162E) >> 64;
            }
            if (x & 0x1000 > 0) {
                result = (result * 0x10000000000000B17) >> 64;
            }
            if (x & 0x800 > 0) {
                result = (result * 0x1000000000000058C) >> 64;
            }
            if (x & 0x400 > 0) {
                result = (result * 0x100000000000002C6) >> 64;
            }
            if (x & 0x200 > 0) {
                result = (result * 0x10000000000000163) >> 64;
            }
            if (x & 0x100 > 0) {
                result = (result * 0x100000000000000B1) >> 64;
            }
        }

        if (x & 0xFF > 0) {
            if (x & 0x80 > 0) {
                result = (result * 0x10000000000000059) >> 64;
            }
            if (x & 0x40 > 0) {
                result = (result * 0x1000000000000002C) >> 64;
            }
            if (x & 0x20 > 0) {
                result = (result * 0x10000000000000016) >> 64;
            }
            if (x & 0x10 > 0) {
                result = (result * 0x1000000000000000B) >> 64;
            }
            if (x & 0x8 > 0) {
                result = (result * 0x10000000000000006) >> 64;
            }
            if (x & 0x4 > 0) {
                result = (result * 0x10000000000000003) >> 64;
            }
            if (x & 0x2 > 0) {
                result = (result * 0x10000000000000001) >> 64;
            }
            if (x & 0x1 > 0) {
                result = (result * 0x10000000000000001) >> 64;
            }
        }

        // In the code snippet below, two operations are executed simultaneously:
        //
        // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1
        // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192.
        // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format.
        //
        // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the,
        // integer part, $2^n$.
        result *= UNIT;
        result >>= (191 - (x >> 64));
    }
}

/// @notice Finds the zero-based index of the first 1 in the binary representation of x.
///
/// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set
///
/// Each step in this implementation is equivalent to this high-level code:
///
/// ```solidity
/// if (x >= 2 ** 128) {
///     x >>= 128;
///     result += 128;
/// }
/// ```
///
/// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here:
/// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948
///
/// The Yul instructions used below are:
///
/// - "gt" is "greater than"
/// - "or" is the OR bitwise operator
/// - "shl" is "shift left"
/// - "shr" is "shift right"
///
/// @param x The uint256 number for which to find the index of the most significant bit.
/// @return result The index of the most significant bit as a uint256.
/// @custom:smtchecker abstract-function-nondet
function msb(uint256 x) pure returns (uint256 result) {
    // 2^128
    assembly ("memory-safe") {
        let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^64
    assembly ("memory-safe") {
        let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^32
    assembly ("memory-safe") {
        let factor := shl(5, gt(x, 0xFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^16
    assembly ("memory-safe") {
        let factor := shl(4, gt(x, 0xFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^8
    assembly ("memory-safe") {
        let factor := shl(3, gt(x, 0xFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^4
    assembly ("memory-safe") {
        let factor := shl(2, gt(x, 0xF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^2
    assembly ("memory-safe") {
        let factor := shl(1, gt(x, 0x3))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^1
    // No need to shift x any more.
    assembly ("memory-safe") {
        let factor := gt(x, 0x1)
        result := or(result, factor)
    }
}

/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - The denominator must not be zero.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as a uint256.
/// @param y The multiplier as a uint256.
/// @param denominator The divisor as a uint256.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {
    // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
    // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256
    // variables such that product = prod1 * 2^256 + prod0.
    uint256 prod0; // Least significant 256 bits of the product
    uint256 prod1; // Most significant 256 bits of the product
    assembly ("memory-safe") {
        let mm := mulmod(x, y, not(0))
        prod0 := mul(x, y)
        prod1 := sub(sub(mm, prod0), lt(mm, prod0))
    }

    // Handle non-overflow cases, 256 by 256 division.
    if (prod1 == 0) {
        unchecked {
            return prod0 / denominator;
        }
    }

    // Make sure the result is less than 2^256. Also prevents denominator == 0.
    if (prod1 >= denominator) {
        revert PRBMath_MulDiv_Overflow(x, y, denominator);
    }

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

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

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

    unchecked {
        // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow
        // because the denominator cannot be zero at this point in the function execution. The result is always >= 1.
        // For more detail, see https://cs.stackexchange.com/q/138556/92363.
        uint256 lpotdod = denominator & (~denominator + 1);
        uint256 flippedLpotdod;

        assembly ("memory-safe") {
            // Factor powers of two out of denominator.
            denominator := div(denominator, lpotdod)

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

            // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.
            // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.
            // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693
            flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
        }

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

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

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

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

/// @notice Calculates x*y÷1e18 with 512-bit precision.
///
/// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18.
///
/// Notes:
/// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}.
/// - The result is rounded toward zero.
/// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations:
///
/// $$
/// \begin{cases}
///     x * y = MAX\_UINT256 * UNIT \\
///     (x * y) \% UNIT \geq \frac{UNIT}{2}
/// \end{cases}
/// $$
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
/// @custom:smtchecker abstract-function-nondet
function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {
    uint256 prod0;
    uint256 prod1;
    assembly ("memory-safe") {
        let mm := mulmod(x, y, not(0))
        prod0 := mul(x, y)
        prod1 := sub(sub(mm, prod0), lt(mm, prod0))
    }

    if (prod1 == 0) {
        unchecked {
            return prod0 / UNIT;
        }
    }

    if (prod1 >= UNIT) {
        revert PRBMath_MulDiv18_Overflow(x, y);
    }

    uint256 remainder;
    assembly ("memory-safe") {
        remainder := mulmod(x, y, UNIT)
        result :=
            mul(
                or(
                    div(sub(prod0, remainder), UNIT_LPOTD),
                    mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
                ),
                UNIT_INVERSE
            )
    }
}

/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - None of the inputs can be `type(int256).min`.
/// - The result must fit in int256.
///
/// @param x The multiplicand as an int256.
/// @param y The multiplier as an int256.
/// @param denominator The divisor as an int256.
/// @return result The result as an int256.
/// @custom:smtchecker abstract-function-nondet
function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {
    if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
        revert PRBMath_MulDivSigned_InputTooSmall();
    }

    // Get hold of the absolute values of x, y and the denominator.
    uint256 xAbs;
    uint256 yAbs;
    uint256 dAbs;
    unchecked {
        xAbs = x < 0 ? uint256(-x) : uint256(x);
        yAbs = y < 0 ? uint256(-y) : uint256(y);
        dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator);
    }

    // Compute the absolute value of x*y÷denominator. The result must fit in int256.
    uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);
    if (resultAbs > uint256(type(int256).max)) {
        revert PRBMath_MulDivSigned_Overflow(x, y);
    }

    // Get the signs of x, y and the denominator.
    uint256 sx;
    uint256 sy;
    uint256 sd;
    assembly ("memory-safe") {
        // "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement.
        sx := sgt(x, sub(0, 1))
        sy := sgt(y, sub(0, 1))
        sd := sgt(denominator, sub(0, 1))
    }

    // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.
    // If there are, the result should be negative. Otherwise, it should be positive.
    unchecked {
        result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);
    }
}

/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - If x is not a perfect square, the result is rounded down.
/// - Credits to OpenZeppelin for the explanations in comments below.
///
/// @param x The uint256 number for which to calculate the square root.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function sqrt(uint256 x) pure returns (uint256 result) {
    if (x == 0) {
        return 0;
    }

    // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.
    //
    // We know that the "msb" (most significant bit) of x is a power of 2 such that we have:
    //
    // $$
    // msb(x) <= x <= 2*msb(x)$
    // $$
    //
    // We write $msb(x)$ as $2^k$, and we get:
    //
    // $$
    // k = log_2(x)
    // $$
    //
    // Thus, we can write the initial inequality as:
    //
    // $$
    // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\
    // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\
    // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}
    // $$
    //
    // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.
    uint256 xAux = uint256(x);
    result = 1;
    if (xAux >= 2 ** 128) {
        xAux >>= 128;
        result <<= 64;
    }
    if (xAux >= 2 ** 64) {
        xAux >>= 64;
        result <<= 32;
    }
    if (xAux >= 2 ** 32) {
        xAux >>= 32;
        result <<= 16;
    }
    if (xAux >= 2 ** 16) {
        xAux >>= 16;
        result <<= 8;
    }
    if (xAux >= 2 ** 8) {
        xAux >>= 8;
        result <<= 4;
    }
    if (xAux >= 2 ** 4) {
        xAux >>= 4;
        result <<= 2;
    }
    if (xAux >= 2 ** 2) {
        result <<= 1;
    }

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

        // If x is not a perfect square, round the result toward zero.
        uint256 roundedResult = x / result;
        if (result >= roundedResult) {
            result = roundedResult;
        }
    }
}

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

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

import {IJBPermissioned} from "./../interfaces/IJBPermissioned.sol";
import {IJBPermissions} from "./../interfaces/IJBPermissions.sol";

/// @notice Modifiers to allow access to transactions based on which permissions the message's sender has.
abstract contract JBPermissioned is Context, IJBPermissioned {
    //*********************************************************************//
    // --------------------------- custom errors -------------------------- //
    //*********************************************************************//

    error JBPermissioned_Unauthorized(address account, address sender, uint256 projectId, uint256 permissionId);

    //*********************************************************************//
    // ---------------- public immutable stored properties --------------- //
    //*********************************************************************//

    /// @notice A contract storing permissions.
    IJBPermissions public immutable override PERMISSIONS;

    //*********************************************************************//
    // -------------------------- constructor ---------------------------- //
    //*********************************************************************//

    /// @param permissions A contract storing permissions.
    constructor(IJBPermissions permissions) {
        PERMISSIONS = permissions;
    }

    //*********************************************************************//
    // -------------------------- internal views ------------------------- //
    //*********************************************************************//

    /// @notice Require the message sender to be the account or have the relevant permission.
    /// @param account The account to allow.
    /// @param projectId The project ID to check the permission under.
    /// @param permissionId The required permission ID. The operator must have this permission within the specified
    /// project ID.
    function _requirePermissionFrom(address account, uint256 projectId, uint256 permissionId) internal view {
        address sender = _msgSender();
        if (
            sender != account
                && !PERMISSIONS.hasPermission({
                    operator: sender,
                    account: account,
                    projectId: projectId,
                    permissionId: permissionId,
                    includeRoot: true,
                    includeWildcardProjectId: true
                })
        ) revert JBPermissioned_Unauthorized(account, sender, projectId, permissionId);
    }

    /// @notice If the 'alsoGrantAccessIf' condition is truthy, proceed. Otherwise, require the message sender to be the
    /// account or
    /// have the relevant permission.
    /// @param account The account to allow.
    /// @param projectId The project ID to check the permission under.
    /// @param permissionId The required permission ID. The operator must have this permission within the specified
    /// project ID.
    /// @param alsoGrantAccessIf An override condition which will allow access regardless of permissions.
    function _requirePermissionAllowingOverrideFrom(
        address account,
        uint256 projectId,
        uint256 permissionId,
        bool alsoGrantAccessIf
    )
        internal
        view
    {
        if (alsoGrantAccessIf) return;
        _requirePermissionFrom(account, projectId, permissionId);
    }
}

File 14 of 58 : JBApprovalStatus.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice A ruleset's approval status in a ruleset approval hook.
enum JBApprovalStatus {
    Empty,
    Upcoming,
    Active,
    ApprovalExpected,
    Approved,
    Failed
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {JBAfterCashOutRecordedContext} from "./../structs/JBAfterCashOutRecordedContext.sol";

/// @notice Hook called after a terminal's `cashOutTokensOf(...)` logic completes (if passed by the ruleset's data
/// hook).
interface IJBCashOutHook is IERC165 {
    /// @notice This function is called by the terminal's `cashOutTokensOf(...)` function after the cash out has been
    /// recorded in the terminal store.
    /// @dev Critical business logic should be protected by appropriate access control.
    /// @param context The context passed in by the terminal, as a `JBAfterCashOutRecordedContext` struct.
    function afterCashOutRecordedWith(JBAfterCashOutRecordedContext calldata context) external payable;
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {IJBDirectory} from "./IJBDirectory.sol";
import {IJBDirectoryAccessControl} from "./IJBDirectoryAccessControl.sol";
import {IJBFundAccessLimits} from "./IJBFundAccessLimits.sol";
import {IJBPriceFeed} from "./IJBPriceFeed.sol";
import {IJBPrices} from "./IJBPrices.sol";
import {IJBProjects} from "./IJBProjects.sol";
import {IJBProjectUriRegistry} from "./IJBProjectUriRegistry.sol";
import {IJBRulesets} from "./IJBRulesets.sol";
import {IJBSplits} from "./IJBSplits.sol";
import {IJBTerminal} from "./IJBTerminal.sol";
import {IJBToken} from "./IJBToken.sol";
import {IJBTokens} from "./IJBTokens.sol";
import {JBApprovalStatus} from "./../enums/JBApprovalStatus.sol";
import {JBRuleset} from "./../structs/JBRuleset.sol";
import {JBRulesetConfig} from "./../structs/JBRulesetConfig.sol";
import {JBRulesetMetadata} from "./../structs/JBRulesetMetadata.sol";
import {JBRulesetWithMetadata} from "./../structs/JBRulesetWithMetadata.sol";
import {JBSplit} from "./../structs/JBSplit.sol";
import {JBSplitGroup} from "./../structs/JBSplitGroup.sol";
import {JBTerminalConfig} from "./../structs/JBTerminalConfig.sol";

interface IJBController is IERC165, IJBProjectUriRegistry, IJBDirectoryAccessControl {
    event BurnTokens(
        address indexed holder, uint256 indexed projectId, uint256 tokenCount, string memo, address caller
    );
    event LaunchProject(uint256 rulesetId, uint256 projectId, string projectUri, string memo, address caller);
    event LaunchRulesets(uint256 rulesetId, uint256 projectId, string memo, address caller);
    event MintTokens(
        address indexed beneficiary,
        uint256 indexed projectId,
        uint256 tokenCount,
        uint256 beneficiaryTokenCount,
        string memo,
        uint256 reservedPercent,
        address caller
    );
    event PrepMigration(uint256 indexed projectId, address from, address caller);
    event QueueRulesets(uint256 rulesetId, uint256 projectId, string memo, address caller);
    event ReservedDistributionReverted(
        uint256 indexed projectId, JBSplit split, uint256 tokenCount, bytes reason, address caller
    );
    event SendReservedTokensToSplit(
        uint256 indexed projectId,
        uint256 indexed rulesetId,
        uint256 indexed groupId,
        JBSplit split,
        uint256 tokenCount,
        address caller
    );
    event SendReservedTokensToSplits(
        uint256 indexed rulesetId,
        uint256 indexed rulesetCycleNumber,
        uint256 indexed projectId,
        address owner,
        uint256 tokenCount,
        uint256 leftoverAmount,
        address caller
    );
    event SetUri(uint256 indexed projectId, string uri, address caller);

    function DIRECTORY() external view returns (IJBDirectory);
    function FUND_ACCESS_LIMITS() external view returns (IJBFundAccessLimits);
    function PRICES() external view returns (IJBPrices);
    function PROJECTS() external view returns (IJBProjects);
    function RULESETS() external view returns (IJBRulesets);
    function SPLITS() external view returns (IJBSplits);
    function TOKENS() external view returns (IJBTokens);

    function allRulesetsOf(
        uint256 projectId,
        uint256 startingId,
        uint256 size
    )
        external
        view
        returns (JBRulesetWithMetadata[] memory rulesets);
    function currentRulesetOf(uint256 projectId)
        external
        view
        returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata);
    function getRulesetOf(
        uint256 projectId,
        uint256 rulesetId
    )
        external
        view
        returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata);
    function latestQueuedRulesetOf(uint256 projectId)
        external
        view
        returns (JBRuleset memory, JBRulesetMetadata memory metadata, JBApprovalStatus);
    function pendingReservedTokenBalanceOf(uint256 projectId) external view returns (uint256);
    function totalTokenSupplyWithReservedTokensOf(uint256 projectId) external view returns (uint256);
    function upcomingRulesetOf(uint256 projectId)
        external
        view
        returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata);

    function addPriceFeed(
        uint256 projectId,
        uint256 pricingCurrency,
        uint256 unitCurrency,
        IJBPriceFeed feed
    )
        external;
    function burnTokensOf(address holder, uint256 projectId, uint256 tokenCount, string calldata memo) external;
    function claimTokensFor(address holder, uint256 projectId, uint256 tokenCount, address beneficiary) external;
    function deployERC20For(
        uint256 projectId,
        string calldata name,
        string calldata symbol,
        bytes32 salt
    )
        external
        returns (IJBToken token);
    function launchProjectFor(
        address owner,
        string calldata projectUri,
        JBRulesetConfig[] calldata rulesetConfigurations,
        JBTerminalConfig[] memory terminalConfigurations,
        string calldata memo
    )
        external
        returns (uint256 projectId);
    function launchRulesetsFor(
        uint256 projectId,
        JBRulesetConfig[] calldata rulesetConfigurations,
        JBTerminalConfig[] memory terminalConfigurations,
        string calldata memo
    )
        external
        returns (uint256 rulesetId);
    function mintTokensOf(
        uint256 projectId,
        uint256 tokenCount,
        address beneficiary,
        string calldata memo,
        bool useReservedPercent
    )
        external
        returns (uint256 beneficiaryTokenCount);
    function queueRulesetsOf(
        uint256 projectId,
        JBRulesetConfig[] calldata rulesetConfigurations,
        string calldata memo
    )
        external
        returns (uint256 rulesetId);
    function sendReservedTokensToSplitsOf(uint256 projectId) external returns (uint256);
    function setSplitGroupsOf(uint256 projectId, uint256 rulesetId, JBSplitGroup[] calldata splitGroups) external;
    function setTokenFor(uint256 projectId, IJBToken token) external;
    function transferCreditsFrom(address holder, uint256 projectId, address recipient, uint256 creditCount) external;
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {IJBProjects} from "./IJBProjects.sol";
import {IJBTerminal} from "./IJBTerminal.sol";

interface IJBDirectory {
    event AddTerminal(uint256 indexed projectId, IJBTerminal indexed terminal, address caller);
    event SetController(uint256 indexed projectId, IERC165 indexed controller, address caller);
    event SetIsAllowedToSetFirstController(address indexed addr, bool indexed isAllowed, address caller);
    event SetPrimaryTerminal(
        uint256 indexed projectId, address indexed token, IJBTerminal indexed terminal, address caller
    );
    event SetTerminals(uint256 indexed projectId, IJBTerminal[] terminals, address caller);

    function PROJECTS() external view returns (IJBProjects);

    function controllerOf(uint256 projectId) external view returns (IERC165);
    function isAllowedToSetFirstController(address account) external view returns (bool);
    function isTerminalOf(uint256 projectId, IJBTerminal terminal) external view returns (bool);
    function primaryTerminalOf(uint256 projectId, address token) external view returns (IJBTerminal);
    function terminalsOf(uint256 projectId) external view returns (IJBTerminal[] memory);

    function setControllerOf(uint256 projectId, IERC165 controller) external;
    function setIsAllowedToSetFirstController(address account, bool flag) external;
    function setPrimaryTerminalOf(uint256 projectId, address token, IJBTerminal terminal) external;
    function setTerminalsOf(uint256 projectId, IJBTerminal[] calldata terminals) external;
}

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

interface IJBDirectoryAccessControl {
    function setControllerAllowed(uint256 projectId) external view returns (bool);
    function setTerminalsAllowed(uint256 projectId) external view returns (bool);
}

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

import {JBCurrencyAmount} from "./../structs/JBCurrencyAmount.sol";
import {JBFundAccessLimitGroup} from "./../structs/JBFundAccessLimitGroup.sol";

interface IJBFundAccessLimits {
    event SetFundAccessLimits(
        uint256 indexed rulesetId,
        uint256 indexed projectId,
        JBFundAccessLimitGroup fundAccessLimitGroup,
        address caller
    );

    function payoutLimitOf(
        uint256 projectId,
        uint256 rulesetId,
        address terminal,
        address token,
        uint256 currency
    )
        external
        view
        returns (uint256 payoutLimit);
    function payoutLimitsOf(
        uint256 projectId,
        uint256 rulesetId,
        address terminal,
        address token
    )
        external
        view
        returns (JBCurrencyAmount[] memory payoutLimits);
    function surplusAllowanceOf(
        uint256 projectId,
        uint256 rulesetId,
        address terminal,
        address token,
        uint256 currency
    )
        external
        view
        returns (uint256 surplusAllowance);
    function surplusAllowancesOf(
        uint256 projectId,
        uint256 rulesetId,
        address terminal,
        address token
    )
        external
        view
        returns (JBCurrencyAmount[] memory surplusAllowances);

    function setFundAccessLimitsFor(
        uint256 projectId,
        uint256 rulesetId,
        JBFundAccessLimitGroup[] memory fundAccessLimitGroups
    )
        external;
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface IJBMigratable is IERC165 {
    event Migrate(uint256 indexed projectId, IERC165 to, address caller);

    function migrate(uint256 projectId, IERC165 to) external;
    function beforeReceiveMigrationFrom(IERC165 from, uint256 projectId) external;
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {JBAfterPayRecordedContext} from "./../structs/JBAfterPayRecordedContext.sol";

/// @notice Hook called after a terminal's `pay(...)` logic completes (if passed by the ruleset's data hook).
interface IJBPayHook is IERC165 {
    /// @notice This function is called by the terminal's `pay(...)` function after the payment has been recorded in the
    /// terminal store.
    /// @dev Critical business logic should be protected by appropriate access control.
    /// @param context The context passed in by the terminal, as a `JBAfterPayRecordedContext` struct.
    function afterPayRecordedWith(JBAfterPayRecordedContext calldata context) external payable;
}

File 22 of 58 : IJBPermissioned.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

interface IJBPermissioned {
    function PERMISSIONS() external view returns (IJBPermissions);
}

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

import {JBPermissionsData} from "./../structs/JBPermissionsData.sol";

interface IJBPermissions {
    event OperatorPermissionsSet(
        address indexed operator,
        address indexed account,
        uint256 indexed projectId,
        uint8[] permissionIds,
        uint256 packed,
        address caller
    );

    function WILDCARD_PROJECT_ID() external view returns (uint256);

    function permissionsOf(address operator, address account, uint256 projectId) external view returns (uint256);

    function hasPermission(
        address operator,
        address account,
        uint256 projectId,
        uint256 permissionId,
        bool includeRoot,
        bool includeWildcardProjectId
    )
        external
        view
        returns (bool);

    function hasPermissions(
        address operator,
        address account,
        uint256 projectId,
        uint256[] calldata permissionIds,
        bool includeRoot,
        bool includeWildcardProjectId
    )
        external
        view
        returns (bool);

    function setPermissionsFor(address account, JBPermissionsData calldata permissionsData) external;
}

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

interface IJBPriceFeed {
    function currentUnitPrice(uint256 targetDecimals) external view returns (uint256);
}

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

import {IJBPriceFeed} from "./IJBPriceFeed.sol";
import {IJBProjects} from "./IJBProjects.sol";

interface IJBPrices {
    event AddPriceFeed(
        uint256 indexed projectId,
        uint256 indexed pricingCurrency,
        uint256 indexed unitCurrency,
        IJBPriceFeed feed,
        address caller
    );

    function DEFAULT_PROJECT_ID() external view returns (uint256);
    function PROJECTS() external view returns (IJBProjects);

    function priceFeedFor(
        uint256 projectId,
        uint256 pricingCurrency,
        uint256 unitCurrency
    )
        external
        view
        returns (IJBPriceFeed);
    function pricePerUnitOf(
        uint256 projectId,
        uint256 pricingCurrency,
        uint256 unitCurrency,
        uint256 decimals
    )
        external
        view
        returns (uint256);

    function addPriceFeedFor(
        uint256 projectId,
        uint256 pricingCurrency,
        uint256 unitCurrency,
        IJBPriceFeed feed
    )
        external;
}

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

interface IJBProjectUriRegistry {
    function uriOf(uint256 projectId) external view returns (string memory);
    function setUriOf(uint256 projectId, string calldata uri) external;
}

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

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

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

interface IJBProjects is IERC721 {
    event Create(uint256 indexed projectId, address indexed owner, address caller);
    event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);

    function count() external view returns (uint256);
    function tokenUriResolver() external view returns (IJBTokenUriResolver);

    function createFor(address owner) external returns (uint256 projectId);
    function setTokenUriResolver(IJBTokenUriResolver resolver) external;
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {JBApprovalStatus} from "./../enums/JBApprovalStatus.sol";

/// @notice `IJBRulesetApprovalHook`s are used to determine whether the next ruleset in the ruleset queue is approved or
/// rejected.
/// @dev Project rulesets are stored in a queue. Rulesets take effect after the previous ruleset in the queue ends, and
/// only if they are approved by the previous ruleset's approval hook.
interface IJBRulesetApprovalHook is IERC165 {
    function DURATION() external view returns (uint256);

    function approvalStatusOf(
        uint256 projectId,
        uint256 rulesetId,
        uint256 start
    )
        external
        view
        returns (JBApprovalStatus);
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {JBBeforePayRecordedContext} from "./../structs/JBBeforePayRecordedContext.sol";
import {JBBeforeCashOutRecordedContext} from "./../structs/JBBeforeCashOutRecordedContext.sol";
import {JBCashOutHookSpecification} from "./../structs/JBCashOutHookSpecification.sol";
import {JBPayHookSpecification} from "./../structs/JBPayHookSpecification.sol";

/// @notice Data hooks can extend a terminal's core pay/cashout functionality by overriding the weight or memo. They can
/// also specify pay/cashout hooks for the terminal to fulfill, or allow addresses to mint a project's tokens on-demand.
/// @dev If a project's ruleset has `useDataHookForPay` or `useDataHookForCashOut` enabled, its `dataHook` is called by
/// the terminal upon payments/cashouts (respectively).
interface IJBRulesetDataHook is IERC165 {
    /// @notice A flag indicating whether an address has permission to mint a project's tokens on-demand.
    /// @dev A project's data hook can allow any address to mint its tokens.
    /// @param projectId The ID of the project whose token can be minted.
    /// @param addr The address to check the token minting permission of.
    /// @return flag A flag indicating whether the address has permission to mint the project's tokens on-demand.
    function hasMintPermissionFor(uint256 projectId, address addr) external view returns (bool flag);

    /// @notice The data calculated before a payment is recorded in the terminal store. This data is provided to the
    /// terminal's `pay(...)` transaction.
    /// @param context The context passed to this data hook by the `pay(...)` function as a `JBBeforePayRecordedContext`
    /// struct.
    /// @return weight The new `weight` to use, overriding the ruleset's `weight`.
    /// @return hookSpecifications The amount and data to send to pay hooks instead of adding to the terminal's balance.
    function beforePayRecordedWith(JBBeforePayRecordedContext calldata context)
        external
        view
        returns (uint256 weight, JBPayHookSpecification[] memory hookSpecifications);

    /// @notice The data calculated before a cash out is recorded in the terminal store. This data is provided to the
    /// terminal's `cashOutTokensOf(...)` transaction.
    /// @param context The context passed to this data hook by the `cashOutTokensOf(...)` function as a
    /// `JBBeforeCashOutRecordedContext` struct.
    /// @return cashOutTaxRate The rate determining the amount that should be reclaimable for a given surplus and token
    /// supply.
    /// @return cashOutCount The amount of tokens that should be considered cashed out.
    /// @return totalSupply The total amount of tokens that are considered to be existing.
    /// @return hookSpecifications The amount and data to send to cash out hooks instead of returning to the
    /// beneficiary.
    function beforeCashOutRecordedWith(JBBeforeCashOutRecordedContext calldata context)
        external
        view
        returns (
            uint256 cashOutTaxRate,
            uint256 cashOutCount,
            uint256 totalSupply,
            JBCashOutHookSpecification[] memory hookSpecifications
        );
}

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

import {JBApprovalStatus} from "./../enums/JBApprovalStatus.sol";
import {JBRuleset} from "./../structs/JBRuleset.sol";
import {IJBRulesetApprovalHook} from "./IJBRulesetApprovalHook.sol";

interface IJBRulesets {
    event RulesetInitialized(
        uint256 indexed rulesetId, uint256 indexed projectId, uint256 indexed basedOnId, address caller
    );
    event RulesetQueued(
        uint256 indexed rulesetId,
        uint256 indexed projectId,
        uint256 duration,
        uint256 weight,
        uint256 weightCutPercent,
        IJBRulesetApprovalHook approvalHook,
        uint256 metadata,
        uint256 mustStartAtOrAfter,
        address caller
    );

    event WeightCacheUpdated(uint256 projectId, uint112 weight, uint256 weightCutMultiple, address caller);

    function latestRulesetIdOf(uint256 projectId) external view returns (uint256);

    function currentApprovalStatusForLatestRulesetOf(uint256 projectId) external view returns (JBApprovalStatus);
    function currentOf(uint256 projectId) external view returns (JBRuleset memory ruleset);
    function deriveCycleNumberFrom(
        uint256 baseRulesetCycleNumber,
        uint256 baseRulesetStart,
        uint256 baseRulesetDuration,
        uint256 start
    )
        external
        returns (uint256);
    function deriveStartFrom(
        uint256 baseRulesetStart,
        uint256 baseRulesetDuration,
        uint256 mustStartAtOrAfter
    )
        external
        view
        returns (uint256 start);
    function deriveWeightFrom(
        uint256 projectId,
        uint256 baseRulesetStart,
        uint256 baseRulesetDuration,
        uint256 baseRulesetWeight,
        uint256 baseRulesetWeightCutPercent,
        uint256 baseRulesetCacheId,
        uint256 start
    )
        external
        view
        returns (uint256 weight);
    function getRulesetOf(uint256 projectId, uint256 rulesetId) external view returns (JBRuleset memory);
    function latestQueuedOf(uint256 projectId)
        external
        view
        returns (JBRuleset memory ruleset, JBApprovalStatus approvalStatus);
    function allOf(
        uint256 projectId,
        uint256 startingId,
        uint256 size
    )
        external
        view
        returns (JBRuleset[] memory rulesets);
    function upcomingOf(uint256 projectId) external view returns (JBRuleset memory ruleset);

    function queueFor(
        uint256 projectId,
        uint256 duration,
        uint256 weight,
        uint256 weightCutPercent,
        IJBRulesetApprovalHook approvalHook,
        uint256 metadata,
        uint256 mustStartAtOrAfter
    )
        external
        returns (JBRuleset memory ruleset);
    function updateRulesetWeightCache(uint256 projectId) external;
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {JBSplitHookContext} from "../structs/JBSplitHookContext.sol";

/// @title Split hook
/// @notice Allows processing a single split with custom logic.
/// @dev The split hook's address should be set as the `hook` in the relevant split.
interface IJBSplitHook is IERC165 {
    /// @notice If a split has a split hook, payment terminals and controllers call this function while processing the
    /// split.
    /// @dev Critical business logic should be protected by appropriate access control. The tokens and/or native tokens
    /// are optimistically transferred to the split hook when this function is called.
    /// @param context The context passed by the terminal/controller to the split hook as a `JBSplitHookContext` struct:
    function processSplitWith(JBSplitHookContext calldata context) external payable;
}

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

import {JBSplit} from "./../structs/JBSplit.sol";
import {JBSplitGroup} from "./../structs/JBSplitGroup.sol";

interface IJBSplits {
    event SetSplit(
        uint256 indexed projectId, uint256 indexed rulesetId, uint256 indexed groupId, JBSplit split, address caller
    );

    function FALLBACK_RULESET_ID() external view returns (uint256);

    function splitsOf(uint256 projectId, uint256 rulesetId, uint256 groupId) external view returns (JBSplit[] memory);

    function setSplitGroupsOf(uint256 projectId, uint256 rulesetId, JBSplitGroup[] memory splitGroups) external;
}

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

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {IJBPayHook} from "./IJBPayHook.sol";
import {JBAccountingContext} from "../structs/JBAccountingContext.sol";
import {JBAfterPayRecordedContext} from "../structs/JBAfterPayRecordedContext.sol";

/// @notice A terminal that accepts payments and can be migrated.
interface IJBTerminal is IERC165 {
    event AddToBalance(
        uint256 indexed projectId, uint256 amount, uint256 returnedFees, string memo, bytes metadata, address caller
    );
    event HookAfterRecordPay(
        IJBPayHook indexed hook, JBAfterPayRecordedContext context, uint256 specificationAmount, address caller
    );

    event MigrateTerminal(
        uint256 indexed projectId, address indexed token, IJBTerminal indexed to, uint256 amount, address caller
    );
    event Pay(
        uint256 indexed rulesetId,
        uint256 indexed rulesetCycleNumber,
        uint256 indexed projectId,
        address payer,
        address beneficiary,
        uint256 amount,
        uint256 newlyIssuedTokenCount,
        string memo,
        bytes metadata,
        address caller
    );
    event SetAccountingContext(uint256 indexed projectId, JBAccountingContext context, address caller);

    function accountingContextForTokenOf(
        uint256 projectId,
        address token
    )
        external
        view
        returns (JBAccountingContext memory);
    function accountingContextsOf(uint256 projectId) external view returns (JBAccountingContext[] memory);
    function currentSurplusOf(
        uint256 projectId,
        JBAccountingContext[] memory accountingContexts,
        uint256 decimals,
        uint256 currency
    )
        external
        view
        returns (uint256);

    function addAccountingContextsFor(uint256 projectId, JBAccountingContext[] calldata accountingContexts) external;
    function addToBalanceOf(
        uint256 projectId,
        address token,
        uint256 amount,
        bool shouldReturnHeldFees,
        string calldata memo,
        bytes calldata metadata
    )
        external
        payable;
    function migrateBalanceOf(uint256 projectId, address token, IJBTerminal to) external returns (uint256 balance);
    function pay(
        uint256 projectId,
        address token,
        uint256 amount,
        address beneficiary,
        uint256 minReturnedTokens,
        string calldata memo,
        bytes calldata metadata
    )
        external
        payable
        returns (uint256 beneficiaryTokenCount);
}

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

interface IJBToken {
    function balanceOf(address account) external view returns (uint256);
    function canBeAddedTo(uint256 projectId) external view returns (bool);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);

    function initialize(string memory name, string memory symbol, address owner) external;
    function burn(address account, uint256 amount) external;
    function mint(address account, uint256 amount) external;
}

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

interface IJBTokenUriResolver {
    function getUri(uint256 projectId) external view returns (string memory tokenUri);
}

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

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

interface IJBTokens {
    event DeployERC20(
        uint256 indexed projectId, IJBToken indexed token, string name, string symbol, bytes32 salt, address caller
    );
    event Burn(
        address indexed holder,
        uint256 indexed projectId,
        uint256 count,
        uint256 creditBalance,
        uint256 tokenBalance,
        address caller
    );
    event ClaimTokens(
        address indexed holder,
        uint256 indexed projectId,
        uint256 creditBalance,
        uint256 count,
        address beneficiary,
        address caller
    );
    event Mint(
        address indexed holder, uint256 indexed projectId, uint256 count, bool tokensWereClaimed, address caller
    );
    event SetToken(uint256 indexed projectId, IJBToken indexed token, address caller);
    event TransferCredits(
        address indexed holder, uint256 indexed projectId, address indexed recipient, uint256 count, address caller
    );

    function creditBalanceOf(address holder, uint256 projectId) external view returns (uint256);
    function projectIdOf(IJBToken token) external view returns (uint256);
    function tokenOf(uint256 projectId) external view returns (IJBToken);
    function totalCreditSupplyOf(uint256 projectId) external view returns (uint256);

    function totalBalanceOf(address holder, uint256 projectId) external view returns (uint256 result);
    function totalSupplyOf(uint256 projectId) external view returns (uint256);

    function burnFrom(address holder, uint256 projectId, uint256 count) external;
    function claimTokensFor(address holder, uint256 projectId, uint256 count, address beneficiary) external;
    function deployERC20For(
        uint256 projectId,
        string calldata name,
        string calldata symbol,
        bytes32 salt
    )
        external
        returns (IJBToken token);
    function mintFor(address holder, uint256 projectId, uint256 count) external returns (IJBToken token);
    function setTokenFor(uint256 projectId, IJBToken token) external;
    function transferCreditsFrom(address holder, uint256 projectId, address recipient, uint256 count) external;
}

File 37 of 58 : JBConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Global constants used across Juicebox contracts.
library JBConstants {
    /// @notice Each chain's native token address in Juicebox is represented by
    /// 0x000000000000000000000000000000000000EEEe.
    address public constant NATIVE_TOKEN = address(0x000000000000000000000000000000000000EEEe);
    uint16 public constant MAX_RESERVED_PERCENT = 10_000;
    uint16 public constant MAX_CASH_OUT_TAX_RATE = 10_000;
    uint32 public constant MAX_WEIGHT_CUT_PERCENT = 1_000_000_000;
    uint32 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;
    uint16 public constant MAX_FEE = 1000;
}

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

import {JBRuleset} from "./../structs/JBRuleset.sol";
import {JBRulesetMetadata} from "./../structs/JBRulesetMetadata.sol";

library JBRulesetMetadataResolver {
    function reservedPercent(JBRuleset memory ruleset) internal pure returns (uint16) {
        return uint16(ruleset.metadata >> 4);
    }

    function cashOutTaxRate(JBRuleset memory ruleset) internal pure returns (uint16) {
        // Cash out tax rate is a number 0-10000.
        return uint16(ruleset.metadata >> 20);
    }

    function baseCurrency(JBRuleset memory ruleset) internal pure returns (uint32) {
        // Currency is a number 0-4294967296.
        return uint32(ruleset.metadata >> 36);
    }

    function pausePay(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 68) & 1) == 1;
    }

    function pauseCreditTransfers(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 69) & 1) == 1;
    }

    function allowOwnerMinting(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 70) & 1) == 1;
    }

    function allowSetCustomToken(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 71) & 1) == 1;
    }

    function allowTerminalMigration(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 72) & 1) == 1;
    }

    function allowSetTerminals(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 73) & 1) == 1;
    }

    function allowSetController(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 74) & 1) == 1;
    }

    function allowAddAccountingContext(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 75) & 1) == 1;
    }

    function allowAddPriceFeed(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 76) & 1) == 1;
    }

    function ownerMustSendPayouts(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 77) & 1) == 1;
    }

    function holdFees(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 78) & 1) == 1;
    }

    function useTotalSurplusForCashOuts(JBRuleset memory ruleset) internal pure returns (bool) {
        return ((ruleset.metadata >> 79) & 1) == 1;
    }

    function useDataHookForPay(JBRuleset memory ruleset) internal pure returns (bool) {
        return (ruleset.metadata >> 80) & 1 == 1;
    }

    function useDataHookForCashOut(JBRuleset memory ruleset) internal pure returns (bool) {
        return (ruleset.metadata >> 81) & 1 == 1;
    }

    function dataHook(JBRuleset memory ruleset) internal pure returns (address) {
        return address(uint160(ruleset.metadata >> 82));
    }

    function metadata(JBRuleset memory ruleset) internal pure returns (uint16) {
        return uint16(ruleset.metadata >> 242);
    }

    /// @notice Pack the funding cycle metadata.
    /// @param rulesetMetadata The ruleset metadata to validate and pack.
    /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version.
    function packRulesetMetadata(JBRulesetMetadata memory rulesetMetadata) internal pure returns (uint256 packed) {
        // version 1 in the bits 0-3 (4 bits).
        packed = 1;
        // reserved percent in bits 4-19 (16 bits).
        packed |= uint256(rulesetMetadata.reservedPercent) << 4;
        // cash out tax rate in bits 20-35 (16 bits).
        // cash out tax rate is a number 0-10000.
        packed |= uint256(rulesetMetadata.cashOutTaxRate) << 20;
        // base currency in bits 36-67 (32 bits).
        // base currency is a number 0-16777215.
        packed |= uint256(rulesetMetadata.baseCurrency) << 36;
        // pause pay in bit 68.
        if (rulesetMetadata.pausePay) packed |= 1 << 68;
        // pause credit transfers in bit 69.
        if (rulesetMetadata.pauseCreditTransfers) packed |= 1 << 69;
        // allow discretionary minting in bit 70.
        if (rulesetMetadata.allowOwnerMinting) packed |= 1 << 70;
        // allow a custom token to be set in bit 71.
        if (rulesetMetadata.allowSetCustomToken) packed |= 1 << 71;
        // allow terminal migration in bit 72.
        if (rulesetMetadata.allowTerminalMigration) packed |= 1 << 72;
        // allow set terminals in bit 73.
        if (rulesetMetadata.allowSetTerminals) packed |= 1 << 73;
        // allow set controller in bit 74.
        if (rulesetMetadata.allowSetController) packed |= 1 << 74;
        // allow add accounting context in bit 75.
        if (rulesetMetadata.allowAddAccountingContext) packed |= 1 << 75;
        // allow add price feed in bit 76.
        if (rulesetMetadata.allowAddPriceFeed) packed |= 1 << 76;
        // allow controller migration in bit 77.
        if (rulesetMetadata.ownerMustSendPayouts) packed |= 1 << 77;
        // hold fees in bit 78.
        if (rulesetMetadata.holdFees) packed |= 1 << 78;
        // useTotalSurplusForCashOuts in bit 79.
        if (rulesetMetadata.useTotalSurplusForCashOuts) packed |= 1 << 79;
        // use pay data source in bit 80.
        if (rulesetMetadata.useDataHookForPay) packed |= 1 << 80;
        // use cash out data source in bit 81.
        if (rulesetMetadata.useDataHookForCashOut) packed |= 1 << 81;
        // data source address in bits 82-241.
        packed |= uint256(uint160(address(rulesetMetadata.dataHook))) << 82;
        // metadata in bits 242-255 (14 bits).
        packed |= (uint256(rulesetMetadata.metadata) & 0x3FFF) << 242;
    }

    /// @notice Expand the funding cycle metadata.
    /// @param ruleset The funding cycle having its metadata expanded.
    /// @return rulesetMetadata The ruleset's metadata object.
    function expandMetadata(JBRuleset memory ruleset) internal pure returns (JBRulesetMetadata memory) {
        return JBRulesetMetadata(
            reservedPercent(ruleset),
            cashOutTaxRate(ruleset),
            baseCurrency(ruleset),
            pausePay(ruleset),
            pauseCreditTransfers(ruleset),
            allowOwnerMinting(ruleset),
            allowSetCustomToken(ruleset),
            allowTerminalMigration(ruleset),
            allowSetTerminals(ruleset),
            allowSetController(ruleset),
            allowAddAccountingContext(ruleset),
            allowAddPriceFeed(ruleset),
            ownerMustSendPayouts(ruleset),
            holdFees(ruleset),
            useTotalSurplusForCashOuts(ruleset),
            useDataHookForPay(ruleset),
            useDataHookForCashOut(ruleset),
            dataHook(ruleset),
            metadata(ruleset)
        );
    }
}

File 39 of 58 : JBSplitGroupIds.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Group IDs that categorize splits.
library JBSplitGroupIds {
    uint256 public constant RESERVED_TOKENS = 1;
}

File 40 of 58 : JBAccountingContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @custom:member token The address of the token that accounting is being done with.
/// @custom:member decimals The number of decimals expected in that token's fixed point accounting.
/// @custom:member currency The currency that the token is priced in terms of. By convention, this is
/// `uint32(uint160(tokenAddress))` for tokens, or a constant ID from e.g. `JBCurrencyIds` for other currencies.
struct JBAccountingContext {
    address token;
    uint8 decimals;
    uint32 currency;
}

File 41 of 58 : JBAfterCashOutRecordedContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @custom:member holder The holder of the tokens being cashed out.
/// @custom:member projectId The ID of the project being cashed out from.
/// @custom:member rulesetId The ID of the ruleset the cash out is being made during.
/// @custom:member cashOutCount The number of project tokens being cashed out.
/// @custom:member cashOutTaxRate The current ruleset's cash out tax rate.
/// @custom:member reclaimedAmount The token amount being reclaimed from the project's terminal balance. Includes the
/// token being
/// reclaimed, the value, the number of decimals included, and the currency of the amount.
/// @custom:member forwardedAmount The token amount being forwarded to the cash out hook. Includes the token
/// being forwarded, the value, the number of decimals included, and the currency of the amount.
/// @custom:member beneficiary The address the reclaimed amount will be sent to.
/// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the cash out hook.
/// @custom:member cashOutMetadata Extra data specified by the account cashing out, which is sent to the cash out hook.
struct JBAfterCashOutRecordedContext {
    address holder;
    uint256 projectId;
    uint256 rulesetId;
    uint256 cashOutCount;
    JBTokenAmount reclaimedAmount;
    JBTokenAmount forwardedAmount;
    uint256 cashOutTaxRate;
    address payable beneficiary;
    bytes hookMetadata;
    bytes cashOutMetadata;
}

File 42 of 58 : JBAfterPayRecordedContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @custom:member payer The address the payment originated from.
/// @custom:member projectId The ID of the project being paid.
/// @custom:member rulesetId The ID of the ruleset the payment is being made during.
/// @custom:member amount The payment's token amount. Includes the token being paid, the value, the number of decimals
/// included, and the currency of the amount.
/// @custom:member forwardedAmount The token amount being forwarded to the pay hook. Includes the token
/// being paid, the value, the number of decimals included, and the currency of the amount.
/// @custom:member weight The current ruleset's weight (used to determine how many tokens should be minted).
/// @custom:member newlyIssuedTokenCount The number of project tokens minted for the beneficiary.
/// @custom:member beneficiary The address which receives any tokens this payment yields.
/// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the pay hook.
/// @custom:member payerMetadata Extra data specified by the payer, which is sent to the pay hook.
struct JBAfterPayRecordedContext {
    address payer;
    uint256 projectId;
    uint256 rulesetId;
    JBTokenAmount amount;
    JBTokenAmount forwardedAmount;
    uint256 weight;
    uint256 newlyIssuedTokenCount;
    address beneficiary;
    bytes hookMetadata;
    bytes payerMetadata;
}

File 43 of 58 : JBBeforeCashOutRecordedContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @notice Context sent from the terminal to the ruleset's data hook upon cash out.
/// @custom:member terminal The terminal that is facilitating the cash out.
/// @custom:member holder The holder of the tokens being cashed out.
/// @custom:member projectId The ID of the project whose tokens are being cashed out.
/// @custom:member rulesetId The ID of the ruleset the cash out is being made during.
/// @custom:member cashOutCount The number of tokens being cashed out, as a fixed point number with 18 decimals.
/// @custom:member totalSupply The total token supply being used for the calculation, as a fixed point number with 18
/// decimals.
/// @custom:member surplus The surplus amount used for the calculation, as a fixed point number with 18 decimals.
/// Includes the token of the surplus, the surplus value, the number of decimals
/// included, and the currency of the surplus.
/// @custom:member useTotalSurplus If surplus across all of a project's terminals is being used when making cash outs.
/// @custom:member cashOutTaxRate The cash out tax rate of the ruleset the cash out is being made during.
/// @custom:member metadata Extra data provided by the casher.
struct JBBeforeCashOutRecordedContext {
    address terminal;
    address holder;
    uint256 projectId;
    uint256 rulesetId;
    uint256 cashOutCount;
    uint256 totalSupply;
    JBTokenAmount surplus;
    bool useTotalSurplus;
    uint256 cashOutTaxRate;
    bytes metadata;
}

File 44 of 58 : JBBeforePayRecordedContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @notice Context sent from the terminal to the ruleset's data hook upon payment.
/// @custom:member terminal The terminal that is facilitating the payment.
/// @custom:member payer The address that the payment originated from.
/// @custom:member amount The payment's token amount, including the token being paid, the value, the number of decimals
/// included, and the currency of the amount.
/// @custom:member projectId The ID of the project being paid.
/// @custom:member rulesetId The ID of the ruleset the payment is being made during.
/// @custom:member beneficiary The specified address that should be the beneficiary of anything that this payment
/// yields.
/// @custom:member weight The weight of the ruleset during which the payment is being made.
/// @custom:member reservedPercent The reserved percent of the ruleset the payment is being made during.
/// @custom:member metadata Extra data specified by the payer.
struct JBBeforePayRecordedContext {
    address terminal;
    address payer;
    JBTokenAmount amount;
    uint256 projectId;
    uint256 rulesetId;
    address beneficiary;
    uint256 weight;
    uint256 reservedPercent;
    bytes metadata;
}

File 45 of 58 : JBCashOutHookSpecification.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @notice A cash out hook specification sent from the ruleset's data hook back to the terminal. This specification is
/// fulfilled by the terminal.
/// @custom:member hook The cash out hook to use when fulfilling this specification.
/// @custom:member amount The amount to send to the hook.
/// @custom:member metadata Metadata to pass to the hook.
struct JBCashOutHookSpecification {
    IJBCashOutHook hook;
    uint256 amount;
    bytes metadata;
}

File 46 of 58 : JBCurrencyAmount.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @custom:member amount The amount of the currency.
/// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
/// constant ID from e.g. `JBCurrencyIds` for other currencies.
struct JBCurrencyAmount {
    uint224 amount;
    uint32 currency;
}

File 47 of 58 : JBFundAccessLimitGroup.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @dev Payout limit example: if the `amount` is 5, the `currency` is 1 (USD), and the terminal's token is ETH, then
/// the project can pay out 5 USD worth of ETH during a ruleset.
/// @dev Surplus allowance example: if the `amount` is 5, the `currency` is 1 (USD), and the terminal's token is ETH,
/// then the project can pay out 5 USD worth of ETH from its surplus during a ruleset. A project's surplus is its
/// balance minus its current combined payout limit.
/// @dev If a project has multiple payout limits or surplus allowances, they are all available. They can all be used
/// during a single ruleset.
/// @dev The payout limits' and surplus allowances' fixed point amounts have the same number of decimals as the
/// terminal.
/// @custom:member terminal The terminal that the payout limits and surplus allowances apply to.
/// @custom:member token The token that the payout limits and surplus allowances apply to within the `terminal`.
/// @custom:member payoutLimits An array of payout limits. The payout limits cumulatively dictate the maximum value of
/// `token`s a project can pay out from its balance in a terminal during a ruleset. Each payout limit can have a unique
/// currency and amount.
/// @custom:member surplusAllowances An array of surplus allowances. The surplus allowances cumulatively dictates the
/// maximum value of `token`s a project can pay out from its surplus (balance less payouts) in a terminal during a
/// ruleset. Each surplus allowance can have a unique currency and amount.
struct JBFundAccessLimitGroup {
    address terminal;
    address token;
    JBCurrencyAmount[] payoutLimits;
    JBCurrencyAmount[] surplusAllowances;
}

File 48 of 58 : JBPayHookSpecification.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @notice A pay hook specification sent from the ruleset's data hook back to the terminal. This specification is
/// fulfilled by the terminal.
/// @custom:member hook The pay hook to use when fulfilling this specification.
/// @custom:member amount The amount to send to the hook.
/// @custom:member metadata Metadata to pass the hook.
struct JBPayHookSpecification {
    IJBPayHook hook;
    uint256 amount;
    bytes metadata;
}

File 49 of 58 : JBPermissionsData.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @custom:member operator The address that permissions are being given to.
/// @custom:member projectId The ID of the project the operator is being given permissions for. Operators only have
/// permissions under this project's scope. An ID of 0 is a wildcard, which gives an operator permissions across all
/// projects.
/// @custom:member permissionIds The IDs of the permissions being given. See the `JBPermissionIds` library.
struct JBPermissionsData {
    address operator;
    uint64 projectId;
    uint8[] permissionIds;
}

File 50 of 58 : JBRuleset.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @dev `JBRuleset` timestamps are unix timestamps (seconds since 00:00 January 1st, 1970 UTC).
/// @custom:member cycleNumber The ruleset's cycle number. Each ruleset's `cycleNumber` is the previous ruleset's
/// `cycleNumber` plus one. Each project's first ruleset has a `cycleNumber` of 1.
/// @custom:member id The ruleset's ID, which is a timestamp of when this ruleset's rules were initialized. The
/// `rulesetId` stays the same for rulesets that automatically cycle over from a manually queued ruleset.
/// @custom:member basedOnId The `rulesetId` of the ruleset which was active when this ruleset was created.
/// @custom:member start The timestamp from which this ruleset is considered active.
/// @custom:member duration The number of seconds the ruleset lasts for. After this duration, a new ruleset will start.
/// The project owner can queue new rulesets at any time, which will take effect once the current ruleset's duration is
/// over. If the `duration` is 0, newly queued rulesets will take effect immediately. If a ruleset ends and there are no
/// new rulesets queued, the current ruleset cycles over to another one with the same properties but a new `start`
/// timestamp and a `weight` reduced by the ruleset's `weightCutPercent`.
/// @custom:member weight A fixed point number with 18 decimals which is typically used by payment terminals to
/// determine how many tokens should be minted when a payment is received. This can be used by other contracts for
/// arbitrary calculations.
/// @custom:member weightCutPercent The percentage by which to reduce the `weight` each time a new ruleset starts.
/// `weight`
/// is
/// a percentage out of `JBConstants.MAX_WEIGHT_CUT_PERCENT`. If it's 0, the next ruleset will have the same `weight` by
/// default. If it's 90%, the next ruleset's `weight` will be 10% smaller. If a ruleset explicitly sets a new `weight`,
/// the `weightCutPercent` doesn't apply.
/// @custom:member approvalHook An address of a contract that says whether a queued ruleset should be approved or
/// rejected. If a
/// ruleset is rejected, it won't go into effect. An approval hook can be used to create rules which dictate how a
/// project owner can change their ruleset over time.
/// @custom:member metadata Extra data associated with a ruleset which can be used by other contracts.
struct JBRuleset {
    uint48 cycleNumber;
    uint48 id;
    uint48 basedOnId;
    uint48 start;
    uint32 duration;
    uint112 weight;
    uint32 weightCutPercent;
    IJBRulesetApprovalHook approvalHook;
    uint256 metadata;
}

File 51 of 58 : JBRulesetConfig.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IJBRulesetApprovalHook} from "../interfaces/IJBRulesetApprovalHook.sol";
import {JBFundAccessLimitGroup} from "./JBFundAccessLimitGroup.sol";
import {JBRulesetMetadata} from "./JBRulesetMetadata.sol";
import {JBSplitGroup} from "./JBSplitGroup.sol";

/// @custom:member mustStartAtOrAfter The earliest time the ruleset can start.
/// @custom:member duration The number of seconds the ruleset lasts for, after which a new ruleset will start. A
/// duration of 0 means that the ruleset will stay active until the project owner explicitly issues a reconfiguration,
/// at which point a new ruleset will immediately start with the updated properties. If the duration is greater than 0,
/// a project owner cannot make changes to a ruleset's parameters while it is active – any proposed changes will apply
/// to the subsequent ruleset. If no changes are proposed, a ruleset rolls over to another one with the same properties
/// but new `start` timestamp and a cut `weight`.
/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations
/// on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is
/// received.
/// @custom:member weightCutPercent A percent by how much the `weight` of the subsequent ruleset should be reduced, if
/// the
/// project owner hasn't queued the subsequent ruleset with an explicit `weight`. If it's 0, each ruleset will have
/// equal weight. If the number is 90%, the next ruleset will have a 10% smaller weight. This weight is out of
/// `JBConstants.MAX_WEIGHT_CUT_PERCENT`.
/// @custom:member approvalHook An address of a contract that says whether a proposed ruleset should be accepted or
/// rejected. It
/// can be used to create rules around how a project owner can change ruleset parameters over time.
/// @custom:member metadata Metadata specifying the controller-specific parameters that a ruleset can have. These
/// properties cannot change until the next ruleset starts.
/// @custom:member splitGroups An array of splits to use for any number of groups while the ruleset is active.
/// @custom:member fundAccessLimitGroups An array of structs which dictate the amount of funds a project can access from
/// its balance in each payment terminal while the ruleset is active. Amounts are fixed point numbers using the same
/// number of decimals as the corresponding terminal. The `_payoutLimit` and `_surplusAllowance` parameters must fit in
/// a `uint232`.
struct JBRulesetConfig {
    uint48 mustStartAtOrAfter;
    uint32 duration;
    uint112 weight;
    uint32 weightCutPercent;
    IJBRulesetApprovalHook approvalHook;
    JBRulesetMetadata metadata;
    JBSplitGroup[] splitGroups;
    JBFundAccessLimitGroup[] fundAccessLimitGroups;
}

File 52 of 58 : JBRulesetMetadata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @custom:member reservedPercent The reserved percent of the ruleset. This number is a percentage calculated out of
/// `JBConstants.MAX_RESERVED_PERCENT`.
/// @custom:member cashOutTaxRate The cash out tax rate of the ruleset. This number is a percentage calculated out of
/// `JBConstants.MAX_CASH_OUT_TAX_RATE`.
/// @custom:member baseCurrency The currency on which to base the ruleset's weight. By convention, this is
/// `uint32(uint160(tokenAddress))` for tokens, or a constant ID from e.g. `JBCurrencyIds` for other currencies.
/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the ruleset.
/// @custom:member pauseCreditTransfers A flag indicating if the project token transfer functionality should be paused
/// during the funding cycle.
/// @custom:member allowOwnerMinting A flag indicating if the project owner or an operator with the `MINT_TOKENS`
/// permission from the owner should be allowed to mint project tokens on demand during this ruleset.
/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this
/// ruleset.
/// @custom:member allowSetTerminals A flag indicating if a project's terminals can be added or removed.
/// @custom:member allowSetController A flag indicating if a project's controller can be changed.
/// @custom:member allowAddAccountingContext A flag indicating if a project can add new accounting contexts for its
/// terminals to use.
/// @custom:member allowAddPriceFeed A flag indicating if a project can add new price feeds to calculate exchange rates
/// between its tokens.
/// @custom:member ownerMustSendPayouts A flag indicating if privileged payout distribution should be
/// enforced, otherwise payouts can be distributed by anyone.
/// @custom:member holdFees A flag indicating if fees should be held during this ruleset.
/// @custom:member useTotalSurplusForCashOuts A flag indicating if cash outs should use the project's balance held
/// in all terminals instead of the project's local terminal balance from which the cash out is being fulfilled.
/// @custom:member useDataHookForPay A flag indicating if the data hook should be used for pay transactions during this
/// ruleset.
/// @custom:member useDataHookForCashOut A flag indicating if the data hook should be used for cash out transactions
/// during
/// this ruleset.
/// @custom:member dataHook The data hook to use during this ruleset.
/// @custom:member metadata Metadata of the metadata, only the 14 least significant bits can be used, the 2 most
/// significant bits are disregarded.
struct JBRulesetMetadata {
    uint16 reservedPercent;
    uint16 cashOutTaxRate;
    uint32 baseCurrency;
    bool pausePay;
    bool pauseCreditTransfers;
    bool allowOwnerMinting;
    bool allowSetCustomToken;
    bool allowTerminalMigration;
    bool allowSetTerminals;
    bool allowSetController;
    bool allowAddAccountingContext;
    bool allowAddPriceFeed;
    bool ownerMustSendPayouts;
    bool holdFees;
    bool useTotalSurplusForCashOuts;
    bool useDataHookForPay;
    bool useDataHookForCashOut;
    address dataHook;
    uint16 metadata;
}

File 53 of 58 : JBRulesetWithMetadata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {JBRuleset} from "./JBRuleset.sol";
import {JBRulesetMetadata} from "./JBRulesetMetadata.sol";

/// @custom:member ruleset The ruleset.
/// @custom:member metadata The ruleset's metadata.
struct JBRulesetWithMetadata {
    JBRuleset ruleset;
    JBRulesetMetadata metadata;
}

File 54 of 58 : JBSplit.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @notice Splits are used to send a percentage of a total token amount to a specific contract, project, or address.
/// Splits are used to send payouts and reserved tokens.
/// @dev 1. If a non-zero split hook contract is specified, this split's tokens are sent there along with this split's
/// properties.
/// @dev 2. Otherwise, if a non-zero project ID is specified, this split's tokens are used to `pay` it through its
/// terminal if possible, or sent to the project's owner if not. If this payment yields tokens, those go to the split's
/// `beneficiary`.
/// @dev 3. Otherwise, this split's tokens are sent directly to the `beneficiary`.
/// @dev To summarize, this split's tokens are sent according to the following priority: `split hook` > `projectId` >
/// `beneficiary`.
/// @custom:member percent The percent of the total token amount that this split sends. This number is out of
/// `JBConstants.SPLITS_TOTAL_PERCENT`.
/// @custom:member projectId The ID of a project to `pay`, if applicable. Resulting tokens will be routed to the
/// `beneficiary`.
/// @custom:member beneficiary Receives this split's tokens if the `hook` and `projectId` are zero. If the `projectId`
/// is specified, the `beneficiary` receives any project tokens minted by this split.
/// @custom:member preferAddToBalance If this split were to `pay` a project through its terminal, this flag indicates
/// whether it should prefer using the terminal's `addToBalance` function instead.
/// @custom:member lockedUntil The split cannot be changed until this timestamp. The `lockedUntil` timestamp can be
/// increased while a split is locked. If `lockedUntil` is zero, this split can be changed at any time.
/// @custom:member hook A contract which will receive this split's tokens and properties, and can define custom
/// behavior.
struct JBSplit {
    uint32 percent;
    uint64 projectId;
    address payable beneficiary;
    bool preferAddToBalance;
    uint48 lockedUntil;
    IJBSplitHook hook;
}

File 55 of 58 : JBSplitGroup.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @custom:member groupId An identifier for the group. By convention, this ID is `uint256(uint160(tokenAddress))` for
/// payouts and `1` for reserved tokens.
/// @custom:member splits The splits in the group.
struct JBSplitGroup {
    uint256 groupId;
    JBSplit[] splits;
}

File 56 of 58 : JBSplitHookContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @custom:member token The token being sent to the split hook.
/// @custom:member amount The amount being sent to the split hook, as a fixed point number.
/// @custom:member decimals The number of decimals in the amount.
/// @custom:member projectId The project the split belongs to.
/// @custom:member groupId The group the split belongs to. By convention, this ID is `uint256(uint160(tokenAddress))`
/// for payouts and `1` for reserved tokens.
/// @custom:member split The split which specified the hook.
struct JBSplitHookContext {
    address token;
    uint256 amount;
    uint256 decimals;
    uint256 projectId;
    uint256 groupId;
    JBSplit split;
}

File 57 of 58 : JBTerminalConfig.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {JBAccountingContext} from "./JBAccountingContext.sol";
import {IJBTerminal} from "./../interfaces/IJBTerminal.sol";

/// @custom:member terminal The terminal to configure.
/// @custom:member accountingContextsToAccept The accounting contexts to accept from the terminal.
struct JBTerminalConfig {
    IJBTerminal terminal;
    JBAccountingContext[] accountingContextsToAccept;
}

File 58 of 58 : JBTokenAmount.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @custom:member token The token the payment was made in.
/// @custom:member decimals The number of decimals included in the value fixed point number.
/// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
/// constant ID from e.g. `JBCurrencyIds` for other currencies.
/// @custom:member value The amount of tokens that was paid, as a fixed point number.
struct JBTokenAmount {
    address token;
    uint8 decimals;
    uint32 currency;
    uint256 value;
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "appendCBOR": true,
    "bytecodeHash": "ipfs",
    "useLiteralContent": false
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": [
    "@sphinx-labs/contracts/=lib/sphinx/packages/contracts/contracts/foundry/",
    "@arbitrum/=node_modules/@arbitrum/",
    "@bananapus/=node_modules/@bananapus/",
    "@chainlink/=node_modules/@chainlink/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@offchainlabs/=node_modules/@offchainlabs/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@prb/=node_modules/@prb/",
    "@scroll-tech/=node_modules/@scroll-tech/",
    "@uniswap/=node_modules/@uniswap/",
    "@zksync/=node_modules/@zksync/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/",
    "solmate/=node_modules/solmate/",
    "sphinx/=lib/sphinx/packages/contracts/contracts/forge-std/src/"
  ],
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IJBDirectory","name":"directory","type":"address"},{"internalType":"contract IJBFundAccessLimits","name":"fundAccessLimits","type":"address"},{"internalType":"contract IJBPermissions","name":"permissions","type":"address"},{"internalType":"contract IJBPrices","name":"prices","type":"address"},{"internalType":"contract IJBProjects","name":"projects","type":"address"},{"internalType":"contract IJBRulesets","name":"rulesets","type":"address"},{"internalType":"contract IJBSplits","name":"splits","type":"address"},{"internalType":"contract IJBTokens","name":"tokens","type":"address"},{"internalType":"address","name":"trustedForwarder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"JBController_AddingPriceFeedNotAllowed","type":"error"},{"inputs":[],"name":"JBController_CreditTransfersPaused","type":"error"},{"inputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"JBController_InvalidCashOutTaxRate","type":"error"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"JBController_InvalidReservedPercent","type":"error"},{"inputs":[],"name":"JBController_MintNotAllowedAndNotTerminalOrHook","type":"error"},{"inputs":[],"name":"JBController_NoReservedTokens","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"contract IJBDirectory","name":"directory","type":"address"}],"name":"JBController_OnlyDirectory","type":"error"},{"inputs":[],"name":"JBController_RulesetSetTokenNotAllowed","type":"error"},{"inputs":[],"name":"JBController_RulesetsAlreadyLaunched","type":"error"},{"inputs":[],"name":"JBController_RulesetsArrayEmpty","type":"error"},{"inputs":[],"name":"JBController_ZeroTokensToBurn","type":"error"},{"inputs":[],"name":"JBController_ZeroTokensToMint","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"permissionId","type":"uint256"}],"name":"JBPermissioned_Unauthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath_MulDiv_Overflow","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenCount","type":"uint256"},{"indexed":false,"internalType":"string","name":"memo","type":"string"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"BurnTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rulesetId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"string","name":"projectUri","type":"string"},{"indexed":false,"internalType":"string","name":"memo","type":"string"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"LaunchProject","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rulesetId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"string","name":"memo","type":"string"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"LaunchRulesets","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"contract IERC165","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"Migrate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"beneficiaryTokenCount","type":"uint256"},{"indexed":false,"internalType":"string","name":"memo","type":"string"},{"indexed":false,"internalType":"uint256","name":"reservedPercent","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"MintTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"PrepMigration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rulesetId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"string","name":"memo","type":"string"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"QueueRulesets","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"components":[{"internalType":"uint32","name":"percent","type":"uint32"},{"internalType":"uint64","name":"projectId","type":"uint64"},{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"bool","name":"preferAddToBalance","type":"bool"},{"internalType":"uint48","name":"lockedUntil","type":"uint48"},{"internalType":"contract IJBSplitHook","name":"hook","type":"address"}],"indexed":false,"internalType":"struct JBSplit","name":"split","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"tokenCount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"ReservedDistributionReverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"rulesetId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"components":[{"internalType":"uint32","name":"percent","type":"uint32"},{"internalType":"uint64","name":"projectId","type":"uint64"},{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"bool","name":"preferAddToBalance","type":"bool"},{"internalType":"uint48","name":"lockedUntil","type":"uint48"},{"internalType":"contract IJBSplitHook","name":"hook","type":"address"}],"indexed":false,"internalType":"struct JBSplit","name":"split","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"tokenCount","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"SendReservedTokensToSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rulesetId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"rulesetCycleNumber","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leftoverAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"SendReservedTokensToSplits","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"string","name":"uri","type":"string"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"SetUri","type":"event"},{"inputs":[],"name":"DIRECTORY","outputs":[{"internalType":"contract IJBDirectory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FUND_ACCESS_LIMITS","outputs":[{"internalType":"contract IJBFundAccessLimits","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMISSIONS","outputs":[{"internalType":"contract IJBPermissions","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICES","outputs":[{"internalType":"contract IJBPrices","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROJECTS","outputs":[{"internalType":"contract IJBProjects","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RULESETS","outputs":[{"internalType":"contract IJBRulesets","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPLITS","outputs":[{"internalType":"contract IJBSplits","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKENS","outputs":[{"internalType":"contract IJBTokens","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"pricingCurrency","type":"uint256"},{"internalType":"uint256","name":"unitCurrency","type":"uint256"},{"internalType":"contract IJBPriceFeed","name":"feed","type":"address"}],"name":"addPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"startingId","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"allRulesetsOf","outputs":[{"components":[{"components":[{"internalType":"uint48","name":"cycleNumber","type":"uint48"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"basedOnId","type":"uint48"},{"internalType":"uint48","name":"start","type":"uint48"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"weight","type":"uint112"},{"internalType":"uint32","name":"weightCutPercent","type":"uint32"},{"internalType":"contract IJBRulesetApprovalHook","name":"approvalHook","type":"address"},{"internalType":"uint256","name":"metadata","type":"uint256"}],"internalType":"struct JBRuleset","name":"ruleset","type":"tuple"},{"components":[{"internalType":"uint16","name":"reservedPercent","type":"uint16"},{"internalType":"uint16","name":"cashOutTaxRate","type":"uint16"},{"internalType":"uint32","name":"baseCurrency","type":"uint32"},{"internalType":"bool","name":"pausePay","type":"bool"},{"internalType":"bool","name":"pauseCreditTransfers","type":"bool"},{"internalType":"bool","name":"allowOwnerMinting","type":"bool"},{"internalType":"bool","name":"allowSetCustomToken","type":"bool"},{"internalType":"bool","name":"allowTerminalMigration","type":"bool"},{"internalType":"bool","name":"allowSetTerminals","type":"bool"},{"internalType":"bool","name":"allowSetController","type":"bool"},{"internalType":"bool","name":"allowAddAccountingContext","type":"bool"},{"internalType":"bool","name":"allowAddPriceFeed","type":"bool"},{"internalType":"bool","name":"ownerMustSendPayouts","type":"bool"},{"internalType":"bool","name":"holdFees","type":"bool"},{"internalType":"bool","name":"useTotalSurplusForCashOuts","type":"bool"},{"internalType":"bool","name":"useDataHookForPay","type":"bool"},{"internalType":"bool","name":"useDataHookForCashOut","type":"bool"},{"internalType":"address","name":"dataHook","type":"address"},{"internalType":"uint16","name":"metadata","type":"uint16"}],"internalType":"struct JBRulesetMetadata","name":"metadata","type":"tuple"}],"internalType":"struct JBRulesetWithMetadata[]","name":"rulesets","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC165","name":"from","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"beforeReceiveMigrationFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"tokenCount","type":"uint256"},{"internalType":"string","name":"memo","type":"string"}],"name":"burnTokensOf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"tokenCount","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"}],"name":"claimTokensFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"currentRulesetOf","outputs":[{"components":[{"internalType":"uint48","name":"cycleNumber","type":"uint48"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"basedOnId","type":"uint48"},{"internalType":"uint48","name":"start","type":"uint48"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"weight","type":"uint112"},{"internalType":"uint32","name":"weightCutPercent","type":"uint32"},{"internalType":"contract IJBRulesetApprovalHook","name":"approvalHook","type":"address"},{"internalType":"uint256","name":"metadata","type":"uint256"}],"internalType":"struct JBRuleset","name":"ruleset","type":"tuple"},{"components":[{"internalType":"uint16","name":"reservedPercent","type":"uint16"},{"internalType":"uint16","name":"cashOutTaxRate","type":"uint16"},{"internalType":"uint32","name":"baseCurrency","type":"uint32"},{"internalType":"bool","name":"pausePay","type":"bool"},{"internalType":"bool","name":"pauseCreditTransfers","type":"bool"},{"internalType":"bool","name":"allowOwnerMinting","type":"bool"},{"internalType":"bool","name":"allowSetCustomToken","type":"bool"},{"internalType":"bool","name":"allowTerminalMigration","type":"bool"},{"internalType":"bool","name":"allowSetTerminals","type":"bool"},{"internalType":"bool","name":"allowSetController","type":"bool"},{"internalType":"bool","name":"allowAddAccountingContext","type":"bool"},{"internalType":"bool","name":"allowAddPriceFeed","type":"bool"},{"internalType":"bool","name":"ownerMustSendPayouts","type":"bool"},{"internalType":"bool","name":"holdFees","type":"bool"},{"internalType":"bool","name":"useTotalSurplusForCashOuts","type":"bool"},{"internalType":"bool","name":"useDataHookForPay","type":"bool"},{"internalType":"bool","name":"useDataHookForCashOut","type":"bool"},{"internalType":"address","name":"dataHook","type":"address"},{"internalType":"uint16","name":"metadata","type":"uint16"}],"internalType":"struct JBRulesetMetadata","name":"metadata","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"deployERC20For","outputs":[{"internalType":"contract IJBToken","name":"token","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IJBTerminal","name":"terminal","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"contract IJBToken","name":"token","type":"address"},{"internalType":"uint256","name":"splitTokenCount","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"executePayReservedTokenToTerminal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"rulesetId","type":"uint256"}],"name":"getRulesetOf","outputs":[{"components":[{"internalType":"uint48","name":"cycleNumber","type":"uint48"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"basedOnId","type":"uint48"},{"internalType":"uint48","name":"start","type":"uint48"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"weight","type":"uint112"},{"internalType":"uint32","name":"weightCutPercent","type":"uint32"},{"internalType":"contract IJBRulesetApprovalHook","name":"approvalHook","type":"address"},{"internalType":"uint256","name":"metadata","type":"uint256"}],"internalType":"struct JBRuleset","name":"ruleset","type":"tuple"},{"components":[{"internalType":"uint16","name":"reservedPercent","type":"uint16"},{"internalType":"uint16","name":"cashOutTaxRate","type":"uint16"},{"internalType":"uint32","name":"baseCurrency","type":"uint32"},{"internalType":"bool","name":"pausePay","type":"bool"},{"internalType":"bool","name":"pauseCreditTransfers","type":"bool"},{"internalType":"bool","name":"allowOwnerMinting","type":"bool"},{"internalType":"bool","name":"allowSetCustomToken","type":"bool"},{"internalType":"bool","name":"allowTerminalMigration","type":"bool"},{"internalType":"bool","name":"allowSetTerminals","type":"bool"},{"internalType":"bool","name":"allowSetController","type":"bool"},{"internalType":"bool","name":"allowAddAccountingContext","type":"bool"},{"internalType":"bool","name":"allowAddPriceFeed","type":"bool"},{"internalType":"bool","name":"ownerMustSendPayouts","type":"bool"},{"internalType":"bool","name":"holdFees","type":"bool"},{"internalType":"bool","name":"useTotalSurplusForCashOuts","type":"bool"},{"internalType":"bool","name":"useDataHookForPay","type":"bool"},{"internalType":"bool","name":"useDataHookForCashOut","type":"bool"},{"internalType":"address","name":"dataHook","type":"address"},{"internalType":"uint16","name":"metadata","type":"uint16"}],"internalType":"struct JBRulesetMetadata","name":"metadata","type":"tuple"}],"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":"uint256","name":"projectId","type":"uint256"}],"name":"latestQueuedRulesetOf","outputs":[{"components":[{"internalType":"uint48","name":"cycleNumber","type":"uint48"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"basedOnId","type":"uint48"},{"internalType":"uint48","name":"start","type":"uint48"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"weight","type":"uint112"},{"internalType":"uint32","name":"weightCutPercent","type":"uint32"},{"internalType":"contract IJBRulesetApprovalHook","name":"approvalHook","type":"address"},{"internalType":"uint256","name":"metadata","type":"uint256"}],"internalType":"struct JBRuleset","name":"ruleset","type":"tuple"},{"components":[{"internalType":"uint16","name":"reservedPercent","type":"uint16"},{"internalType":"uint16","name":"cashOutTaxRate","type":"uint16"},{"internalType":"uint32","name":"baseCurrency","type":"uint32"},{"internalType":"bool","name":"pausePay","type":"bool"},{"internalType":"bool","name":"pauseCreditTransfers","type":"bool"},{"internalType":"bool","name":"allowOwnerMinting","type":"bool"},{"internalType":"bool","name":"allowSetCustomToken","type":"bool"},{"internalType":"bool","name":"allowTerminalMigration","type":"bool"},{"internalType":"bool","name":"allowSetTerminals","type":"bool"},{"internalType":"bool","name":"allowSetController","type":"bool"},{"internalType":"bool","name":"allowAddAccountingContext","type":"bool"},{"internalType":"bool","name":"allowAddPriceFeed","type":"bool"},{"internalType":"bool","name":"ownerMustSendPayouts","type":"bool"},{"internalType":"bool","name":"holdFees","type":"bool"},{"internalType":"bool","name":"useTotalSurplusForCashOuts","type":"bool"},{"internalType":"bool","name":"useDataHookForPay","type":"bool"},{"internalType":"bool","name":"useDataHookForCashOut","type":"bool"},{"internalType":"address","name":"dataHook","type":"address"},{"internalType":"uint16","name":"metadata","type":"uint16"}],"internalType":"struct JBRulesetMetadata","name":"metadata","type":"tuple"},{"internalType":"enum JBApprovalStatus","name":"approvalStatus","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"projectUri","type":"string"},{"components":[{"internalType":"uint48","name":"mustStartAtOrAfter","type":"uint48"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"weight","type":"uint112"},{"internalType":"uint32","name":"weightCutPercent","type":"uint32"},{"internalType":"contract IJBRulesetApprovalHook","name":"approvalHook","type":"address"},{"components":[{"internalType":"uint16","name":"reservedPercent","type":"uint16"},{"internalType":"uint16","name":"cashOutTaxRate","type":"uint16"},{"internalType":"uint32","name":"baseCurrency","type":"uint32"},{"internalType":"bool","name":"pausePay","type":"bool"},{"internalType":"bool","name":"pauseCreditTransfers","type":"bool"},{"internalType":"bool","name":"allowOwnerMinting","type":"bool"},{"internalType":"bool","name":"allowSetCustomToken","type":"bool"},{"internalType":"bool","name":"allowTerminalMigration","type":"bool"},{"internalType":"bool","name":"allowSetTerminals","type":"bool"},{"internalType":"bool","name":"allowSetController","type":"bool"},{"internalType":"bool","name":"allowAddAccountingContext","type":"bool"},{"internalType":"bool","name":"allowAddPriceFeed","type":"bool"},{"internalType":"bool","name":"ownerMustSendPayouts","type":"bool"},{"internalType":"bool","name":"holdFees","type":"bool"},{"internalType":"bool","name":"useTotalSurplusForCashOuts","type":"bool"},{"internalType":"bool","name":"useDataHookForPay","type":"bool"},{"internalType":"bool","name":"useDataHookForCashOut","type":"bool"},{"internalType":"address","name":"dataHook","type":"address"},{"internalType":"uint16","name":"metadata","type":"uint16"}],"internalType":"struct JBRulesetMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"components":[{"internalType":"uint32","name":"percent","type":"uint32"},{"internalType":"uint64","name":"projectId","type":"uint64"},{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"bool","name":"preferAddToBalance","type":"bool"},{"internalType":"uint48","name":"lockedUntil","type":"uint48"},{"internalType":"contract IJBSplitHook","name":"hook","type":"address"}],"internalType":"struct JBSplit[]","name":"splits","type":"tuple[]"}],"internalType":"struct JBSplitGroup[]","name":"splitGroups","type":"tuple[]"},{"components":[{"internalType":"address","name":"terminal","type":"address"},{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"currency","type":"uint32"}],"internalType":"struct JBCurrencyAmount[]","name":"payoutLimits","type":"tuple[]"},{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"currency","type":"uint32"}],"internalType":"struct JBCurrencyAmount[]","name":"surplusAllowances","type":"tuple[]"}],"internalType":"struct JBFundAccessLimitGroup[]","name":"fundAccessLimitGroups","type":"tuple[]"}],"internalType":"struct JBRulesetConfig[]","name":"rulesetConfigurations","type":"tuple[]"},{"components":[{"internalType":"contract IJBTerminal","name":"terminal","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint32","name":"currency","type":"uint32"}],"internalType":"struct JBAccountingContext[]","name":"accountingContextsToAccept","type":"tuple[]"}],"internalType":"struct JBTerminalConfig[]","name":"terminalConfigurations","type":"tuple[]"},{"internalType":"string","name":"memo","type":"string"}],"name":"launchProjectFor","outputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"components":[{"internalType":"uint48","name":"mustStartAtOrAfter","type":"uint48"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"weight","type":"uint112"},{"internalType":"uint32","name":"weightCutPercent","type":"uint32"},{"internalType":"contract IJBRulesetApprovalHook","name":"approvalHook","type":"address"},{"components":[{"internalType":"uint16","name":"reservedPercent","type":"uint16"},{"internalType":"uint16","name":"cashOutTaxRate","type":"uint16"},{"internalType":"uint32","name":"baseCurrency","type":"uint32"},{"internalType":"bool","name":"pausePay","type":"bool"},{"internalType":"bool","name":"pauseCreditTransfers","type":"bool"},{"internalType":"bool","name":"allowOwnerMinting","type":"bool"},{"internalType":"bool","name":"allowSetCustomToken","type":"bool"},{"internalType":"bool","name":"allowTerminalMigration","type":"bool"},{"internalType":"bool","name":"allowSetTerminals","type":"bool"},{"internalType":"bool","name":"allowSetController","type":"bool"},{"internalType":"bool","name":"allowAddAccountingContext","type":"bool"},{"internalType":"bool","name":"allowAddPriceFeed","type":"bool"},{"internalType":"bool","name":"ownerMustSendPayouts","type":"bool"},{"internalType":"bool","name":"holdFees","type":"bool"},{"internalType":"bool","name":"useTotalSurplusForCashOuts","type":"bool"},{"internalType":"bool","name":"useDataHookForPay","type":"bool"},{"internalType":"bool","name":"useDataHookForCashOut","type":"bool"},{"internalType":"address","name":"dataHook","type":"address"},{"internalType":"uint16","name":"metadata","type":"uint16"}],"internalType":"struct JBRulesetMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"components":[{"internalType":"uint32","name":"percent","type":"uint32"},{"internalType":"uint64","name":"projectId","type":"uint64"},{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"bool","name":"preferAddToBalance","type":"bool"},{"internalType":"uint48","name":"lockedUntil","type":"uint48"},{"internalType":"contract IJBSplitHook","name":"hook","type":"address"}],"internalType":"struct JBSplit[]","name":"splits","type":"tuple[]"}],"internalType":"struct JBSplitGroup[]","name":"splitGroups","type":"tuple[]"},{"components":[{"internalType":"address","name":"terminal","type":"address"},{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"currency","type":"uint32"}],"internalType":"struct JBCurrencyAmount[]","name":"payoutLimits","type":"tuple[]"},{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"currency","type":"uint32"}],"internalType":"struct JBCurrencyAmount[]","name":"surplusAllowances","type":"tuple[]"}],"internalType":"struct JBFundAccessLimitGroup[]","name":"fundAccessLimitGroups","type":"tuple[]"}],"internalType":"struct JBRulesetConfig[]","name":"rulesetConfigurations","type":"tuple[]"},{"components":[{"internalType":"contract IJBTerminal","name":"terminal","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint32","name":"currency","type":"uint32"}],"internalType":"struct JBAccountingContext[]","name":"accountingContextsToAccept","type":"tuple[]"}],"internalType":"struct JBTerminalConfig[]","name":"terminalConfigurations","type":"tuple[]"},{"internalType":"string","name":"memo","type":"string"}],"name":"launchRulesetsFor","outputs":[{"internalType":"uint256","name":"rulesetId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"contract IERC165","name":"to","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"tokenCount","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"string","name":"memo","type":"string"},{"internalType":"bool","name":"useReservedPercent","type":"bool"}],"name":"mintTokensOf","outputs":[{"internalType":"uint256","name":"beneficiaryTokenCount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"pendingReservedTokenBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"components":[{"internalType":"uint48","name":"mustStartAtOrAfter","type":"uint48"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"weight","type":"uint112"},{"internalType":"uint32","name":"weightCutPercent","type":"uint32"},{"internalType":"contract IJBRulesetApprovalHook","name":"approvalHook","type":"address"},{"components":[{"internalType":"uint16","name":"reservedPercent","type":"uint16"},{"internalType":"uint16","name":"cashOutTaxRate","type":"uint16"},{"internalType":"uint32","name":"baseCurrency","type":"uint32"},{"internalType":"bool","name":"pausePay","type":"bool"},{"internalType":"bool","name":"pauseCreditTransfers","type":"bool"},{"internalType":"bool","name":"allowOwnerMinting","type":"bool"},{"internalType":"bool","name":"allowSetCustomToken","type":"bool"},{"internalType":"bool","name":"allowTerminalMigration","type":"bool"},{"internalType":"bool","name":"allowSetTerminals","type":"bool"},{"internalType":"bool","name":"allowSetController","type":"bool"},{"internalType":"bool","name":"allowAddAccountingContext","type":"bool"},{"internalType":"bool","name":"allowAddPriceFeed","type":"bool"},{"internalType":"bool","name":"ownerMustSendPayouts","type":"bool"},{"internalType":"bool","name":"holdFees","type":"bool"},{"internalType":"bool","name":"useTotalSurplusForCashOuts","type":"bool"},{"internalType":"bool","name":"useDataHookForPay","type":"bool"},{"internalType":"bool","name":"useDataHookForCashOut","type":"bool"},{"internalType":"address","name":"dataHook","type":"address"},{"internalType":"uint16","name":"metadata","type":"uint16"}],"internalType":"struct JBRulesetMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"components":[{"internalType":"uint32","name":"percent","type":"uint32"},{"internalType":"uint64","name":"projectId","type":"uint64"},{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"bool","name":"preferAddToBalance","type":"bool"},{"internalType":"uint48","name":"lockedUntil","type":"uint48"},{"internalType":"contract IJBSplitHook","name":"hook","type":"address"}],"internalType":"struct JBSplit[]","name":"splits","type":"tuple[]"}],"internalType":"struct JBSplitGroup[]","name":"splitGroups","type":"tuple[]"},{"components":[{"internalType":"address","name":"terminal","type":"address"},{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"currency","type":"uint32"}],"internalType":"struct JBCurrencyAmount[]","name":"payoutLimits","type":"tuple[]"},{"components":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"currency","type":"uint32"}],"internalType":"struct JBCurrencyAmount[]","name":"surplusAllowances","type":"tuple[]"}],"internalType":"struct JBFundAccessLimitGroup[]","name":"fundAccessLimitGroups","type":"tuple[]"}],"internalType":"struct JBRulesetConfig[]","name":"rulesetConfigurations","type":"tuple[]"},{"internalType":"string","name":"memo","type":"string"}],"name":"queueRulesetsOf","outputs":[{"internalType":"uint256","name":"rulesetId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"sendReservedTokensToSplitsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"setControllerAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"rulesetId","type":"uint256"},{"components":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"components":[{"internalType":"uint32","name":"percent","type":"uint32"},{"internalType":"uint64","name":"projectId","type":"uint64"},{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"bool","name":"preferAddToBalance","type":"bool"},{"internalType":"uint48","name":"lockedUntil","type":"uint48"},{"internalType":"contract IJBSplitHook","name":"hook","type":"address"}],"internalType":"struct JBSplit[]","name":"splits","type":"tuple[]"}],"internalType":"struct JBSplitGroup[]","name":"splitGroups","type":"tuple[]"}],"name":"setSplitGroupsOf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"setTerminalsAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"contract IJBToken","name":"token","type":"address"}],"name":"setTokenFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"string","name":"uri","type":"string"}],"name":"setUriOf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"totalTokenSupplyWithReservedTokensOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"creditCount","type":"uint256"}],"name":"transferCreditsFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"upcomingRulesetOf","outputs":[{"components":[{"internalType":"uint48","name":"cycleNumber","type":"uint48"},{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"basedOnId","type":"uint48"},{"internalType":"uint48","name":"start","type":"uint48"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"weight","type":"uint112"},{"internalType":"uint32","name":"weightCutPercent","type":"uint32"},{"internalType":"contract IJBRulesetApprovalHook","name":"approvalHook","type":"address"},{"internalType":"uint256","name":"metadata","type":"uint256"}],"internalType":"struct JBRuleset","name":"ruleset","type":"tuple"},{"components":[{"internalType":"uint16","name":"reservedPercent","type":"uint16"},{"internalType":"uint16","name":"cashOutTaxRate","type":"uint16"},{"internalType":"uint32","name":"baseCurrency","type":"uint32"},{"internalType":"bool","name":"pausePay","type":"bool"},{"internalType":"bool","name":"pauseCreditTransfers","type":"bool"},{"internalType":"bool","name":"allowOwnerMinting","type":"bool"},{"internalType":"bool","name":"allowSetCustomToken","type":"bool"},{"internalType":"bool","name":"allowTerminalMigration","type":"bool"},{"internalType":"bool","name":"allowSetTerminals","type":"bool"},{"internalType":"bool","name":"allowSetController","type":"bool"},{"internalType":"bool","name":"allowAddAccountingContext","type":"bool"},{"internalType":"bool","name":"allowAddPriceFeed","type":"bool"},{"internalType":"bool","name":"ownerMustSendPayouts","type":"bool"},{"internalType":"bool","name":"holdFees","type":"bool"},{"internalType":"bool","name":"useTotalSurplusForCashOuts","type":"bool"},{"internalType":"bool","name":"useDataHookForPay","type":"bool"},{"internalType":"bool","name":"useDataHookForCashOut","type":"bool"},{"internalType":"address","name":"dataHook","type":"address"},{"internalType":"uint16","name":"metadata","type":"uint16"}],"internalType":"struct JBRulesetMetadata","name":"metadata","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"uriOf","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

6101a06040523480156200001257600080fd5b5060405162005c2e38038062005c2e833981016040819052620000359162000092565b6001600160a01b03968716608052861660a05296851660c05294841660e0529183166101005282166101205281166101405290811661016052166101805262000169565b6001600160a01b03811681146200008f57600080fd5b50565b60008060008060008060008060006101208a8c031215620000b257600080fd5b8951620000bf8162000079565b60208b0151909950620000d28162000079565b60408b0151909850620000e58162000079565b60608b0151909750620000f88162000079565b60808b01519096506200010b8162000079565b60a08b01519095506200011e8162000079565b60c08b0151909450620001318162000079565b60e08b0151909350620001448162000079565b6101008b0151909250620001588162000079565b809150509295985092959850929598565b60805160a05160c05160e0516101005161012051610140516101605161018051615919620003156000396000818161027a0152818161095701528181610ee201528181611064015281816116a70152818161180e01528181611b0f01528181611ec50152818161213501528181613245015261339b0152600081816102e0015281816115aa0152818161284d0152612e5d0152600081816105a30152818161072701528181610c32015281816112c90152818161187f015281816125e30152818161272c0152612bc3015260008181610328015281816107c9015281816109f601528181610b0901528181610b9e01528181610f840152818161111301528181611421015281816115180152818161195e01528181611dcb015261209f0152600081816102b901526108b201526000818161062a01526128d40152600081816104b501528181610ce001528181610db801528181610dfa015281816111c101528181611c2e01528181611c8401528181612ac101528181612b21015261306f0152600081816104010152818161048c01526135840152600081816105f0015261251901526159196000f3fe608060405234801561001057600080fd5b50600436106102275760003560e01c80636567b40611610130578063b1e6d2a1116100b8578063f0118e181161007c578063f0118e18146105c5578063f12b64a5146105d8578063f434c914146105eb578063fb61b4e314610612578063ffa082441461062557600080fd5b8063b1e6d2a114610543578063c02c63ad14610556578063c1ec61ee14610569578063c7fb92de1461058b578063d4a1b4b11461059e57600080fd5b80638a36dffd116100ff5780638a36dffd146104d757806399d25a34146104ea578063a2d532e6146104fd578063a312889b14610510578063b1a50e331461053057600080fd5b80636567b40614610457578063702a3977146104775780637da0a8771461048a57806388bc2ef3146104b057600080fd5b80633141db70116101b3578063419296261161018257806341929626146103cb5780634da781a9146103de578063572b6c05146103f157806358178191146104315780635c7465e51461044457600080fd5b80633141db701461037257806339284f35146103855780633997557114610398578063405b84fa146103b857600080fd5b80631f47ce69116101fa5780631f47ce69146102db57806325a61d5c14610302578063293c4999146103235780632fa902031461034a578063303f5dfa1461035f57600080fd5b806301ffc9a71461022c578063090db2f1146102545780631d831d5c146102755780631eabcd34146102b4575b600080fd5b61023f61023a3660046137e7565b61064c565b60405190151581526020015b60405180910390f35b610267610262366004613811565b6106ef565b60405190815260200161024b565b61029c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161024b565b61029c7f000000000000000000000000000000000000000000000000000000000000000081565b61029c7f000000000000000000000000000000000000000000000000000000000000000081565b61031561031036600461382a565b6106fa565b60405161024b929190613a36565b61029c7f000000000000000000000000000000000000000000000000000000000000000081565b61035d610358366004613a6b565b6107af565b005b61035d61036d366004613abc565b610916565b610267610380366004613b87565b6109ba565b610267610393366004613c00565b610acd565b6102676103a6366004613811565b60006020819052908152604090205481565b61035d6103c6366004613ca3565b610dad565b6103156103d9366004613811565b610e92565b6102676103ec366004613811565b610ebd565b61023f6103ff366004613cd3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61029c61043f366004613cf0565b610f5f565b610267610452366004613d71565b6110f1565b61046a610465366004613e49565b611297565b60405161024b9190613e75565b61035d610485366004613ed8565b611407565b7f000000000000000000000000000000000000000000000000000000000000000061029c565b61029c7f000000000000000000000000000000000000000000000000000000000000000081565b61035d6104e5366004613f23565b6114fe565b61023f6104f8366004613811565b6115e5565b61035d61050b366004613f75565b611603565b61052361051e366004613811565b6116e0565b60405161024b919061401d565b61023f61053e366004613811565b61177a565b61035d610551366004614030565b611793565b610315610564366004613811565b61183d565b61057c610577366004613811565b611856565b60405161024b93929190614078565b6102676105993660046140db565b61190a565b61029c7f000000000000000000000000000000000000000000000000000000000000000081565b61035d6105d3366004614156565b611c20565b61035d6105e6366004613ca3565b611db1565b61029c7f000000000000000000000000000000000000000000000000000000000000000081565b61035d610620366004614182565b611f26565b61029c7f000000000000000000000000000000000000000000000000000000000000000081565b60006001600160e01b03198216635709f28160e01b148061067d57506001600160e01b031982166334ce2c7b60e21b145b8061069857506001600160e01b03198216632877540760e01b145b806106b357506001600160e01b03198216635825057160e11b145b806106ce57506001600160e01b03198216633d0d324560e21b145b806106e957506001600160e01b031982166301ffc9a760e01b145b92915050565b60006106e982612040565b6107026136da565b61070a613726565b604051630969875760e21b815260048101859052602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906325a61d5c9060440161012060405180830381865afa158015610777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079b9190614452565b91506107a682612273565b90509250929050565b6040516331a9108f60e11b815260048101859052610844907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610818573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083c919061446f565b8560126124ad565b600061084f856125c5565b610100810151909150604c1c60019081161461087e576040516383d788ab60e01b815260040160405180910390fd5b60405163c6081d7160e01b81526004810186905260248101859052604481018490526001600160a01b0383811660648301527f0000000000000000000000000000000000000000000000000000000000000000169063c6081d71906084015b600060405180830381600087803b1580156108f757600080fd5b505af115801561090b573d6000803e3d6000fd5b505050505050505050565b6109228484600b6124ad565b60405163181faefd60e11b81526001600160a01b038581166004830152602482018590526044820184905282811660648301527f0000000000000000000000000000000000000000000000000000000000000000169063303f5dfa906084015b600060405180830381600087803b15801561099c57600080fd5b505af11580156109b0573d6000803e3d6000fd5b5050505050505050565b60008381036109dc57604051632b72d06560e01b815260040160405180910390fd5b6040516331a9108f60e11b815260048101879052610a71907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a69919061446f565b8760026124ad565b610a7c868686612658565b90507f24d02d612b06648bfa2000859f3de7e6f336139eaf5877c24b0d21320625286281878585610aab612972565b604051610abc9594939291906144b5565b60405180910390a195945050505050565b6000858103610aef57604051632b72d06560e01b815260040160405180910390fd5b6040516331a9108f60e11b815260048101899052610b84907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7c919061446f565b8960026124ad565b6040516331a9108f60e11b815260048101899052610c19907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c11919061446f565b89600e6124ad565b6040516319fade8560e11b8152600481018990526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906333f5bd0a90602401602060405180830381865afa158015610c81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca591906144ef565b1115610cc4576040516319d957db60e01b815260040160405180910390fd5b6040516338a73f9960e11b8152600481018990523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063714e7f3290604401600060405180830381600087803b158015610d2c57600080fd5b505af1158015610d40573d6000803e3d6000fd5b50505050610d4f888686612981565b610d5a888888612658565b90507f23164adda696b19106c2eef50ba44461997682bf5aeb9fdb383117fa9952cc7581898585610d89612972565b604051610d9a9594939291906144b5565b60405180910390a1979650505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e2c57604051639653dbed60e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b604080516001600160a01b038316815233602082015283917f01f954abace731a88ab86e71186040cc2be49fe517ea06bc0d24f25b82b83456910160405180910390a260008281526020819052604090205415610e8e57610e8c82612040565b505b5050565b610e9a6136da565b610ea2613726565b610eab836125c5565b9150610eb682612273565b9050915091565b6000818152602081905260408082205490516375b0d9cd60e01b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906375b0d9cd90602401602060405180830381865afa158015610f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5591906144ef565b6106e9919061451e565b6040516331a9108f60e11b815260048101879052600090610ff7906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015610fcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fef919061446f565b8860076124ad565b811561104d57611005612972565b8260405160200161103492919060609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6040516020818303038152906040528051906020012091505b604051635817819160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906358178191906110a3908a908a908a908a908a908a90600401614531565b6020604051808303816000875af11580156110c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e6919061446f565b979650505050505050565b60405163180e2b1160e31b81526001600160a01b038a811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063c0715888906024016020604051808303816000875af115801561115e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118291906144ef565b905087156111a55760008181526001602052604090206111a3898b836145fc565b505b6040516338a73f9960e11b8152600481018290523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063714e7f3290604401600060405180830381600087803b15801561120d57600080fd5b505af1158015611221573d6000803e3d6000fd5b50505050611230818686612981565b600061123d828989612658565b90507f8dac501f24f52bda9ebdfa6a1789878c1d1e23823c771f7d52b5ba41261b0f4581838c8c888861126e612972565b60405161128197969594939291906146bc565b60405180910390a1509998505050505050505050565b6040516301fd03bb60e71b81526004810184905260248101839052604481018290526060906000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fe81dd8090606401600060405180830381865afa158015611310573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611338919081019061472f565b8051909150806001600160401b03811115611355576113556141fd565b60405190808252806020026020018201604052801561138e57816020015b61137b6137c2565b8152602001906001900390816113735790505b50925060005b818110156113fd5760008382815181106113b0576113b06147d4565b6020026020010151905060405180604001604052808281526020016113d483612273565b8152508583815181106113e9576113e96147d4565b602090810291909101015250600101611394565b5050509392505050565b6040516331a9108f60e11b81526004810184905261149c907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611470573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611494919061446f565b8460066124ad565b60008381526001602052604090206114b58284836145fc565b50827f0f3d240fe5efaeda774d27bf0425f932ddd2098297b26de8070d6c8bef534b1683836114e2612972565b6040516114f1939291906147ea565b60405180910390a2505050565b6040516331a9108f60e11b815260048101859052611593907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158b919061446f565b8560116124ad565b604051638a36dffd60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638a36dffd90610982908790879087908790600401614841565b60006115f86115f3836125c5565b612273565b610120015192915050565b6116208585600a61161b82611616612972565b612af8565b612b95565b82600003611641576040516346545c9960e11b815260040160405180910390fd5b83856001600160a01b03167fdf04e13ee4fcd48a81ab2fd114757093740a3efa9b6475d86e05878b4c59d079858585611678612972565b60405161168894939291906149c5565b60405180910390a360405163124d91e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063124d91e5906108dd908890889088906004016149f8565b600160205260009081526040902080546116f990614572565b80601f016020809104026020016040519081016040528092919081815260200182805461172590614572565b80156117725780601f1061174757610100808354040283529160200191611772565b820191906000526020600020905b81548152906001019060200180831161175557829003601f168201915b505050505081565b60006117886115f3836125c5565b610100015192915050565b61179f8484600c6124ad565b60006117aa846125c5565b61010081015190915060451c6001908116036117d957604051636af4c57760e01b815260040160405180910390fd5b60405163b1e6d2a160e01b81526001600160a01b038681166004830152602482018690528481166044830152606482018490527f0000000000000000000000000000000000000000000000000000000000000000169063b1e6d2a1906084016108dd565b6118456136da565b61184d613726565b610eab83612ba5565b61185e6136da565b611866613726565b60405163855a54ed60e01b8152600481018490526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063855a54ed9060240161014060405180830381865afa1580156118cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f39190614a19565b909350905061190183612273565b91509193909250565b60008560000361192d5760405163064fae8d60e41b815260040160405180910390fd5b600080611939896125c5565b6040516331a9108f60e11b8152600481018b9052909150611a1b906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa1580156119a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c9919061446f565b8a60096119d882611616612972565b80611a03575061010085015160521c6001600160a01b03166119f8612972565b6001600160a01b0316145b8061161b575061161b8d86611a16612972565b612bfa565b602081015165ffffffffffff1615801590611a42575061010081015160461c600190811614155b8015611a575750611a5589611616612972565b155b8015611a84575061010081015160521c6001600160a01b0316611a78612972565b6001600160a01b031614155b8015611a9a5750611a988982611a16612972565b155b15611ab857604051632475c19d60e21b815260040160405180910390fd5b83611ac4576000611ace565b61010081015160041c5b61ffff1691506127108214611b8d57611af588611aed84612710614a4c565b612710612ca2565b60405163aab68bdb60e01b81529093506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063aab68bdb90611b48908a908d9088906004016149f8565b6020604051808303816000875af1158015611b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8b919061446f565b505b88876001600160a01b03167fe6fee9c572244c0c2238c3112ac12d411750a7ee00eeebd32521c3e5a666c14b8a868a8a88611bc6612972565b604051611bd896959493929190614a5f565b60405180910390a38115611c1457611bf08389614a4c565b60008a81526020819052604081208054909190611c0e90849061451e565b90915550505b50509695505050505050565b6000611c2a612972565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614611cb157604051639653dbed60e01b81526001600160a01b0380831660048301527f0000000000000000000000000000000000000000000000000000000000000000166024820152604401610e23565b6040516301ffc9a760e01b81526334ce2c7b60e21b60048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa158015611cfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d209190614aa2565b15610e8c5760405163a312889b60e01b8152600481018390526001600160a01b0384169063a312889b90602401600060405180830381865afa158015611d6a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d929190810190614abf565b600083815260016020526040902090611dab9082614b52565b50505050565b6040516331a9108f60e11b815260048101839052611e46907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3e919061446f565b8360086124ad565b6000611e51836125c5565b9050806020015165ffffffffffff16600003611e7357611e7083612ba5565b90505b61010081015160471c600190811614611e9f57604051631b6846ab60e01b815260040160405180910390fd5b60405163f12b64a560e01b8152600481018490526001600160a01b0383811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063f12b64a590604401600060405180830381600087803b158015611f0957600080fd5b505af1158015611f1d573d6000803e3d6000fd5b50505050505050565b333014611f3257600080fd5b611f466001600160a01b0386168886612d76565b60405163fef4325760e01b81526001600160a01b0388169063fef4325790611f7f9089908990899089906000908a908a90600401614c11565b6020604051808303816000875af1158015611f9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc291906144ef565b50604051636eb1769f60e11b81523060048201526001600160a01b03888116602483015286169063dd62ed3e90604401602060405180830381865afa15801561200f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203391906144ef565b15611f1d57611f1d614c6c565b60008181526020819052604081205490819003612070576040516364d7bdaf60e01b815260040160405180910390fd5b600061207b836125c5565b6040516331a9108f60e11b8152600481018590529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa1580156120e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210a919061446f565b6000858152602081905260408082208290555163aab68bdb60e01b8152919250906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063aab68bdb9061216e903090899089906004016149f8565b6020604051808303816000875af115801561218d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b1919061446f565b9050600084156121da576121d586856020015165ffffffffffff1660018886612e34565b6121dd565b60005b905080156121f1576121f186828585613340565b85846000015165ffffffffffff16856020015165ffffffffffff167f32411cac611c47cfe73afc187645c9cf3aec828d5f91780138d8421378fc0edb868986612238612972565b604080516001600160a01b0395861681526020810194909452830191909152909116606082015260800160405180910390a450505050919050565b61227b613726565b60405180610260016040528061229684610100015160041c90565b61ffff1681526020016122ae84610100015160141c90565b61ffff1681526020016122c684610100015160241c90565b63ffffffff1681526020016122e8846101000151600160449190911c81161490565b15158152602001612306846101000151600160459190911c81161490565b15158152602001612324846101000151600160469190911c81161490565b15158152602001612342846101000151600160479190911c81161490565b15158152602001612360846101000151600160489190911c81161490565b1515815260200161237e846101000151600160499190911c81161490565b1515815260200161239c8461010001516001604a9190911c81161490565b151581526020016123ba8461010001516001604b9190911c81161490565b151581526020016123d88461010001516001604c9190911c81161490565b151581526020016123f68461010001516001604d9190911c81161490565b151581526020016124148461010001516001604e9190911c81161490565b151581526020016124328461010001516001604f9190911c81161490565b15158152602001612450846101000151600160509190911c81161490565b1515815260200161246e846101000151600160519190911c81161490565b1515815260200161248484610100015160521c90565b6001600160a01b031681526020016124a184610100015160f21c90565b61ffff16905292915050565b60006124b7612972565b9050836001600160a01b0316816001600160a01b0316141580156125865750604051631a45b42760e11b81526001600160a01b0382811660048301528581166024830152604482018590526064820184905260016084830181905260a48301527f0000000000000000000000000000000000000000000000000000000000000000169063348b684e9060c401602060405180830381865afa158015612560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125849190614aa2565b155b15611dab57604051631326f75560e11b81526001600160a01b038086166004830152821660248201526044810184905260648101839052608401610e23565b6125cd6136da565b6040516321d1336160e11b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c2906024015b61012060405180830381865afa158015612634573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e99190614452565b6000805b8281101561296a576000848483818110612678576126786147d4565b905060200281019061268a9190614c82565b6126939061516f565b905061271061ffff168160a001516000015161ffff1611156126dd5760a08101515160405163a162453f60e01b815261ffff90911660048201526127106024820152604401610e23565b61271061ffff168160a001516020015161ffff1611156127285760a0810151602001516040516318e037d360e11b815261ffff90911660048201526127106024820152604401610e23565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370174dcc88846020015185604001518660600151876080015161277b8960a001516133ca565b895160405160e089901b6001600160e01b0319168152600481019790975263ffffffff95861660248801526001600160701b0390941660448701529390911660648501526001600160a01b0316608484015260a483019190915265ffffffffffff1660c482015260e401610120604051808303816000875af1158015612805573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128299190614452565b602081015160c0840151604051638a36dffd60e01b81529293506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692638a36dffd92612882928c926004016152a4565b600060405180830381600087803b15801561289c57600080fd5b505af11580156128b0573d6000803e3d6000fd5b505050602082015160e08401516040516323c620f360e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169350638f1883cc9261290a928c926004016153bd565b600060405180830381600087803b15801561292457600080fd5b505af1158015612938573d6000803e3d6000fd5b5061294a925060019150879050614a4c565b830361296057806020015165ffffffffffff1693505b505060010161265c565b509392505050565b600061297c613574565b905090565b6000816001600160401b0381111561299b5761299b6141fd565b6040519080825280602002602001820160405280156129c4578160200160208202803683370190505b50905060005b82811015612aa35760008484838181106129e6576129e66147d4565b90506020028101906129f8919061546b565b612a0190615481565b805160208201516040516304a6e43960e31b81529293506001600160a01b039091169163253721c891612a39918a919060040161557e565b600060405180830381600087803b158015612a5357600080fd5b505af1158015612a67573d6000803e3d6000fd5b505050508060000151838381518110612a8257612a826147d4565b6001600160a01b0390921660209283029190910190910152506001016129ca565b508115611dab5760405163104373fb60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063821b9fd89061098290879085906004016155f6565b604051636e49181f60e01b8152600481018390526001600160a01b0382811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690636e49181f90604401602060405180830381865afa158015612b6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8e9190614aa2565b9392505050565b80611dab57611dab8484846124ad565b612bad6136da565b604051631735e2c560e11b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e6bc58a90602401612616565b600080612c0c84610100015160521c90565b6001600160a01b031614158015612c9a575061010083015160521c604051630cef9c1160e31b8152600481018690526001600160a01b038481166024830152919091169063677ce08890604401602060405180830381865afa158015612c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9a9190614aa2565b949350505050565b6000808060001985870985870292508281108382030391505080600003612cdc57838281612cd257612cd261564f565b0492505050612b8e565b838110612d0d57604051630c740aef60e31b8152600481018790526024810186905260448101859052606401610e23565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052612dc784826135e9565b611dab576040516001600160a01b03848116602483015260006044830152612e2a91869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613638565b611dab8482613638565b6040516369e11cc560e01b815260048101869052602481018590526044810184905282906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906369e11cc590606401600060405180830381865afa158015612eac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612ed49190810190615665565b805190915060005b81811015613334576000838281518110612ef857612ef86147d4565b602002602001015190506000612f2388836000015163ffffffff16633b9aca0063ffffffff16612ca2565b905080156132e55760a08201516001600160a01b031615612feb57612f4e8b828460a001518a613340565b8160a001516001600160a01b031663c5a093886040518060c001604052808a6001600160a01b03168152602001848152602001601281526020018e81526020018c8152602001858152506040518263ffffffff1660e01b8152600401612fb4919061576a565b600060405180830381600087803b158015612fce57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b505050506132d8565b60408201516000906001600160a01b031661300d57613008612972565b613013565b82604001515b905082602001516001600160401b03166000146132305760006001600160a01b038916156130df576020840151604051630862026560e41b81526001600160401b0390911660048201526001600160a01b038a811660248301527f00000000000000000000000000000000000000000000000000000000000000001690638620265090604401602060405180830381865afa1580156130b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130da919061446f565b6130e2565b60005b90506001600160a01b038916158061310157506001600160a01b038116155b15613117576131128d84848c613340565b61322a565b60008d60405160200161312c91815260200190565b60408051601f1981840301815290829052602087015163fb61b4e360e01b8352909250309163fb61b4e39161316e918691908f908a908a9089906004016157be565b600060405180830381600087803b15801561318857600080fd5b505af1925050508015613199575060015b613228573d8080156131c7576040519150601f19603f3d011682016040523d82523d6000602084013e6131cc565b606091505b508e7fdba24f3504238ca84f6411d16a14bb7ae54061b0a80892bf93eb5a8912ed73558787846131fa612972565b60405161320a9493929190615814565b60405180910390a26132266001600160a01b038c1685876136a9565b505b505b506132d6565b61deac196001600160a01b038216016132ca577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663124d91e5308e856040518463ffffffff1660e01b8152600401613293939291906149f8565b600060405180830381600087803b1580156132ad57600080fd5b505af11580156132c1573d6000803e3d6000fd5b505050506132d6565b6132d68c83838b613340565b505b6132e28187614a4c565b95505b888a8c7fbfcad5a78fa104a30927810dfb51a41d1119d43ce12be27620ab589e1273cebe8585613313612972565b60405161332293929190615856565b60405180910390a45050600101612edc565b50505095945050505050565b6001600160a01b03811615613368576133636001600160a01b03821683856136a9565b611dab565b60405163b1e6d2a160e01b8152306004820152602481018590526001600160a01b038381166044830152606482018590527f0000000000000000000000000000000000000000000000000000000000000000169063b1e6d2a190608401610982565b6000600190506004826000015161ffff16901b811790506014826020015161ffff16901b811790506024826040015163ffffffff16901b8117905081606001511561341b5768100000000000000000175b8160800151156134315768200000000000000000175b8160a00151156134475768400000000000000000175b8160c001511561345d5768800000000000000000175b8160e0015115613474576901000000000000000000175b8161010001511561348c576902000000000000000000175b816101200151156134a4576904000000000000000000175b816101400151156134bc576908000000000000000000175b816101600151156134d4576910000000000000000000175b816101800151156134ec576920000000000000000000175b816101a0015115613504576940000000000000000000175b816101c001511561351c576980000000000000000000175b816101e001511561352e57600160501b175b8161020001511561354057600160511b175b6102208201516102409092015160529290921b600160521b600160f21b03161760f29190911b6001600160f21b0319161790565b6000366014336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480156135b15750808210155b156135e1576000366135c38385614a4c565b6135ce928290615884565b6135d7916158ae565b60601c9250505090565b339250505090565b6000806000806020600086516020880160008a5af192503d9150600051905082801561362e5750811561361f578060011461362e565b6000866001600160a01b03163b115b9695505050505050565b600080602060008451602086016000885af18061365b576040513d6000823e3d81fd5b50506000513d91508115613673578060011415613680565b6001600160a01b0384163b155b15611dab57604051635274afe760e01b81526001600160a01b0385166004820152602401610e23565b6040516001600160a01b03838116602483015260448201839052610e8c91859182169063a9059cbb90606401612df8565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b6040805161026081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e081018290526102008101829052610220810182905261024081019190915290565b60405180604001604052806137d56136da565b81526020016137e2613726565b905290565b6000602082840312156137f957600080fd5b81356001600160e01b031981168114612b8e57600080fd5b60006020828403121561382357600080fd5b5035919050565b6000806040838503121561383d57600080fd5b50508035926020909101359150565b65ffffffffffff80825116835280602083015116602084015280604083015116604084015250606081015161388b606084018265ffffffffffff169052565b5060808101516138a3608084018263ffffffff169052565b5060a08101516138be60a08401826001600160701b03169052565b5060c08101516138d660c084018263ffffffff169052565b5060e08101516138f160e08401826001600160a01b03169052565b5061010090810151910152565b805161ffff168252602081015161391b602084018261ffff169052565b506040810151613933604084018263ffffffff169052565b506060810151613947606084018215159052565b50608081015161395b608084018215159052565b5060a081015161396f60a084018215159052565b5060c081015161398360c084018215159052565b5060e081015161399760e084018215159052565b5061010081810151151590830152610120808201511515908301526101408082015115159083015261016080820151151590830152610180808201511515908301526101a0808201511515908301526101c0808201511515908301526101e08082015115159083015261020080820151151590830152610220808201516001600160a01b0316908301526102408082015161ffff811682850152611dab565b6103808101613a45828561384c565b612b8e6101208301846138fe565b6001600160a01b0381168114613a6857600080fd5b50565b60008060008060808587031215613a8157600080fd5b8435935060208501359250604085013591506060850135613aa181613a53565b939692955090935050565b8035613ab781613a53565b919050565b60008060008060808587031215613ad257600080fd5b8435613add81613a53565b935060208501359250604085013591506060850135613aa181613a53565b60008083601f840112613b0d57600080fd5b5081356001600160401b03811115613b2457600080fd5b6020830191508360208260051b8501011115613b3f57600080fd5b9250929050565b60008083601f840112613b5857600080fd5b5081356001600160401b03811115613b6f57600080fd5b602083019150836020828501011115613b3f57600080fd5b600080600080600060608688031215613b9f57600080fd5b8535945060208601356001600160401b0380821115613bbd57600080fd5b613bc989838a01613afb565b90965094506040880135915080821115613be257600080fd5b50613bef88828901613b46565b969995985093965092949392505050565b60008060008060008060006080888a031215613c1b57600080fd5b8735965060208801356001600160401b0380821115613c3957600080fd5b613c458b838c01613afb565b909850965060408a0135915080821115613c5e57600080fd5b613c6a8b838c01613afb565b909650945060608a0135915080821115613c8357600080fd5b50613c908a828b01613b46565b989b979a50959850939692959293505050565b60008060408385031215613cb657600080fd5b823591506020830135613cc881613a53565b809150509250929050565b600060208284031215613ce557600080fd5b8135612b8e81613a53565b60008060008060008060808789031215613d0957600080fd5b8635955060208701356001600160401b0380821115613d2757600080fd5b613d338a838b01613b46565b90975095506040890135915080821115613d4c57600080fd5b50613d5989828a01613b46565b979a9699509497949695606090950135949350505050565b600080600080600080600080600060a08a8c031215613d8f57600080fd5b8935613d9a81613a53565b985060208a01356001600160401b0380821115613db657600080fd5b613dc28d838e01613b46565b909a50985060408c0135915080821115613ddb57600080fd5b613de78d838e01613afb565b909850965060608c0135915080821115613e0057600080fd5b613e0c8d838e01613afb565b909650945060808c0135915080821115613e2557600080fd5b50613e328c828d01613b46565b915080935050809150509295985092959850929598565b600080600060608486031215613e5e57600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b81811015613ecc578351613ea684825161384c565b850151613eb76101208501826138fe565b50928401926103809290920191600101613e91565b50909695505050505050565b600080600060408486031215613eed57600080fd5b8335925060208401356001600160401b03811115613f0a57600080fd5b613f1686828701613b46565b9497909650939450505050565b60008060008060608587031215613f3957600080fd5b843593506020850135925060408501356001600160401b03811115613f5d57600080fd5b613f6987828801613afb565b95989497509550505050565b600080600080600060808688031215613f8d57600080fd5b8535613f9881613a53565b9450602086013593506040860135925060608601356001600160401b03811115613fc157600080fd5b613bef88828901613b46565b60005b83811015613fe8578181015183820152602001613fd0565b50506000910152565b60008151808452614009816020860160208601613fcd565b601f01601f19169290920160200192915050565b602081526000612b8e6020830184613ff1565b6000806000806080858703121561404657600080fd5b843561405181613a53565b935060208501359250604085013561406881613a53565b9396929550929360600135925050565b6103a08101614087828661384c565b6140956101208301856138fe565b600683106140b357634e487b7160e01b600052602160045260246000fd5b82610380830152949350505050565b8015158114613a6857600080fd5b8035613ab7816140c2565b60008060008060008060a087890312156140f457600080fd5b8635955060208701359450604087013561410d81613a53565b935060608701356001600160401b0381111561412857600080fd5b61413489828a01613b46565b9094509250506080870135614148816140c2565b809150509295509295509295565b6000806040838503121561416957600080fd5b823561417481613a53565b946020939093013593505050565b600080600080600080600060c0888a03121561419d57600080fd5b87356141a881613a53565b96506020880135955060408801356141bf81613a53565b94506060880135935060808801356141d681613a53565b925060a08801356001600160401b038111156141f157600080fd5b613c908a828b01613b46565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614236576142366141fd565b60405290565b60405161026081016001600160401b0381118282101715614236576142366141fd565b604080519081016001600160401b0381118282101715614236576142366141fd565b60405160c081016001600160401b0381118282101715614236576142366141fd565b604051608081016001600160401b0381118282101715614236576142366141fd565b60405161010081016001600160401b0381118282101715614236576142366141fd565b604051606081016001600160401b0381118282101715614236576142366141fd565b604051601f8201601f191681016001600160401b0381118282101715614332576143326141fd565b604052919050565b65ffffffffffff81168114613a6857600080fd5b8051613ab78161433a565b63ffffffff81168114613a6857600080fd5b8051613ab781614359565b6001600160701b0381168114613a6857600080fd5b8051613ab781614376565b8051613ab781613a53565b600061012082840312156143b457600080fd5b6143bc614213565b90506143c78261434e565b81526143d56020830161434e565b60208201526143e66040830161434e565b60408201526143f76060830161434e565b60608201526144086080830161436b565b608082015261441960a0830161438b565b60a082015261442a60c0830161436b565b60c082015261443b60e08301614396565b60e082015261010080830151818301525092915050565b6000610120828403121561446557600080fd5b612b8e83836143a1565b60006020828403121561448157600080fd5b8151612b8e81613a53565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8581528460208201526080604082015260006144d560808301858761448c565b905060018060a01b03831660608301529695505050505050565b60006020828403121561450157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156106e9576106e9614508565b86815260806020820152600061454b60808301878961448c565b828103604084015261455e81868861448c565b915050826060830152979650505050505050565b600181811c9082168061458657607f821691505b6020821081036145a657634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610e8c576000816000526020600020601f850160051c810160208610156145d55750805b601f850160051c820191505b818110156145f4578281556001016145e1565b505050505050565b6001600160401b03831115614613576146136141fd565b614627836146218354614572565b836145ac565b6000601f84116001811461465b57600085156146435750838201355b600019600387901b1c1916600186901b1783556146b5565b600083815260209020601f19861690835b8281101561468c578685013582556020948501946001909201910161466c565b50868210156146a95760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b87815286602082015260a0604082015260006146dc60a08301878961448c565b82810360608401526146ef81868861448c565b91505060018060a01b038316608083015298975050505050505050565b60006001600160401b03821115614725576147256141fd565b5060051b60200190565b6000602080838503121561474257600080fd5b82516001600160401b0381111561475857600080fd5b8301601f8101851361476957600080fd5b805161477c6147778261470c565b61430a565b8082825260208201915061012060208185028601019350888411156147a057600080fd5b6020850194505b838510156147c8576147b989866143a1565b835293840193918501916147a7565b50979650505050505050565b634e487b7160e01b600052603260045260246000fd5b6040815260006147fe60408301858761448c565b905060018060a01b0383166020830152949350505050565b8035613ab781614359565b6001600160401b0381168114613a6857600080fd5b8035613ab78161433a565b6000606080830187845260208781860152604060606040870152828784526080935060808701905060808860051b8801018960005b8a8110156149b357898303607f190184528135368d9003603e1901811261489c57600080fd5b8c01803584528386018782013536839003601e190181126148bc57600080fd5b9091018781019190356001600160401b03808211156148da57600080fd5b60c080830236038513156148ed57600080fd5b878b018a9052928290526000928c88015b8385101561499c57853561491181614359565b63ffffffff168152858c013561492681614821565b8316818d0152858b013561493981613a53565b6001600160a01b0316818c0152858e0135614953816140c2565b1515818f0152614964868e01614836565b65ffffffffffff168d82015260a061497d878201613aac565b6001600160a01b031690820152948101946001949094019381016148fe565b988b01989750505093880193505050600101614876565b50909c9b505050505050505050505050565b8481526060602082015260006149df60608301858761448c565b905060018060a01b038316604083015295945050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b6000806101408385031215614a2d57600080fd5b614a3784846143a1565b915061012083015160068110613cc857600080fd5b818103818111156106e9576106e9614508565b86815285602082015260a060408201526000614a7f60a08301868861448c565b6060830194909452506001600160a01b0391909116608090910152949350505050565b600060208284031215614ab457600080fd5b8151612b8e816140c2565b600060208284031215614ad157600080fd5b81516001600160401b0380821115614ae857600080fd5b818401915084601f830112614afc57600080fd5b815181811115614b0e57614b0e6141fd565b614b21601f8201601f191660200161430a565b9150808252856020828501011115614b3857600080fd5b614b49816020840160208601613fcd565b50949350505050565b81516001600160401b03811115614b6b57614b6b6141fd565b614b7f81614b798454614572565b846145ac565b602080601f831160018114614bb45760008415614b9c5750858301515b600019600386901b1c1916600185901b1785556145f4565b600085815260208120601f198616915b82811015614be357888601518255948401946001909101908401614bc4565b5085821015614c015787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b878152600060018060a01b03808916602084015287604084015280871660608401525084608083015260e060a0830152600060e08301526101008060c0840152614c5e818401858761448c565b9a9950505050505050505050565b634e487b7160e01b600052600160045260246000fd5b6000823561033e19833603018112614c9957600080fd5b9190910192915050565b8035613ab781614376565b803561ffff81168114613ab757600080fd5b60006102608284031215614cd357600080fd5b614cdb61423c565b9050614ce682614cae565b8152614cf460208301614cae565b6020820152614d0560408301614816565b6040820152614d16606083016140d0565b6060820152614d27608083016140d0565b6080820152614d3860a083016140d0565b60a0820152614d4960c083016140d0565b60c0820152614d5a60e083016140d0565b60e0820152610100614d6d8184016140d0565b90820152610120614d7f8382016140d0565b90820152610140614d918382016140d0565b90820152610160614da38382016140d0565b90820152610180614db58382016140d0565b908201526101a0614dc78382016140d0565b908201526101c0614dd98382016140d0565b908201526101e0614deb8382016140d0565b90820152610200614dfd8382016140d0565b90820152610220614e0f838201613aac565b90820152610240614e21838201614cae565b9082015292915050565b600082601f830112614e3c57600080fd5b81356020614e4c6147778361470c565b82815260059290921b84018101918181019086841115614e6b57600080fd5b8286015b84811015614fbf5780356001600160401b0380821115614e8e57600080fd5b908801906040828b03601f1901811315614ea757600080fd5b614eaf61425f565b8784013581528184013583811115614ec657600080fd5b8085019450508b603f850112614edb57600080fd5b878401359250614eed6147778461470c565b83815260c09093028401820192888101908d851115614f0b57600080fd5b948301945b84861015614faa5760c0868f031215614f2857600080fd5b614f30614281565b8635614f3b81614359565b8152868b0135614f4a81614821565b818c015286850135614f5b81613a53565b818601526060870135614f6d816140c2565b60608201526080870135614f808161433a565b608082015260a0870135614f9381613a53565b60a0820152825260c0959095019490890190614f10565b828a0152508652505050918301918301614e6f565b509695505050505050565b600082601f830112614fdb57600080fd5b81356020614feb6147778361470c565b82815260069290921b8401810191818101908684111561500a57600080fd5b8286015b84811015614fbf57604081890312156150275760008081fd5b61502f61425f565b81356001600160e01b03811681146150475760008081fd5b81528185013561505681614359565b8186015283529183019160400161500e565b600082601f83011261507957600080fd5b813560206150896147778361470c565b82815260059290921b840181019181810190868411156150a857600080fd5b8286015b84811015614fbf5780356001600160401b03808211156150cc5760008081fd5b908801906080828b03601f19018113156150e65760008081fd5b6150ee6142a3565b878401356150fb81613a53565b815260408481013561510c81613a53565b828a0152606085810135858111156151245760008081fd5b6151328f8c838a0101614fca565b848401525092850135928484111561514c57600091508182fd5b61515a8e8b86890101614fca565b908301525086525050509183019183016150ac565b6000610340823603121561518257600080fd5b61518a6142c5565b61519383614836565b81526151a160208401614816565b60208201526151b260408401614ca3565b60408201526151c360608401614816565b60608201526151d460808401613aac565b60808201526151e63660a08501614cc0565b60a08201526103008301356001600160401b038082111561520657600080fd5b61521236838701614e2b565b60c084015261032085013591508082111561522c57600080fd5b5061523936828601615068565b60e08301525092915050565b805163ffffffff1682526020808201516001600160401b0316908301526040808201516001600160a01b039081169184019190915260608083015115159084015260808083015165ffffffffffff169084015260a09182015116910152565b60006060808301868452602065ffffffffffff87168186015260406060604087015282875180855260808801915060808160051b89010194508389016000805b83811015615355578a8803607f190185528251805189528701518789018790528051878a018190529088019083908b8b01905b808310156153405761532a828551615245565b60c0820191508a84019350600183019250615317565b509950505093860193918601916001016152e4565b50959c9b505050505050505050505050565b60008151808452602080850194506020840160005b838110156153b257815180516001600160e01b0316885283015163ffffffff16838801526040909601959082019060010161537c565b509495945050505050565b60006060808301868452602065ffffffffffff8716818601526040606060408701528287518085526080945060808801915060808160051b890101848a0160005b838110156149b3578a8303607f19018552815180516001600160a01b039081168552888201511688850152868101518785018a905261543f8a860182615367565b918b0151858303868d01529190506154578183615367565b9689019694505050908601906001016153fe565b60008235603e19833603018112614c9957600080fd5b6000604080833603121561549457600080fd5b61549c61425f565b83356154a781613a53565b81526020848101356001600160401b038111156154c357600080fd5b850136601f8201126154d457600080fd5b80356154e26147778261470c565b8181526060918202830184019184820191903684111561550157600080fd5b938501935b8385101561556b5780853603121561551e5760008081fd5b6155266142e8565b853561553181613a53565b81528587013560ff811681146155475760008081fd5b818801528589013561555881614359565b818a015283529384019391850191615506565b5093850193909352509195945050505050565b60006040808301858452602060406020860152818651808452606093506060870191506020880160005b828110156155e757815180516001600160a01b031685528581015160ff168686015287015163ffffffff168785015292850192908401906001016155a8565b50919998505050505050505050565b60006040820184835260206040602085015281855180845260608601915060208701935060005b818110156156425784516001600160a01b03168352938301939183019160010161561d565b5090979650505050505050565b634e487b7160e01b600052601260045260246000fd5b6000602080838503121561567857600080fd5b82516001600160401b0381111561568e57600080fd5b8301601f8101851361569f57600080fd5b80516156ad6147778261470c565b81815260c091820283018401918482019190888411156156cc57600080fd5b938501935b838510156147c85780858a0312156156e95760008081fd5b6156f1614281565b85516156fc81614359565b81528587015161570b81614821565b8188015260408681015161571e81613a53565b90820152606086810151615731816140c2565b908201526080868101516157448161433a565b9082015260a08681015161575781613a53565b90820152835293840193918501916156d1565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0828101516101608301916157b790840182615245565b5092915050565b6001600160a01b0387811682526001600160401b03871660208301528581166040830152606082018590528316608082015260c060a0820181905260009061580890830184613ff1565b98975050505050505050565b60006101206158238388615245565b8560c08401528060e084015261583b81840186613ff1565b91505060018060a01b03831661010083015295945050505050565b61010081016158658286615245565b60c08201939093526001600160a01b039190911660e090910152919050565b6000808585111561589457600080fd5b838611156158a157600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff1981358181169160148510156158db5780818660140360031b1b83161692505b50509291505056fea2646970667358221220e47a917a722a55d39c230307c4cd275c10049322c40500668f190d35403b7b1f64736f6c634300081700330000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41000000000000000000000000f1e1df5bba779e977a27ccc273847ab1346fceb8000000000000000000000000f5ca295dc286a176e35ebb7833031fd95550eb14000000000000000000000000e712d14b04f1a1fe464be930e3ea72b9b0a141d70000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898260000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf360000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f887

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102275760003560e01c80636567b40611610130578063b1e6d2a1116100b8578063f0118e181161007c578063f0118e18146105c5578063f12b64a5146105d8578063f434c914146105eb578063fb61b4e314610612578063ffa082441461062557600080fd5b8063b1e6d2a114610543578063c02c63ad14610556578063c1ec61ee14610569578063c7fb92de1461058b578063d4a1b4b11461059e57600080fd5b80638a36dffd116100ff5780638a36dffd146104d757806399d25a34146104ea578063a2d532e6146104fd578063a312889b14610510578063b1a50e331461053057600080fd5b80636567b40614610457578063702a3977146104775780637da0a8771461048a57806388bc2ef3146104b057600080fd5b80633141db70116101b3578063419296261161018257806341929626146103cb5780634da781a9146103de578063572b6c05146103f157806358178191146104315780635c7465e51461044457600080fd5b80633141db701461037257806339284f35146103855780633997557114610398578063405b84fa146103b857600080fd5b80631f47ce69116101fa5780631f47ce69146102db57806325a61d5c14610302578063293c4999146103235780632fa902031461034a578063303f5dfa1461035f57600080fd5b806301ffc9a71461022c578063090db2f1146102545780631d831d5c146102755780631eabcd34146102b4575b600080fd5b61023f61023a3660046137e7565b61064c565b60405190151581526020015b60405180910390f35b610267610262366004613811565b6106ef565b60405190815260200161024b565b61029c7f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf3681565b6040516001600160a01b03909116815260200161024b565b61029c7f000000000000000000000000e712d14b04f1a1fe464be930e3ea72b9b0a141d781565b61029c7f0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c81565b61031561031036600461382a565b6106fa565b60405161024b929190613a36565b61029c7f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad81565b61035d610358366004613a6b565b6107af565b005b61035d61036d366004613abc565b610916565b610267610380366004613b87565b6109ba565b610267610393366004613c00565b610acd565b6102676103a6366004613811565b60006020819052908152604090205481565b61035d6103c6366004613ca3565b610dad565b6103156103d9366004613811565b610e92565b6102676103ec366004613811565b610ebd565b61023f6103ff366004613cd3565b7f0000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f8876001600160a01b0390811691161490565b61029c61043f366004613cf0565b610f5f565b610267610452366004613d71565b6110f1565b61046a610465366004613e49565b611297565b60405161024b9190613e75565b61035d610485366004613ed8565b611407565b7f0000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f88761029c565b61029c7f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa4181565b61035d6104e5366004613f23565b6114fe565b61023f6104f8366004613811565b6115e5565b61035d61050b366004613f75565b611603565b61052361051e366004613811565b6116e0565b60405161024b919061401d565b61023f61053e366004613811565b61177a565b61035d610551366004614030565b611793565b610315610564366004613811565b61183d565b61057c610577366004613811565b611856565b60405161024b93929190614078565b6102676105993660046140db565b61190a565b61029c7f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c8982681565b61035d6105d3366004614156565b611c20565b61035d6105e6366004613ca3565b611db1565b61029c7f000000000000000000000000f5ca295dc286a176e35ebb7833031fd95550eb1481565b61035d610620366004614182565b611f26565b61029c7f000000000000000000000000f1e1df5bba779e977a27ccc273847ab1346fceb881565b60006001600160e01b03198216635709f28160e01b148061067d57506001600160e01b031982166334ce2c7b60e21b145b8061069857506001600160e01b03198216632877540760e01b145b806106b357506001600160e01b03198216635825057160e11b145b806106ce57506001600160e01b03198216633d0d324560e21b145b806106e957506001600160e01b031982166301ffc9a760e01b145b92915050565b60006106e982612040565b6107026136da565b61070a613726565b604051630969875760e21b815260048101859052602481018490527f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b0316906325a61d5c9060440161012060405180830381865afa158015610777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079b9190614452565b91506107a682612273565b90509250929050565b6040516331a9108f60e11b815260048101859052610844907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015610818573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083c919061446f565b8560126124ad565b600061084f856125c5565b610100810151909150604c1c60019081161461087e576040516383d788ab60e01b815260040160405180910390fd5b60405163c6081d7160e01b81526004810186905260248101859052604481018490526001600160a01b0383811660648301527f000000000000000000000000e712d14b04f1a1fe464be930e3ea72b9b0a141d7169063c6081d71906084015b600060405180830381600087803b1580156108f757600080fd5b505af115801561090b573d6000803e3d6000fd5b505050505050505050565b6109228484600b6124ad565b60405163181faefd60e11b81526001600160a01b038581166004830152602482018590526044820184905282811660648301527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063303f5dfa906084015b600060405180830381600087803b15801561099c57600080fd5b505af11580156109b0573d6000803e3d6000fd5b5050505050505050565b60008381036109dc57604051632b72d06560e01b815260040160405180910390fd5b6040516331a9108f60e11b815260048101879052610a71907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015610a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a69919061446f565b8760026124ad565b610a7c868686612658565b90507f24d02d612b06648bfa2000859f3de7e6f336139eaf5877c24b0d21320625286281878585610aab612972565b604051610abc9594939291906144b5565b60405180910390a195945050505050565b6000858103610aef57604051632b72d06560e01b815260040160405180910390fd5b6040516331a9108f60e11b815260048101899052610b84907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015610b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7c919061446f565b8960026124ad565b6040516331a9108f60e11b815260048101899052610c19907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015610bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c11919061446f565b89600e6124ad565b6040516319fade8560e11b8152600481018990526000907f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b0316906333f5bd0a90602401602060405180830381865afa158015610c81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca591906144ef565b1115610cc4576040516319d957db60e01b815260040160405180910390fd5b6040516338a73f9960e11b8152600481018990523060248201527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa416001600160a01b03169063714e7f3290604401600060405180830381600087803b158015610d2c57600080fd5b505af1158015610d40573d6000803e3d6000fd5b50505050610d4f888686612981565b610d5a888888612658565b90507f23164adda696b19106c2eef50ba44461997682bf5aeb9fdb383117fa9952cc7581898585610d89612972565b604051610d9a9594939291906144b5565b60405180910390a1979650505050505050565b336001600160a01b037f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa411614610e2c57604051639653dbed60e01b81523360048201526001600160a01b037f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa411660248201526044015b60405180910390fd5b604080516001600160a01b038316815233602082015283917f01f954abace731a88ab86e71186040cc2be49fe517ea06bc0d24f25b82b83456910160405180910390a260008281526020819052604090205415610e8e57610e8c82612040565b505b5050565b610e9a6136da565b610ea2613726565b610eab836125c5565b9150610eb682612273565b9050915091565b6000818152602081905260408082205490516375b0d9cd60e01b8152600481018490527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf366001600160a01b0316906375b0d9cd90602401602060405180830381865afa158015610f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5591906144ef565b6106e9919061451e565b6040516331a9108f60e11b815260048101879052600090610ff7906001600160a01b037f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad1690636352211e90602401602060405180830381865afa158015610fcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fef919061446f565b8860076124ad565b811561104d57611005612972565b8260405160200161103492919060609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6040516020818303038152906040528051906020012091505b604051635817819160e01b81526001600160a01b037f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf3616906358178191906110a3908a908a908a908a908a908a90600401614531565b6020604051808303816000875af11580156110c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e6919061446f565b979650505050505050565b60405163180e2b1160e31b81526001600160a01b038a811660048301526000917f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad9091169063c0715888906024016020604051808303816000875af115801561115e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118291906144ef565b905087156111a55760008181526001602052604090206111a3898b836145fc565b505b6040516338a73f9960e11b8152600481018290523060248201527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa416001600160a01b03169063714e7f3290604401600060405180830381600087803b15801561120d57600080fd5b505af1158015611221573d6000803e3d6000fd5b50505050611230818686612981565b600061123d828989612658565b90507f8dac501f24f52bda9ebdfa6a1789878c1d1e23823c771f7d52b5ba41261b0f4581838c8c888861126e612972565b60405161128197969594939291906146bc565b60405180910390a1509998505050505050505050565b6040516301fd03bb60e71b81526004810184905260248101839052604481018290526060906000906001600160a01b037f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c89826169063fe81dd8090606401600060405180830381865afa158015611310573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611338919081019061472f565b8051909150806001600160401b03811115611355576113556141fd565b60405190808252806020026020018201604052801561138e57816020015b61137b6137c2565b8152602001906001900390816113735790505b50925060005b818110156113fd5760008382815181106113b0576113b06147d4565b6020026020010151905060405180604001604052808281526020016113d483612273565b8152508583815181106113e9576113e96147d4565b602090810291909101015250600101611394565b5050509392505050565b6040516331a9108f60e11b81526004810184905261149c907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015611470573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611494919061446f565b8460066124ad565b60008381526001602052604090206114b58284836145fc565b50827f0f3d240fe5efaeda774d27bf0425f932ddd2098297b26de8070d6c8bef534b1683836114e2612972565b6040516114f1939291906147ea565b60405180910390a2505050565b6040516331a9108f60e11b815260048101859052611593907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015611567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158b919061446f565b8560116124ad565b604051638a36dffd60e01b81526001600160a01b037f0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c1690638a36dffd90610982908790879087908790600401614841565b60006115f86115f3836125c5565b612273565b610120015192915050565b6116208585600a61161b82611616612972565b612af8565b612b95565b82600003611641576040516346545c9960e11b815260040160405180910390fd5b83856001600160a01b03167fdf04e13ee4fcd48a81ab2fd114757093740a3efa9b6475d86e05878b4c59d079858585611678612972565b60405161168894939291906149c5565b60405180910390a360405163124d91e560e01b81526001600160a01b037f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063124d91e5906108dd908890889088906004016149f8565b600160205260009081526040902080546116f990614572565b80601f016020809104026020016040519081016040528092919081815260200182805461172590614572565b80156117725780601f1061174757610100808354040283529160200191611772565b820191906000526020600020905b81548152906001019060200180831161175557829003601f168201915b505050505081565b60006117886115f3836125c5565b610100015192915050565b61179f8484600c6124ad565b60006117aa846125c5565b61010081015190915060451c6001908116036117d957604051636af4c57760e01b815260040160405180910390fd5b60405163b1e6d2a160e01b81526001600160a01b038681166004830152602482018690528481166044830152606482018490527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063b1e6d2a1906084016108dd565b6118456136da565b61184d613726565b610eab83612ba5565b61185e6136da565b611866613726565b60405163855a54ed60e01b8152600481018490526000907f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b03169063855a54ed9060240161014060405180830381865afa1580156118cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f39190614a19565b909350905061190183612273565b91509193909250565b60008560000361192d5760405163064fae8d60e41b815260040160405180910390fd5b600080611939896125c5565b6040516331a9108f60e11b8152600481018b9052909150611a1b906001600160a01b037f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad1690636352211e90602401602060405180830381865afa1580156119a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c9919061446f565b8a60096119d882611616612972565b80611a03575061010085015160521c6001600160a01b03166119f8612972565b6001600160a01b0316145b8061161b575061161b8d86611a16612972565b612bfa565b602081015165ffffffffffff1615801590611a42575061010081015160461c600190811614155b8015611a575750611a5589611616612972565b155b8015611a84575061010081015160521c6001600160a01b0316611a78612972565b6001600160a01b031614155b8015611a9a5750611a988982611a16612972565b155b15611ab857604051632475c19d60e21b815260040160405180910390fd5b83611ac4576000611ace565b61010081015160041c5b61ffff1691506127108214611b8d57611af588611aed84612710614a4c565b612710612ca2565b60405163aab68bdb60e01b81529093506001600160a01b037f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063aab68bdb90611b48908a908d9088906004016149f8565b6020604051808303816000875af1158015611b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8b919061446f565b505b88876001600160a01b03167fe6fee9c572244c0c2238c3112ac12d411750a7ee00eeebd32521c3e5a666c14b8a868a8a88611bc6612972565b604051611bd896959493929190614a5f565b60405180910390a38115611c1457611bf08389614a4c565b60008a81526020819052604081208054909190611c0e90849061451e565b90915550505b50509695505050505050565b6000611c2a612972565b90507f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa416001600160a01b0316816001600160a01b031614611cb157604051639653dbed60e01b81526001600160a01b0380831660048301527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41166024820152604401610e23565b6040516301ffc9a760e01b81526334ce2c7b60e21b60048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa158015611cfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d209190614aa2565b15610e8c5760405163a312889b60e01b8152600481018390526001600160a01b0384169063a312889b90602401600060405180830381865afa158015611d6a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d929190810190614abf565b600083815260016020526040902090611dab9082614b52565b50505050565b6040516331a9108f60e11b815260048101839052611e46907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015611e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3e919061446f565b8360086124ad565b6000611e51836125c5565b9050806020015165ffffffffffff16600003611e7357611e7083612ba5565b90505b61010081015160471c600190811614611e9f57604051631b6846ab60e01b815260040160405180910390fd5b60405163f12b64a560e01b8152600481018490526001600160a01b0383811660248301527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063f12b64a590604401600060405180830381600087803b158015611f0957600080fd5b505af1158015611f1d573d6000803e3d6000fd5b50505050505050565b333014611f3257600080fd5b611f466001600160a01b0386168886612d76565b60405163fef4325760e01b81526001600160a01b0388169063fef4325790611f7f9089908990899089906000908a908a90600401614c11565b6020604051808303816000875af1158015611f9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc291906144ef565b50604051636eb1769f60e11b81523060048201526001600160a01b03888116602483015286169063dd62ed3e90604401602060405180830381865afa15801561200f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203391906144ef565b15611f1d57611f1d614c6c565b60008181526020819052604081205490819003612070576040516364d7bdaf60e01b815260040160405180910390fd5b600061207b836125c5565b6040516331a9108f60e11b8152600481018590529091506000906001600160a01b037f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad1690636352211e90602401602060405180830381865afa1580156120e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210a919061446f565b6000858152602081905260408082208290555163aab68bdb60e01b8152919250906001600160a01b037f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063aab68bdb9061216e903090899089906004016149f8565b6020604051808303816000875af115801561218d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b1919061446f565b9050600084156121da576121d586856020015165ffffffffffff1660018886612e34565b6121dd565b60005b905080156121f1576121f186828585613340565b85846000015165ffffffffffff16856020015165ffffffffffff167f32411cac611c47cfe73afc187645c9cf3aec828d5f91780138d8421378fc0edb868986612238612972565b604080516001600160a01b0395861681526020810194909452830191909152909116606082015260800160405180910390a450505050919050565b61227b613726565b60405180610260016040528061229684610100015160041c90565b61ffff1681526020016122ae84610100015160141c90565b61ffff1681526020016122c684610100015160241c90565b63ffffffff1681526020016122e8846101000151600160449190911c81161490565b15158152602001612306846101000151600160459190911c81161490565b15158152602001612324846101000151600160469190911c81161490565b15158152602001612342846101000151600160479190911c81161490565b15158152602001612360846101000151600160489190911c81161490565b1515815260200161237e846101000151600160499190911c81161490565b1515815260200161239c8461010001516001604a9190911c81161490565b151581526020016123ba8461010001516001604b9190911c81161490565b151581526020016123d88461010001516001604c9190911c81161490565b151581526020016123f68461010001516001604d9190911c81161490565b151581526020016124148461010001516001604e9190911c81161490565b151581526020016124328461010001516001604f9190911c81161490565b15158152602001612450846101000151600160509190911c81161490565b1515815260200161246e846101000151600160519190911c81161490565b1515815260200161248484610100015160521c90565b6001600160a01b031681526020016124a184610100015160f21c90565b61ffff16905292915050565b60006124b7612972565b9050836001600160a01b0316816001600160a01b0316141580156125865750604051631a45b42760e11b81526001600160a01b0382811660048301528581166024830152604482018590526064820184905260016084830181905260a48301527f000000000000000000000000f5ca295dc286a176e35ebb7833031fd95550eb14169063348b684e9060c401602060405180830381865afa158015612560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125849190614aa2565b155b15611dab57604051631326f75560e11b81526001600160a01b038086166004830152821660248201526044810184905260648101839052608401610e23565b6125cd6136da565b6040516321d1336160e11b8152600481018390527f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b0316906343a266c2906024015b61012060405180830381865afa158015612634573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e99190614452565b6000805b8281101561296a576000848483818110612678576126786147d4565b905060200281019061268a9190614c82565b6126939061516f565b905061271061ffff168160a001516000015161ffff1611156126dd5760a08101515160405163a162453f60e01b815261ffff90911660048201526127106024820152604401610e23565b61271061ffff168160a001516020015161ffff1611156127285760a0810151602001516040516318e037d360e11b815261ffff90911660048201526127106024820152604401610e23565b60007f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b03166370174dcc88846020015185604001518660600151876080015161277b8960a001516133ca565b895160405160e089901b6001600160e01b0319168152600481019790975263ffffffff95861660248801526001600160701b0390941660448701529390911660648501526001600160a01b0316608484015260a483019190915265ffffffffffff1660c482015260e401610120604051808303816000875af1158015612805573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128299190614452565b602081015160c0840151604051638a36dffd60e01b81529293506001600160a01b037f0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c1692638a36dffd92612882928c926004016152a4565b600060405180830381600087803b15801561289c57600080fd5b505af11580156128b0573d6000803e3d6000fd5b505050602082015160e08401516040516323c620f360e21b81526001600160a01b037f000000000000000000000000f1e1df5bba779e977a27ccc273847ab1346fceb8169350638f1883cc9261290a928c926004016153bd565b600060405180830381600087803b15801561292457600080fd5b505af1158015612938573d6000803e3d6000fd5b5061294a925060019150879050614a4c565b830361296057806020015165ffffffffffff1693505b505060010161265c565b509392505050565b600061297c613574565b905090565b6000816001600160401b0381111561299b5761299b6141fd565b6040519080825280602002602001820160405280156129c4578160200160208202803683370190505b50905060005b82811015612aa35760008484838181106129e6576129e66147d4565b90506020028101906129f8919061546b565b612a0190615481565b805160208201516040516304a6e43960e31b81529293506001600160a01b039091169163253721c891612a39918a919060040161557e565b600060405180830381600087803b158015612a5357600080fd5b505af1158015612a67573d6000803e3d6000fd5b505050508060000151838381518110612a8257612a826147d4565b6001600160a01b0390921660209283029190910190910152506001016129ca565b508115611dab5760405163104373fb60e31b81526001600160a01b037f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41169063821b9fd89061098290879085906004016155f6565b604051636e49181f60e01b8152600481018390526001600160a01b0382811660248301526000917f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa4190911690636e49181f90604401602060405180830381865afa158015612b6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8e9190614aa2565b9392505050565b80611dab57611dab8484846124ad565b612bad6136da565b604051631735e2c560e11b8152600481018390527f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b031690632e6bc58a90602401612616565b600080612c0c84610100015160521c90565b6001600160a01b031614158015612c9a575061010083015160521c604051630cef9c1160e31b8152600481018690526001600160a01b038481166024830152919091169063677ce08890604401602060405180830381865afa158015612c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9a9190614aa2565b949350505050565b6000808060001985870985870292508281108382030391505080600003612cdc57838281612cd257612cd261564f565b0492505050612b8e565b838110612d0d57604051630c740aef60e31b8152600481018790526024810186905260448101859052606401610e23565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052612dc784826135e9565b611dab576040516001600160a01b03848116602483015260006044830152612e2a91869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613638565b611dab8482613638565b6040516369e11cc560e01b815260048101869052602481018590526044810184905282906000907f0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c6001600160a01b0316906369e11cc590606401600060405180830381865afa158015612eac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612ed49190810190615665565b805190915060005b81811015613334576000838281518110612ef857612ef86147d4565b602002602001015190506000612f2388836000015163ffffffff16633b9aca0063ffffffff16612ca2565b905080156132e55760a08201516001600160a01b031615612feb57612f4e8b828460a001518a613340565b8160a001516001600160a01b031663c5a093886040518060c001604052808a6001600160a01b03168152602001848152602001601281526020018e81526020018c8152602001858152506040518263ffffffff1660e01b8152600401612fb4919061576a565b600060405180830381600087803b158015612fce57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b505050506132d8565b60408201516000906001600160a01b031661300d57613008612972565b613013565b82604001515b905082602001516001600160401b03166000146132305760006001600160a01b038916156130df576020840151604051630862026560e41b81526001600160401b0390911660048201526001600160a01b038a811660248301527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa411690638620265090604401602060405180830381865afa1580156130b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130da919061446f565b6130e2565b60005b90506001600160a01b038916158061310157506001600160a01b038116155b15613117576131128d84848c613340565b61322a565b60008d60405160200161312c91815260200190565b60408051601f1981840301815290829052602087015163fb61b4e360e01b8352909250309163fb61b4e39161316e918691908f908a908a9089906004016157be565b600060405180830381600087803b15801561318857600080fd5b505af1925050508015613199575060015b613228573d8080156131c7576040519150601f19603f3d011682016040523d82523d6000602084013e6131cc565b606091505b508e7fdba24f3504238ca84f6411d16a14bb7ae54061b0a80892bf93eb5a8912ed73558787846131fa612972565b60405161320a9493929190615814565b60405180910390a26132266001600160a01b038c1685876136a9565b505b505b506132d6565b61deac196001600160a01b038216016132ca577f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf366001600160a01b031663124d91e5308e856040518463ffffffff1660e01b8152600401613293939291906149f8565b600060405180830381600087803b1580156132ad57600080fd5b505af11580156132c1573d6000803e3d6000fd5b505050506132d6565b6132d68c83838b613340565b505b6132e28187614a4c565b95505b888a8c7fbfcad5a78fa104a30927810dfb51a41d1119d43ce12be27620ab589e1273cebe8585613313612972565b60405161332293929190615856565b60405180910390a45050600101612edc565b50505095945050505050565b6001600160a01b03811615613368576133636001600160a01b03821683856136a9565b611dab565b60405163b1e6d2a160e01b8152306004820152602481018590526001600160a01b038381166044830152606482018590527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063b1e6d2a190608401610982565b6000600190506004826000015161ffff16901b811790506014826020015161ffff16901b811790506024826040015163ffffffff16901b8117905081606001511561341b5768100000000000000000175b8160800151156134315768200000000000000000175b8160a00151156134475768400000000000000000175b8160c001511561345d5768800000000000000000175b8160e0015115613474576901000000000000000000175b8161010001511561348c576902000000000000000000175b816101200151156134a4576904000000000000000000175b816101400151156134bc576908000000000000000000175b816101600151156134d4576910000000000000000000175b816101800151156134ec576920000000000000000000175b816101a0015115613504576940000000000000000000175b816101c001511561351c576980000000000000000000175b816101e001511561352e57600160501b175b8161020001511561354057600160511b175b6102208201516102409092015160529290921b600160521b600160f21b03161760f29190911b6001600160f21b0319161790565b6000366014336001600160a01b037f0000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f887161480156135b15750808210155b156135e1576000366135c38385614a4c565b6135ce928290615884565b6135d7916158ae565b60601c9250505090565b339250505090565b6000806000806020600086516020880160008a5af192503d9150600051905082801561362e5750811561361f578060011461362e565b6000866001600160a01b03163b115b9695505050505050565b600080602060008451602086016000885af18061365b576040513d6000823e3d81fd5b50506000513d91508115613673578060011415613680565b6001600160a01b0384163b155b15611dab57604051635274afe760e01b81526001600160a01b0385166004820152602401610e23565b6040516001600160a01b03838116602483015260448201839052610e8c91859182169063a9059cbb90606401612df8565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b6040805161026081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e081018290526102008101829052610220810182905261024081019190915290565b60405180604001604052806137d56136da565b81526020016137e2613726565b905290565b6000602082840312156137f957600080fd5b81356001600160e01b031981168114612b8e57600080fd5b60006020828403121561382357600080fd5b5035919050565b6000806040838503121561383d57600080fd5b50508035926020909101359150565b65ffffffffffff80825116835280602083015116602084015280604083015116604084015250606081015161388b606084018265ffffffffffff169052565b5060808101516138a3608084018263ffffffff169052565b5060a08101516138be60a08401826001600160701b03169052565b5060c08101516138d660c084018263ffffffff169052565b5060e08101516138f160e08401826001600160a01b03169052565b5061010090810151910152565b805161ffff168252602081015161391b602084018261ffff169052565b506040810151613933604084018263ffffffff169052565b506060810151613947606084018215159052565b50608081015161395b608084018215159052565b5060a081015161396f60a084018215159052565b5060c081015161398360c084018215159052565b5060e081015161399760e084018215159052565b5061010081810151151590830152610120808201511515908301526101408082015115159083015261016080820151151590830152610180808201511515908301526101a0808201511515908301526101c0808201511515908301526101e08082015115159083015261020080820151151590830152610220808201516001600160a01b0316908301526102408082015161ffff811682850152611dab565b6103808101613a45828561384c565b612b8e6101208301846138fe565b6001600160a01b0381168114613a6857600080fd5b50565b60008060008060808587031215613a8157600080fd5b8435935060208501359250604085013591506060850135613aa181613a53565b939692955090935050565b8035613ab781613a53565b919050565b60008060008060808587031215613ad257600080fd5b8435613add81613a53565b935060208501359250604085013591506060850135613aa181613a53565b60008083601f840112613b0d57600080fd5b5081356001600160401b03811115613b2457600080fd5b6020830191508360208260051b8501011115613b3f57600080fd5b9250929050565b60008083601f840112613b5857600080fd5b5081356001600160401b03811115613b6f57600080fd5b602083019150836020828501011115613b3f57600080fd5b600080600080600060608688031215613b9f57600080fd5b8535945060208601356001600160401b0380821115613bbd57600080fd5b613bc989838a01613afb565b90965094506040880135915080821115613be257600080fd5b50613bef88828901613b46565b969995985093965092949392505050565b60008060008060008060006080888a031215613c1b57600080fd5b8735965060208801356001600160401b0380821115613c3957600080fd5b613c458b838c01613afb565b909850965060408a0135915080821115613c5e57600080fd5b613c6a8b838c01613afb565b909650945060608a0135915080821115613c8357600080fd5b50613c908a828b01613b46565b989b979a50959850939692959293505050565b60008060408385031215613cb657600080fd5b823591506020830135613cc881613a53565b809150509250929050565b600060208284031215613ce557600080fd5b8135612b8e81613a53565b60008060008060008060808789031215613d0957600080fd5b8635955060208701356001600160401b0380821115613d2757600080fd5b613d338a838b01613b46565b90975095506040890135915080821115613d4c57600080fd5b50613d5989828a01613b46565b979a9699509497949695606090950135949350505050565b600080600080600080600080600060a08a8c031215613d8f57600080fd5b8935613d9a81613a53565b985060208a01356001600160401b0380821115613db657600080fd5b613dc28d838e01613b46565b909a50985060408c0135915080821115613ddb57600080fd5b613de78d838e01613afb565b909850965060608c0135915080821115613e0057600080fd5b613e0c8d838e01613afb565b909650945060808c0135915080821115613e2557600080fd5b50613e328c828d01613b46565b915080935050809150509295985092959850929598565b600080600060608486031215613e5e57600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b81811015613ecc578351613ea684825161384c565b850151613eb76101208501826138fe565b50928401926103809290920191600101613e91565b50909695505050505050565b600080600060408486031215613eed57600080fd5b8335925060208401356001600160401b03811115613f0a57600080fd5b613f1686828701613b46565b9497909650939450505050565b60008060008060608587031215613f3957600080fd5b843593506020850135925060408501356001600160401b03811115613f5d57600080fd5b613f6987828801613afb565b95989497509550505050565b600080600080600060808688031215613f8d57600080fd5b8535613f9881613a53565b9450602086013593506040860135925060608601356001600160401b03811115613fc157600080fd5b613bef88828901613b46565b60005b83811015613fe8578181015183820152602001613fd0565b50506000910152565b60008151808452614009816020860160208601613fcd565b601f01601f19169290920160200192915050565b602081526000612b8e6020830184613ff1565b6000806000806080858703121561404657600080fd5b843561405181613a53565b935060208501359250604085013561406881613a53565b9396929550929360600135925050565b6103a08101614087828661384c565b6140956101208301856138fe565b600683106140b357634e487b7160e01b600052602160045260246000fd5b82610380830152949350505050565b8015158114613a6857600080fd5b8035613ab7816140c2565b60008060008060008060a087890312156140f457600080fd5b8635955060208701359450604087013561410d81613a53565b935060608701356001600160401b0381111561412857600080fd5b61413489828a01613b46565b9094509250506080870135614148816140c2565b809150509295509295509295565b6000806040838503121561416957600080fd5b823561417481613a53565b946020939093013593505050565b600080600080600080600060c0888a03121561419d57600080fd5b87356141a881613a53565b96506020880135955060408801356141bf81613a53565b94506060880135935060808801356141d681613a53565b925060a08801356001600160401b038111156141f157600080fd5b613c908a828b01613b46565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614236576142366141fd565b60405290565b60405161026081016001600160401b0381118282101715614236576142366141fd565b604080519081016001600160401b0381118282101715614236576142366141fd565b60405160c081016001600160401b0381118282101715614236576142366141fd565b604051608081016001600160401b0381118282101715614236576142366141fd565b60405161010081016001600160401b0381118282101715614236576142366141fd565b604051606081016001600160401b0381118282101715614236576142366141fd565b604051601f8201601f191681016001600160401b0381118282101715614332576143326141fd565b604052919050565b65ffffffffffff81168114613a6857600080fd5b8051613ab78161433a565b63ffffffff81168114613a6857600080fd5b8051613ab781614359565b6001600160701b0381168114613a6857600080fd5b8051613ab781614376565b8051613ab781613a53565b600061012082840312156143b457600080fd5b6143bc614213565b90506143c78261434e565b81526143d56020830161434e565b60208201526143e66040830161434e565b60408201526143f76060830161434e565b60608201526144086080830161436b565b608082015261441960a0830161438b565b60a082015261442a60c0830161436b565b60c082015261443b60e08301614396565b60e082015261010080830151818301525092915050565b6000610120828403121561446557600080fd5b612b8e83836143a1565b60006020828403121561448157600080fd5b8151612b8e81613a53565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8581528460208201526080604082015260006144d560808301858761448c565b905060018060a01b03831660608301529695505050505050565b60006020828403121561450157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156106e9576106e9614508565b86815260806020820152600061454b60808301878961448c565b828103604084015261455e81868861448c565b915050826060830152979650505050505050565b600181811c9082168061458657607f821691505b6020821081036145a657634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610e8c576000816000526020600020601f850160051c810160208610156145d55750805b601f850160051c820191505b818110156145f4578281556001016145e1565b505050505050565b6001600160401b03831115614613576146136141fd565b614627836146218354614572565b836145ac565b6000601f84116001811461465b57600085156146435750838201355b600019600387901b1c1916600186901b1783556146b5565b600083815260209020601f19861690835b8281101561468c578685013582556020948501946001909201910161466c565b50868210156146a95760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b87815286602082015260a0604082015260006146dc60a08301878961448c565b82810360608401526146ef81868861448c565b91505060018060a01b038316608083015298975050505050505050565b60006001600160401b03821115614725576147256141fd565b5060051b60200190565b6000602080838503121561474257600080fd5b82516001600160401b0381111561475857600080fd5b8301601f8101851361476957600080fd5b805161477c6147778261470c565b61430a565b8082825260208201915061012060208185028601019350888411156147a057600080fd5b6020850194505b838510156147c8576147b989866143a1565b835293840193918501916147a7565b50979650505050505050565b634e487b7160e01b600052603260045260246000fd5b6040815260006147fe60408301858761448c565b905060018060a01b0383166020830152949350505050565b8035613ab781614359565b6001600160401b0381168114613a6857600080fd5b8035613ab78161433a565b6000606080830187845260208781860152604060606040870152828784526080935060808701905060808860051b8801018960005b8a8110156149b357898303607f190184528135368d9003603e1901811261489c57600080fd5b8c01803584528386018782013536839003601e190181126148bc57600080fd5b9091018781019190356001600160401b03808211156148da57600080fd5b60c080830236038513156148ed57600080fd5b878b018a9052928290526000928c88015b8385101561499c57853561491181614359565b63ffffffff168152858c013561492681614821565b8316818d0152858b013561493981613a53565b6001600160a01b0316818c0152858e0135614953816140c2565b1515818f0152614964868e01614836565b65ffffffffffff168d82015260a061497d878201613aac565b6001600160a01b031690820152948101946001949094019381016148fe565b988b01989750505093880193505050600101614876565b50909c9b505050505050505050505050565b8481526060602082015260006149df60608301858761448c565b905060018060a01b038316604083015295945050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b6000806101408385031215614a2d57600080fd5b614a3784846143a1565b915061012083015160068110613cc857600080fd5b818103818111156106e9576106e9614508565b86815285602082015260a060408201526000614a7f60a08301868861448c565b6060830194909452506001600160a01b0391909116608090910152949350505050565b600060208284031215614ab457600080fd5b8151612b8e816140c2565b600060208284031215614ad157600080fd5b81516001600160401b0380821115614ae857600080fd5b818401915084601f830112614afc57600080fd5b815181811115614b0e57614b0e6141fd565b614b21601f8201601f191660200161430a565b9150808252856020828501011115614b3857600080fd5b614b49816020840160208601613fcd565b50949350505050565b81516001600160401b03811115614b6b57614b6b6141fd565b614b7f81614b798454614572565b846145ac565b602080601f831160018114614bb45760008415614b9c5750858301515b600019600386901b1c1916600185901b1785556145f4565b600085815260208120601f198616915b82811015614be357888601518255948401946001909101908401614bc4565b5085821015614c015787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b878152600060018060a01b03808916602084015287604084015280871660608401525084608083015260e060a0830152600060e08301526101008060c0840152614c5e818401858761448c565b9a9950505050505050505050565b634e487b7160e01b600052600160045260246000fd5b6000823561033e19833603018112614c9957600080fd5b9190910192915050565b8035613ab781614376565b803561ffff81168114613ab757600080fd5b60006102608284031215614cd357600080fd5b614cdb61423c565b9050614ce682614cae565b8152614cf460208301614cae565b6020820152614d0560408301614816565b6040820152614d16606083016140d0565b6060820152614d27608083016140d0565b6080820152614d3860a083016140d0565b60a0820152614d4960c083016140d0565b60c0820152614d5a60e083016140d0565b60e0820152610100614d6d8184016140d0565b90820152610120614d7f8382016140d0565b90820152610140614d918382016140d0565b90820152610160614da38382016140d0565b90820152610180614db58382016140d0565b908201526101a0614dc78382016140d0565b908201526101c0614dd98382016140d0565b908201526101e0614deb8382016140d0565b90820152610200614dfd8382016140d0565b90820152610220614e0f838201613aac565b90820152610240614e21838201614cae565b9082015292915050565b600082601f830112614e3c57600080fd5b81356020614e4c6147778361470c565b82815260059290921b84018101918181019086841115614e6b57600080fd5b8286015b84811015614fbf5780356001600160401b0380821115614e8e57600080fd5b908801906040828b03601f1901811315614ea757600080fd5b614eaf61425f565b8784013581528184013583811115614ec657600080fd5b8085019450508b603f850112614edb57600080fd5b878401359250614eed6147778461470c565b83815260c09093028401820192888101908d851115614f0b57600080fd5b948301945b84861015614faa5760c0868f031215614f2857600080fd5b614f30614281565b8635614f3b81614359565b8152868b0135614f4a81614821565b818c015286850135614f5b81613a53565b818601526060870135614f6d816140c2565b60608201526080870135614f808161433a565b608082015260a0870135614f9381613a53565b60a0820152825260c0959095019490890190614f10565b828a0152508652505050918301918301614e6f565b509695505050505050565b600082601f830112614fdb57600080fd5b81356020614feb6147778361470c565b82815260069290921b8401810191818101908684111561500a57600080fd5b8286015b84811015614fbf57604081890312156150275760008081fd5b61502f61425f565b81356001600160e01b03811681146150475760008081fd5b81528185013561505681614359565b8186015283529183019160400161500e565b600082601f83011261507957600080fd5b813560206150896147778361470c565b82815260059290921b840181019181810190868411156150a857600080fd5b8286015b84811015614fbf5780356001600160401b03808211156150cc5760008081fd5b908801906080828b03601f19018113156150e65760008081fd5b6150ee6142a3565b878401356150fb81613a53565b815260408481013561510c81613a53565b828a0152606085810135858111156151245760008081fd5b6151328f8c838a0101614fca565b848401525092850135928484111561514c57600091508182fd5b61515a8e8b86890101614fca565b908301525086525050509183019183016150ac565b6000610340823603121561518257600080fd5b61518a6142c5565b61519383614836565b81526151a160208401614816565b60208201526151b260408401614ca3565b60408201526151c360608401614816565b60608201526151d460808401613aac565b60808201526151e63660a08501614cc0565b60a08201526103008301356001600160401b038082111561520657600080fd5b61521236838701614e2b565b60c084015261032085013591508082111561522c57600080fd5b5061523936828601615068565b60e08301525092915050565b805163ffffffff1682526020808201516001600160401b0316908301526040808201516001600160a01b039081169184019190915260608083015115159084015260808083015165ffffffffffff169084015260a09182015116910152565b60006060808301868452602065ffffffffffff87168186015260406060604087015282875180855260808801915060808160051b89010194508389016000805b83811015615355578a8803607f190185528251805189528701518789018790528051878a018190529088019083908b8b01905b808310156153405761532a828551615245565b60c0820191508a84019350600183019250615317565b509950505093860193918601916001016152e4565b50959c9b505050505050505050505050565b60008151808452602080850194506020840160005b838110156153b257815180516001600160e01b0316885283015163ffffffff16838801526040909601959082019060010161537c565b509495945050505050565b60006060808301868452602065ffffffffffff8716818601526040606060408701528287518085526080945060808801915060808160051b890101848a0160005b838110156149b3578a8303607f19018552815180516001600160a01b039081168552888201511688850152868101518785018a905261543f8a860182615367565b918b0151858303868d01529190506154578183615367565b9689019694505050908601906001016153fe565b60008235603e19833603018112614c9957600080fd5b6000604080833603121561549457600080fd5b61549c61425f565b83356154a781613a53565b81526020848101356001600160401b038111156154c357600080fd5b850136601f8201126154d457600080fd5b80356154e26147778261470c565b8181526060918202830184019184820191903684111561550157600080fd5b938501935b8385101561556b5780853603121561551e5760008081fd5b6155266142e8565b853561553181613a53565b81528587013560ff811681146155475760008081fd5b818801528589013561555881614359565b818a015283529384019391850191615506565b5093850193909352509195945050505050565b60006040808301858452602060406020860152818651808452606093506060870191506020880160005b828110156155e757815180516001600160a01b031685528581015160ff168686015287015163ffffffff168785015292850192908401906001016155a8565b50919998505050505050505050565b60006040820184835260206040602085015281855180845260608601915060208701935060005b818110156156425784516001600160a01b03168352938301939183019160010161561d565b5090979650505050505050565b634e487b7160e01b600052601260045260246000fd5b6000602080838503121561567857600080fd5b82516001600160401b0381111561568e57600080fd5b8301601f8101851361569f57600080fd5b80516156ad6147778261470c565b81815260c091820283018401918482019190888411156156cc57600080fd5b938501935b838510156147c85780858a0312156156e95760008081fd5b6156f1614281565b85516156fc81614359565b81528587015161570b81614821565b8188015260408681015161571e81613a53565b90820152606086810151615731816140c2565b908201526080868101516157448161433a565b9082015260a08681015161575781613a53565b90820152835293840193918501916156d1565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0828101516101608301916157b790840182615245565b5092915050565b6001600160a01b0387811682526001600160401b03871660208301528581166040830152606082018590528316608082015260c060a0820181905260009061580890830184613ff1565b98975050505050505050565b60006101206158238388615245565b8560c08401528060e084015261583b81840186613ff1565b91505060018060a01b03831661010083015295945050505050565b61010081016158658286615245565b60c08201939093526001600160a01b039190911660e090910152919050565b6000808585111561589457600080fd5b838611156158a157600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff1981358181169160148510156158db5780818660140360031b1b83161692505b50509291505056fea2646970667358221220e47a917a722a55d39c230307c4cd275c10049322c40500668f190d35403b7b1f64736f6c63430008170033

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

0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41000000000000000000000000f1e1df5bba779e977a27ccc273847ab1346fceb8000000000000000000000000f5ca295dc286a176e35ebb7833031fd95550eb14000000000000000000000000e712d14b04f1a1fe464be930e3ea72b9b0a141d70000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898260000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf360000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f887

-----Decoded View---------------
Arg [0] : directory (address): 0x0bC9F153DEe4d3D474ce0903775b9b2AAae9AA41
Arg [1] : fundAccessLimits (address): 0xf1e1dF5bba779e977A27ccC273847Ab1346fCEb8
Arg [2] : permissions (address): 0xF5CA295dc286A176E35eBB7833031Fd95550eb14
Arg [3] : prices (address): 0xE712D14b04F1a1Fe464Be930e3ea72B9B0a141D7
Arg [4] : projects (address): 0x0b538A02610d7d3Cc91Ce2870F423e0a34D646AD
Arg [5] : rulesets (address): 0xDA86EeDb67C6C9FB3E58FE83Efa28674D7C89826
Arg [6] : splits (address): 0x9e834f2ae0970f8746E25Fba6D42FD90BB96630C
Arg [7] : tokens (address): 0xA59e9F424901fB9DBD8913a9A32A081F9425bf36
Arg [8] : trustedForwarder (address): 0x8A5ba591Ed2bed5691a378C65611eD492500f887

-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41
Arg [1] : 000000000000000000000000f1e1df5bba779e977a27ccc273847ab1346fceb8
Arg [2] : 000000000000000000000000f5ca295dc286a176e35ebb7833031fd95550eb14
Arg [3] : 000000000000000000000000e712d14b04f1a1fe464be930e3ea72b9b0a141d7
Arg [4] : 0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad
Arg [5] : 000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c89826
Arg [6] : 0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c
Arg [7] : 000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36
Arg [8] : 0000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f887


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

Juicebox is a programmable crypto fundraising platform for web3.

Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.