Programmable treasury
In order to understand what Juicebox can do for your project, all you have to do is understand how one transaction works: JBController3_1.launchProjectFor(...), which creates a project, configures its first funding cycle, and specifies where it can begin receiving and managing funds from.
function launchProjectFor(
address _owner,
JBProjectMetadata calldata _projectMetadata,
JBFundingCycleData calldata _data,
JBFundingCycleMetadata calldata _metadata,
uint256 _mustStartAtOrAfter,
JBGroupedSplits[] calldata _groupedSplits,
JBFundAccessConstraints[] calldata _fundAccessConstraints,
IJBPaymentTerminal[] memory _terminals,
string memory _memo
) external virtual override returns (uint256 projectId) { ... }
This transaction launches a project. It does so by:
- Minting a project in the
JBProjectsERC-721 contract by callingJBProjects.createFor(...). - Then giving the
JBController3_1contract that is currently handling thelaunchProjectFortransaction authority to write to theJBFundingCycleStoreand theJBTokenStoreon the project's behalf by callingJBDirectory.setControllerOf(...). - Then creating the project's first funding cycle using the provided
_data,_metadata, and_mustStartAtOrAfterparameters by callingJBFundingCycleStore.configureFor(...). - Then storing splits for any provided split groups by calling
JBSplitStore.set(...). - Then storing any provided constraints on how the project will be able to access funds within any specified payment terminals by storing values via
JBController3_1.fundAccessConstraintsStore.setFor()(you can access those stored values viaJBFundAccessConstraintsStore.distributionLimitOf(...),JBFundAccessConstraintsStore.overflowAllowanceOf(...)). - Then giving the provided
_terminalsaccess to theJBController3_1contract that is handling thelaunchProjectFor(...)transaction that is currently being executed, and also allowing anyone or any other contract in Web3 to know that the project is currently accepting funds through them by callingJBDirectory.setTerminalsOf(...).
Basics
Here are some examples, starting with the simplest version:
-
For
_projectMetadatasend the followingJBProjectMetadatavalues:{
content: "QmbH96jj8RTJgC9526RdsFs5dPvcsRfiRuD9797JXzcvbw",
domain: 0
} -
For
_datasend the followingJBFundingCycleDatavalues:{
duration: 0,
weight: 1000000000000000000000000,
discountRate: 0,
ballot: 0x0000000000000000000000000000000000000000
} -
For
_metadatasend the followingJBFundingCycleMetadatavalues:{
global: {
allowSetTerminals: false,
allowSetController: false,
pauseTransfers: false
},
reservedRate: 0,
redemptionRate: 10000,
ballotRedemptionRate: 0,
pausePay: false,
pauseDistributions: false,
pauseRedeem: false,
pauseBurn: false,
allowMinting: false,
allowTerminalMigration: false,
allowControllerMigration: false,
holdFees: false,
preferClaimedTokenOverride: false,
useTotalOverflowForRedemptions: false,
useDataSourceForPay: false,
useDataSourceForRedeem: false,
dataSource: 0x0000000000000000000000000000000000000000,
metadata: 0
} -
For
_mustStartAtOrAftersend current timestamp. -
For
_groupedSplitssend an empty array. -
For
_fundAccessConstraintssend an empty array. -
For
_terminalssend an array only including the contract address of theJBETHPaymentTerminal3_1_2.
This is the most vanilla project you can launch, which also makes it cheapest to launch gas-wise. Relatively little needs to get saved into storage.
Under these conditions:
- Your project can begin receiving funds through the
JBETHPaymentTerminal3_1_2. - 1,000,000 of your project's tokens will be minted per ETH received since the configured
_data.weightis1000000000000000000000000. (The raw value sent has 18 decimal places). - All tokens minted as a result of received ETH will go to the beneficiary address specified by the payer of the ETH since the configured
_metadata.reservedRateis 0. - Nothing fancy will happen outside of the default token minting behavior since the configured
_metadata.useDataSourceForPayisfalse. - Nothing fancy will happen outside of the default token redemption behavior since the configured
_metadata.useDataSourceForRedeemisfalse. - None of the funds in the treasury can be distributed to the project owner since no
_fundAccessConstraintswere specified. This means all funds in the treasury are considered overflow. Since the configured_metadata.redemptionRatesent is10000(which represents 100%), all outstanding tokens can be redeemed/burned to claim a proportional part of the overflow. This lets everyone who contributed funds reclaim their ETH if desired. - A new funding cycle with an updated configuration can be triggered at any time by the project owner since the configured
_data.durationof 0 and_data.ballotof0x0000000000000000000000000000000000000000. This lets the project owner capture an arbitrary amount of what is in the treasury at any given point by sending a reconfiguration transaction with_fundAccessConstraintsspecified. - Your project will have basic project info with the IPFS file on
ipfs://QmbH96jj8RTJgC9526RdsFs5dPvcsRfiRuD9797JXzcvbw(Juicebox Frontend use domain0to locate project metadata through IPFS, such as project name, logo, description, twitter handle and discord link)
Fund access constraints
Here's what happens when basic _fundAccessConstraints are specified by sending the following JBFundAccessContraints values:
[
{
terminal: <address of JBETHPaymentTerminal3_1_2>,
token: 0x000000000000000000000000000000000000EEEe, // Address representing ETH in JBTokens.
distributionLimit: 4200000000000000000,
overflowAllowance: 0,
distributionLimitCurrency: 1,
overflowAllowanceCurrency: 0
}
]
- During each funding cycle with this configuration, the project can receive up to 4.2 ETH worth of tokens from the
JBETHPaymentTerminal3_1_2, since the configureddistributionLimitCurrencyis 1 (which represents ETH) and thedistributionLimitis4200000000000000000. (The raw value sent has 18 decimal places). - Anyone can call the
JBPayoutRedemptionPaymentTerminal3_1_2.distributePayoutsOf(...)transaction to send up to 4.2 ETH per funding cycle to the preconfigured splits. Since no splits were specified, all distributed funds go to the project owner. - With each new funding cycle, another 4.2 ETH can be distributed.
- The project cannot distribute any funds in excess of the distribution limit since there is no
overflowAllowance.
Here's what happens when using an overflow allowance instead:
[
{
terminal: <address of JBETHPaymentTerminal3_1_2>,
token: 0x000000000000000000000000000000000000EEEe, // Address representing ETH in JBTokens.
distributionLimit: 0,
overflowAllowance: 690000000000000000000,
distributionLimitCurrency: 0,
overflowAllowanceCurrency: 2
}
]
- Until a new reconfiguration transaction is sent, the project owner can send up to 690 USD worth of ETH tokens from the
JBETHPaymentTerminal3_1_2to any address it chooses since the configuredoverflowAllowanceCurrencyis 2 (which represents USD) and theoverflowAllowanceis690000000000000000000(the raw value sent has 18 decimal places). - Meanwhile, all of the project's funds in the
JBPayoutRedemptionPaymentTerminal3_1_2are considered overflow since there is no distribution limit. - Rolled-over funding cycles (i.e. cycles with the same configuration) do not refresh the allowance.
- An overflow allowance is a free allowance the project can use without additional pre-programmed stipulations.
The _distributionLimit and _overflowAllowance parameters must fit in a uint232.
Grouped splits
If you wish to automatically split treasury payouts or reserved token distributions between various destinations (addresses, other Juicebox projects, or split allocator contracts), add some grouped splits to the launchProjectFor transaction.
{
group: 1,
splits: [
{
preferClaimed: false,
preferAddToBalance: false,
percent: 50000000, // 5%, out of 1000000000
projectId: 0,
beneficiary: 0x0123456789012345678901234567890123456789,
lockedUntil: 0,
allocator: 0x0000000000000000000000000000000000000000
},
{
preferClaimed: false,
preferAddToBalance: false,
percent: 60000000, // 6%, out of 1000000000
projectId: 420,
beneficiary: 0x0123456789012345678901234567890123456789,
lockedUntil: 0,
allocator: 0x0000000000000000000000000000000000000000
},
{
preferClaimed: true,
preferAddToBalance: false,
percent: 60000000, // 6%, out of 1000000000
projectId: 421,
beneficiary: 0x0123456789012345678901234567890123456789,
lockedUntil: 0,
allocator: 0x0000000000000000000000000000000000000000
},
{
preferClaimed: false,
preferAddToBalance: false,
percent: 70000000, // 7%, out of 1000000000
projectId: 0,
beneficiary: 0x0000000000000000000000000000000000000000,
lockedUntil: 1644543173,
allocator: 0x6969696969696969696969696969696969696969
},
{
preferClaimed: false,
preferAddToBalance: false,
percent: 10000000, // 1%, out of 1000000000
projectId: 0,
beneficiary: 0x0000000000000000000000000000000000000000,
lockedUntil: 0,
allocator: 0x0000000000000000000000000000000000000000
},
]
}
- If an
allocatoris provided, the split will try to send the split funds to it. Otherwise, if aprojectIdis provided the split will try to send funds to that projectId's Juicebox treasury by callingpay(...)oraddToBalanceOf(...), sending the project's tokens to thebeneficiaryif usingpay(...). Otherwise, if abeneficiaryis provided the split funds will be sent directly to it. Otherwise, the split will not have a destination defined within it and so applications can treat it as a wild card. In this case, payouts send the split amount to themsg.senderof the transaction. - There are 5 splits in this group.
- The first will send 5% of the total directly to address
0x0123456789012345678901234567890123456789. - The second will send 6% to the treasury of the Juicebox project with ID 420. Since
preferAddToBalanceis false, the payment will be made through thepay(...)function of the project's current primary terminal for the token being distributed. Project 420's tokens will be sent to address0x0123456789012345678901234567890123456789.. - The third will send 6% to the Juicebox treasury of project with ID 421. This project's tokens will be sent to address
0x0123456789012345678901234567890123456789., and they will be automatically claimed as ERC-20s in the beneficiary's wallet if the project has issued them due to thepreferClaimedflag beingtrue. - The fourth will send 7% to the
allocatefunction in contract with address0x6969696969696969696969696969696969696969which must adhere toIJBSplitAllocator. This function will also receive all contextual information regarding the split for it to do custom things with. This split will not be editable or removable from the group during this funding cycle configuration while thelockedUntildate has yet to passed. - The last will send 1% of the total directly to
msg.senderaddress since no destination was specified within the split. - All of the remaining funds (100% - 5% - 6% - 6% - 7% - 1% = 75%) will be sent to the project owner's address.
- The first will send 5% of the total directly to address
- Since the configured split group is 1 (which represents ETH payouts), the protocol will use this group of splits when distributing funds from the ETH terminal.
- This splits will only apply to the funding cycle configuration during which they were set. Splits will have to be set again for future configurations.
- The same group split behavior applies to reserved tokens (represented by group namespace 2), although those routed to a
projectIdwill be sent to the project's owner, and those routed to an allocator will be sent to the contract before having the contract'sallocatefunction called.