Skip to main content

Life of a project

To launch a project, call JBController.launchProjectFor(...).

function launchProjectFor(
address owner,
string calldata projectUri,
JBRulesetConfig[] calldata rulesetConfigurations,
JBTerminalConfig[] calldata terminalConfigurations,
string calldata memo
) external override returns (uint256 projectId) { ... }

Check out the Launching a project example page for more info on how to build projects treasuries to various specifications.

View project info

Launching a project will mint a new ERC-721 in the JBProjects contract. The owner can be found using JBProjects.ownerOf(...).

function ownerOf(uint256 projectId) external returns (address owner) { ... }

A link to the project's metadata can be found using JBController.uriOf(...).

function uriOf(uint256 projectId) external view returns (string memory)
View rulesets

Ruleset data can be found in the JBController contract.

function getRulesetOf(
uint256 projectId,
uint256 rulesetId
) external view returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)

The project's current ruleset can be found using JBController.currentRulesetOf(...).

function currentRulesetOf(uint256 projectId) external view returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)

The project's upcoming ruleset can be found using JBController.upcomingRulesetOf(...).

By default, the upcoming ruleset is a copy of the current one that starts immediately afterwards, using a discounted weight if applicable.

If the project has queued a new ruleset, the upcoming ruleset will reflect the changes once they are approved by the current ruleset's ballot. Rulesets queued during a ruleset with no ballot are automatically queued.

The project has no upcoming ruleset if the current ruleset has no duration.

function upcomingRulesetOf(uint256 projectId) external view returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)

The project's latest configured ruleset can be found using JBController.latestConfiguredRulesetOf(...).

function latestQueuedRulesetOf(uint256 projectId) external view returns (JBRuleset memory, JBRulesetMetadata memory metadata, JBApprovalStatus);

All of a project's rulesets can be found using JBController.allRulesetsOf(...).

function allRulesetsOf(uint256 projectId) external view returns (JBRuleset[] memory rulesets, JBRulesetMetadata[] memory metadata);
View splits

A project's splits data can be found in the JBSplits contract. A set of splits used for any particular functionality during any particular rulesets configuration can be found using JBSplits.splitsOf(...).

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

A project's accounting contexts data can be found in its IJBTerminal contracts. For example, if a project is using the JBMultiTerminal contract, its accounting contexts can be found through its JBMultiTerminal.accountingContextsOf(...) transaction.

function accountingContextsOf(uint256 projectId) external view returns (JBAccountingContext[] memory) { ... }

Or, through the JBMultiTerminal.accountingContextForTokenOf(...) transaction.

function accountingContextForTokenOf(
uint256 projectId,
address token
)
external view returns (JBAccountingContext memory) { ... }
View fund access limits

Constraints on accessing a project's funds can found in the JBFundAccessLimits contract. The payout limit of any terminal during any ruleset using any token with any currency can be found using JBFundAccessLimits.payoutLimitOf(...).

function payoutLimitOf(
uint256 projectId,
uint256 rulesetId,
address terminal,
address token,
uint256 currency
) external view returns (uint256 payoutLimit);

Or, get all limits for any currency

function payoutLimitsOf(
uint256 projectId,
uint256 rulesetId,
address terminal,
address token
) external view returns (JBCurrencyAmount[] memory payoutLimits);

The surplus allowance from any terminal during any ruleset using any token with any currency can be found using JBFundAccessLimits.surplusAllowanceOf.

function surplusAllowanceOf(
uint256 projectId,
uint256 rulesetId,
address terminal,
address token,
uint256 currency
) external view returns (uint256 surplusAllowance);
View terminals and controller

The JBDirectory contract stores addresses of terminals that a project is currently accepting funds through. A project's currently set terminals can be found using JBDirectory.terminalsOf(...), and the address of the terminal to which payments to projects should be sent for any token can be found using JBDirectory.primaryTerminalOf(...).

function terminalsOf(uint256 projectId) external view returns (IJBTerminal[] memory) { ... }
function primaryTerminalOf(uint256 projectId, address token) external view returns (IJBTerminal)

The JBDirectory contract also stores the address of the controller that is managing a project's rulesets and tokens. A projects current controller can be found using JBDirectory.controllerOf(...).

function controllerOf(uint256 projectId) external view returns (IERC165) { ... }

Once a project has been created, it can begin accepting funds from anyone through any terminal it has added, using any token that it has specified accounting contexts for. For example, if the project has added the JBMultiTerminal with only an ETH accounting context, only ETH can be sent to the project by calling its JBMultiTerminal.pay(...) transaction.

function pay(
uint256 projectId,
address token,
uint256 amount,
address beneficiary,
uint256 minReturnedTokens,
string calldata memo,
bytes calldata metadata
) external payable returns (uint256 beneficiaryTokenCount);

Check out the Paying a project example page for more info on how to pay a project.

View treasury balance

A project's treasury balance can be found in the JBTerminalStore contract.

function balanceOf(address terminal, uint256 projectId, address token) external view returns (uint256);

The project's current surplus for a terminal can also be found in the JBTerminalStore contract.

function currentSurplusOf(
address terminal,
uint256 projectId,
JBAccountingContext[] calldata accountingContexts,
uint256 decimals,
uint256 currency
) external view returns (uint256);

The JBTerminalStore can also resolve the total amount of overflow in all of a project's terminals using JBTerminalStore.currentTotalSurplusOf(...).

function currentTotalSurplusOf(
uint256 projectId,
uint256 decimals,
uint256 currency
)
external
view
returns (uint256);
View reserved token balance

A project's undistributed reserved token balance can be found in the project's current controller. For example in the JBController, this balance can be found using JBController.pendingReservedTokenBalanceOf(...).

function pendingReservedTokenBalanceOf(uint256 projectId) external view returns (uint256) { ... }

For projects using JBController, the project token's total supply including any allocated reserved tokens that have yet to be distributed can be found in using JBController.totalTokenSupplyWithReservedTokensOf(...).

function totalTokenSupplyWithReservedTokensOf(uint256 projectId) external view returns (uint256) { ... }
View project token balance

Each holder's balance of a project's token can be found in the JBTokens contract. The balance can be found using JBTokens.totalBalanceOf(...).

function totalBalanceOf(address holder, uint256 projectId) external view returns (uint256 result) { ... }

To only retrieve a holder's internally tracked token credit balance, use JBTokens.creditBalanceOf(...)

function creditBalanceOf(address holder, uint256 projectId) external view returns (uint256) { ... }
View price conversions

The protocol uses price feeds to convert values from one currency to another when sending payouts, using surplus allowances, issuing project tokens when payments are received in various currencies, and more. Current currency indexes can be found in JBCurrencyIds. If the currency strongly correlates to an ERC-20, it is cusom to use the first 32 bytes of its address as the currency. Since ETH is treated using JBConstants.NATIVE_TOKEN, its currency is 61166. New currencies and price feeds can be added in the future.

The same price feeds the protocol uses internally can be accessed externally through the JBPrices contract using JBPrices.pricePerUnitOf(...).

function pricePerUnitOf(
uint256 projectId,
uint256 pricingCurrency,
uint256 unitCurrency,
uint256 decimals
) external view returns (uint256) { ... }

At any point, anyone can distribute a project's reserved tokens to the project's preprogrammed reserved token splits by calling JBController.sendReservedTokensToSplitsOf(...).

function sendReservedTokensToSplitsOf(uint256 projectId) external returns (uint256) { ... }

At any time after the project has been created, its owner can issue ERC-20 tokens for the protocol by calling JBController.deployERC20For(...).

function deployERC20For(
uint256 projectId,
string calldata name,
string calldata symbol,
bytes32 salt
)
external
returns (IJBToken token) { ... }

A project can instead bring their own token, so long as the token adheres to the IJBToken interface, uses 18 decimals fixed point accounting, and isn't already being used by another project. They can do so by calling JBController.setTokenFor(...). This makes it easy to use ERC-1155s or custom contracts.

function setTokenFor(uint256 projectId, IJBToken token) external  { ... };

For projects who don't issue ERC-20's right away, holders can claim their credit balance into a project's ERC-20 once one has been made using the JBTokens.claimTokensFor(...)

function claimTokensFor(address holder, uint256 projectId, uint256 count, address beneficiary) external { ... }
View the project's token

The token currently being used by a project can be found in the JBTokens contract by using JBTokens.tokenOf(...). This will return a zero address if the project hasn't yet issued tokens or changed into a custom token.

function tokenOf(uint256 _projectId) external view override returns (IJBToken) { ... }

Anyone can distribute a project's payouts from a terminal up to its current ruleset's payout limit to its preprogrammed payout splits at any time. For example, if the project has added the JBMultiTerminal, funds can be distributed by calling JBMultiTerminal.sendPayoutsOf(...).

function sendPayoutsOf(
uint256 projectId,
address token,
uint256 amount,
uint256 currency,
uint256 minTokensPaidOut
) external returns (uint256 netLeftoverPayoutAmount) { ... }
View used payout limit

Any payout limit used by a project can be found in the terminal store contract for each terminal by calling JBTerminalStore.usedPayoutLimitOf(...).

function usedPayoutLimitOf(
address terminal,
uint256 projectId,
address token,
uint256 rulesetCycleNumber,
uint256 currency
) external view returns (uint256) { ... }

A project's owner can distribute additional funds from its treasury's surplus for each of its terminals up until its preconfigured allowance by calling its JBMultiTerminal.useAllowanceOf(...) transaction.

function useAllowanceOf(
uint256 projectId,
address token,
uint256 amount,
uint256 currency,
uint256 minTokensPaidOut,
address payable beneficiary,
address payable feeBeneficiary,
string calldata memo
) external returns (uint256 netAmountPaidOut) { ... }
View used surplus allowance

Any surplus allowance used can also be found in the terminal store contracts for each terminal using JBTerminalStore.usedSurplusAllowanceOf(...).

function usedSurplusAllowanceOf(
address terminal,
uint256 projectId,
address token,
uint256 rulesetId,
uint256 currency
)
external view returns (uint256) { ... }

Anyone who holds a project's tokens can cash them out at one of the project's terminals for a proportional share of the project's surplus. For example, if the project has funds in the JBMultiTerminal, ETH can be reclaimed by redeeming project tokens in its JBMultiTerminal.cashOutTokensOf(...) transaction. The surplus amount is the terminal's balance minus the current ruleset's payout limit, and can be set to include the project's balance across all terminals.

Cashing out tokens allows a project's token holders to exit the community at any time with their share of the funds. If the project's cash out tax rate is more than 0%, cash outs incur a 2.5% JBX membership fee.

function cashOutTokensOf(
address holder,
uint256 projectId,
uint256 cashOutCount,
address tokenToReclaim,
uint256 minTokensReclaimed,
address payable beneficiary,
bytes calldata metadata
)
external
returns (uint256 reclaimAmount);
View cash out values

Any surplus allowance used can also be found in the terminal store contracts for each terminal using JBTerminalStore.usedSurplusAllowanceOf(...).

function currentReclaimableSurplusOf(
uint256 projectId,
uint256 tokenCount,
uint256 totalSupply,
uint256 surplus
)
external view returns (uint256) { ... }

or, to determine the surplus of a project from its terminals, use JBTerminalStore.currentReclaimableSurplusOf(...).

function currentReclaimableSurplusOf(
uint256 projectId,
uint256 cashOutCount,
IJBTerminal[] calldata terminals,
JBAccountingContext[] calldata accountingContexts,
uint256 decimals,
uint256 currency
)
external view returns (uint256) { ... }

If a project's current ruleset allow, project's owner can issue more of the project's token on demand lby calling JBController.mintTokensOf(...). Anyone can burn their tokens by calling JBController.burnTokensOf(...).

function mintTokensOf(
uint256 projectId,
uint256 tokenCount,
address beneficiary,
string calldata memo,
bool useReservedPercent
)
external
returns (uint256 beneficiaryTokenCount) { ... }
function burnTokensOf(address holder, uint256 projectId, uint256 tokenCount, string calldata memo) external;

A project's owner can queue new rulesets at any time by calling JBController.queueRulesetsOf(...). If the project is in the middle of a ruleset with a duration, the update will be queued to take effect next ruleset, otherwise it will start right away. If the current ruleset has an attached approval hook contract, it must approve the queue rulesets before taking effect.

function queueRulesetsOf(
uint256 projectId,
JBRulesetConfig[] calldata rulesetConfigurations,
string calldata memo
)
external
returns (uint256 rulesetId){ ... }

At any point, anyone can inject funds into one of a project's terminals by calling the terminal's JBMultiTerminal.addToBalanceOf(...) transaction.

function addToBalanceOf(
uint256 projectId,
address token,
uint256 amount,
bool shouldReturnHeldFees,
string calldata memo,
bytes calldata metadata
) external payable;