Latest 25 from a total of 140 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Send Reserved To... | 37873616 | 10 days ago | IN | 0 ETH | 0.0000015 | ||||
| Send Reserved To... | 37517918 | 18 days ago | IN | 0 ETH | 0.00000154 | ||||
| Send Reserved To... | 37517883 | 18 days ago | IN | 0 ETH | 0.00000161 | ||||
| Send Reserved To... | 37517866 | 18 days ago | IN | 0 ETH | 0.00000203 | ||||
| Send Reserved To... | 37517654 | 18 days ago | IN | 0 ETH | 0.00000116 | ||||
| Send Reserved To... | 37072057 | 28 days ago | IN | 0 ETH | 0.0000005 | ||||
| Set Split Groups... | 37071362 | 28 days ago | IN | 0 ETH | 0.00000008 | ||||
| Set Uri Of | 36848993 | 34 days ago | IN | 0 ETH | 0.0000002 | ||||
| Send Reserved To... | 36366254 | 45 days ago | IN | 0 ETH | 0.00000049 | ||||
| Send Reserved To... | 36238624 | 48 days ago | IN | 0 ETH | 0.00000269 | ||||
| Set Uri Of | 35795191 | 58 days ago | IN | 0 ETH | 0.00000035 | ||||
| Send Reserved To... | 35721847 | 60 days ago | IN | 0 ETH | 0.00000066 | ||||
| Set Uri Of | 35557063 | 63 days ago | IN | 0 ETH | 0.00000045 | ||||
| Launch Project F... | 35453769 | 66 days ago | IN | 0 ETH | 0.00000448 | ||||
| Send Reserved To... | 35372143 | 68 days ago | IN | 0 ETH | 0.00000134 | ||||
| Send Reserved To... | 35370939 | 68 days ago | IN | 0 ETH | 0.00000009 | ||||
| Send Reserved To... | 35370895 | 68 days ago | IN | 0 ETH | 0.00000072 | ||||
| Send Reserved To... | 34280380 | 93 days ago | IN | 0 ETH | 0.00000058 | ||||
| Queue Rulesets O... | 34219283 | 94 days ago | IN | 0 ETH | 0.00000043 | ||||
| Set Uri Of | 34152534 | 96 days ago | IN | 0 ETH | 0.0000009 | ||||
| Send Reserved To... | 34008837 | 99 days ago | IN | 0 ETH | 0.00000116 | ||||
| Send Reserved To... | 33991679 | 100 days ago | IN | 0 ETH | 0.00000305 | ||||
| Set Uri Of | 33724379 | 106 days ago | IN | 0 ETH | 0.00000008 | ||||
| Set Uri Of | 33551283 | 110 days ago | IN | 0 ETH | 0.00000057 | ||||
| Launch Project F... | 33550443 | 110 days ago | IN | 0 ETH | 0.00000826 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 26485017 | 273 days ago | Contract Creation | 0 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
Contract Source Code (Solidity Standard Json-Input format)
// 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
});
}
}
}// 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);
}// 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";// 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);
}// 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);
}
}// 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;
}// 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;
}// 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)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Group IDs that categorize splits.
library JBSplitGroupIds {
uint256 public constant RESERVED_TOKENS = 1;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}// 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;
}{
"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
- No Contract Security Audit Submitted- Submit Audit Here
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"}]Contract Creation Code
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
Loading...
Loading
Loading...
Loading
OVERVIEW
Juicebox is a programmable crypto fundraising platform for web3.Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.