Juicebox Protocol V5

website·Indexed 35 days ago

https://docs.juicebox.money

Complete reference for the Juicebox Protocol V5, covering protocol architecture and comprehensive context for AI systems to understand and interact with the protocol.

Tokens
3.7K
Snippets
18
Records
19
Agent score
15%

What's inside Juicebox

  1. Juicebox Protocol V5 Overview

    Juicebox is an Ethereum-native programmable treasury protocol used for tokenized fundraising, revenue management, and financial operations. It allows projects to issue tokens to contributors proportional to their payments, manage funds via programmable rulesets, and operate across multiple chains (Ethereum, Optimism, Arbitrum, and Base). Key features include automated distributions via splits and community exit mechanisms (cash outs) where token holders can reclaim proportional treasury surplus.
  2. Launch a New Juicebox Project

    To start a new project, use the launchProjectFor function, providing the owner address, metadata URI, and configurations for rulesets and terminals.
    function launchProjectFor(
        address owner,
        string calldata projectUri,
        JBRulesetConfig[] calldata rulesetConfigurations,
        JBTerminalConfig[] calldata terminalConfigurations,
        string calldata memo
    ) external returns (uint256 projectId);
  3. Deploy a Revnet

    Revnets are specialized projects with automated operations, predictable issuance (scheduled weight cuts), and omnichain native deployment. They are deployed via the REVDeployer contract.
    // Via REVDeployer
    function deployFor(
        uint256 revnetId,
        REVConfig calldata configuration,
        JBTerminalConfig[] calldata terminalConfigurations,
        REVBuybackHookConfig calldata buybackHookConfiguration,
        REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
        REVCroptopAllowedPost[] calldata allowedPosts,
        bytes calldata extraHookMetadata,
        JBPayHookSpecification[] memory otherPayHooksSpecifications
    ) external returns (uint256, address);
  4. Manage Project Tokens and Credits

    Juicebox uses a dual-token system: internal 'Credits' for accounting and optional ERC-20 tokens that can be claimed from those credits.
    // Get total token balance (credits + ERC-20)
    uint256 balance = JBTokens.totalBalanceOf(holder, projectId);
    
    // Get only credit balance
    uint256 credits = JBTokens.creditBalanceOf(holder, projectId);
    
    // Get project's ERC-20 token
    IJBToken token = JBTokens.tokenOf(projectId);
    
    // Claim credits as ERC-20
    JBTokens.claimTokensFor(holder, projectId, amount, beneficiary);
    
    // Deploy ERC-20 for project
    IJBToken token = JBController.deployERC20For(projectId, "Name", "SYMBOL", salt);
  5. AI Agent Skills for Juicebox V5

    For AI coding assistants (like Claude Code), a skills plugin is available at https://github.com/mejango/juicebox-skills. These skills allow agents to programmatically deploy projects, generate Solidity hooks with tests, and query blockchain state.

    Available skills:

    • /jb-project: Create and configure projects
    • /jb-ruleset: Configure and queue rulesets
    • /jb-pay-hook: Generate custom pay hooks
    • /jb-cash-out-hook: Generate custom cash out hooks
    • /jb-split-hook: Generate custom split hooks
    • /jb-decode: Decode transaction calldata
    • /jb-query: Query project state
    • /jb-docs: Query documentation via MCP
    • /jb-v5-api: API reference for contracts
    • /jb-v5-impl: Implementation knowledge
  6. Configure Juicebox V5 Project Rulesets and Terminals

    Juicebox V5 projects are configured using JBRulesetConfig and JBTerminalConfig. The ruleset defines tokenomics (weight, duration, taxes) and payout splits, while the terminal configuration defines which accounting contexts (currencies) the project accepts.
    const rulesetConfig = {
      mustStartAtOrAfter: 0,
      duration: 0,                    // Infinite ruleset
      weight: 1_000_000_000_000_000_000_000_000, // 1M tokens per ETH
      weightCutPercent: 0,
      approvalHook: ethers.ZeroAddress,
      metadata: {
        reservedPercent: 5_000,       // 50%
        cashOutTaxRate: 0,
        baseCurrency: 1,              // ETH
        pausePay: false,
        pauseCreditTransfers: false,
        allowOwnerMinting: false,
        allowTerminalMigration: false,
        allowSetTerminals: false,
        allowSetController: false,
        allowAddAccountingContext: false,
        allowAddPriceFeed: false,
        ownerMustSendPayouts: false,
        holdFees: false,
        useTotalSurplusForCashOuts: false,
        useDataHookForPay: false,
        useDataHookForCashOut: false,
        dataHook: ethers.ZeroAddress,
        metadata: 0
      },
      splitGroups: [
        {
          groupId: 1, // Payouts
          splits: [
            {
              preferAddToBalance: false,
              percent: 500_000_000,   // 50%
              projectId: 0,
              beneficiary: "0x...",
              lockedUntil: 0,
              hook: ethers.ZeroAddress
            }
          ]
        }
      ],
      fundAccessLimitGroups: [
        {
          terminal: JBMultiTerminal.address,
          token: ethers.ZeroAddress, // Native token
          payoutLimits: [
            { amount: ethers.parseEther("10"), currency: 1 }
          ],
          surplusAllowances: []
        }
      ]
    };
    
    const terminalConfig = {
      terminal: JBMultiTerminal.address,
      accountingContextsToAccept: [
        {
          token: ethers.ZeroAddress, // ETH
          decimals: 18,
          currency: 61166           // Native token currency
        }
      ]
    };
  7. Integrate Juicebox V5 with React

    The juice-sdk-react package provides a provider for project context and hooks for reading metadata and executing payments or cashouts.
    import { JBProjectProvider, useJBProjectMetadata, useJBRuleset, useJBTokenContext, usePay, useCashOut } from "juice-sdk-react";
    
    function App() {
      return (
        <JBProjectProvider projectId={1n} ctxProps={{ metadata: { ipfsGatewayHostname: "..." }}}>
          <ProjectComponent />
        </JBProjectProvider>
      );
    }
    
    function ProjectComponent() {
      // Read Hooks
      const { data: metadata } = useJBProjectMetadata();
      const { ruleset, rulesetMetadata } = useJBRuleset();
      const { token } = useJBTokenContext();
    
      // Write Hooks
      const { write: pay } = usePay();
      const { write: cashOut } = useCashOut();
    
      return <div>...</div>;
    }
  8. Distribute Funds and Reserved Tokens

    Juicebox allows for automated distribution of funds to preprogrammed splits. This includes standard payouts, owner-authorized surplus allowances, and reserved token distributions.
    // Send payouts (up to payout limit)
    function sendPayoutsOf(
        uint256 projectId,
        address token,
        uint256 amount,
        uint256 currency,
        uint256 minTokensPaidOut
    ) external returns (uint256 netLeftoverPayoutAmount);
    
    // Use surplus allowance (owner only)
    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);
    
    // Distribute reserved tokens
    JBController.sendReservedTokensToSplitsOf(projectId);
  9. Implement Custom Logic using Juicebox Hooks

    Juicebox provides several hook interfaces to inject custom logic into the protocol flow:

    • IJBRulesetDataHook: Called before pay or cashOut to modify behavior (e.g., dynamic weight or tax rates).
    • IJBPayHook: Executed after a payment is recorded.
    • IJBCashOutHook: Executed after a cashout is recorded.
    • IJBSplitHook: Executed when a split is processed.
    • IJBRulesetApprovalHook: Controls whether a ruleset change is approved.
    interface IJBRulesetDataHook {
        function beforePayRecordedWith(JBBeforePayRecordedContext calldata context)
            external view returns (uint256 weight, JBPayHookSpecification[] memory hookSpecifications);
    
        function beforeCashOutRecordedWith(JBBeforeCashOutRecordedContext calldata context)
            external view returns (uint256 cashOutTaxRate, uint256 cashOutCount, uint256 totalSupply, JBCashOutHookSpecification[] memory hookSpecifications);
    }
    
    interface IJBPayHook {
        function afterPayRecordedWith(JBAfterPayRecordedContext calldata context) external payable;
    }
    
    interface IJBCashOutHook {
        function afterCashOutRecordedWith(JBAfterCashOutRecordedContext calldata context) external payable;
    }
    
    interface IJBSplitHook {
        function processSplitWith(JBSplitHookContext calldata context) external payable;
    }
    
    interface IJBRulesetApprovalHook {
        function approvalStatusOf(uint256 projectId, uint256 rulesetId, uint256 start)
            external view returns (JBApprovalStatus);
    }
  10. Cash Out Tokens for Treasury Surplus

    Token holders can burn tokens to reclaim a proportional share of the project's treasury surplus, minus the cashOutTaxRate defined in the ruleset.

    Formula: reclaimAmount = surplus * cashOutCount / totalSupply * (1 - cashOutTaxRate)

    function cashOutTokensOf(
        address holder,
        uint256 projectId,
        uint256 cashOutCount,    // Tokens to burn
        address tokenToReclaim,  // Token to receive (ETH, USDC, etc.)
        uint256 minTokensReclaimed,
        address payable beneficiary,
        bytes calldata metadata
    ) external returns (uint256 reclaimAmount);
  11. Deploy an Omnichain Project

    To deploy a project across multiple chains using suckers for token bridging, use the launchProjectFor function. This requires owner details, project URI, ruleset and terminal configurations, and sucker deployment settings.
    function launchProjectFor(
        address owner,
        string calldata projectUri,
        JBRulesetConfig[] calldata rulesetConfigurations,
        JBTerminalConfig[] calldata terminalConfigurations,
        string calldata memo,
        REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
    ) external returns (uint256 projectId, address[] memory suckers);