jb-project

1
0
Source

Create and configure Juicebox V5 projects. Generate deployment scripts for launching projects with rulesets, terminals, and splits using JBController. Also helps with project ownership transfer and metadata updates.

Install

mkdir -p .claude/skills/jb-project && curl -L -o skill.zip "https://mcp.directory/api/skills/download/8828" && unzip -o skill.zip -d .claude/skills/jb-project && rm skill.zip

Installs to .claude/skills/jb-project

About this skill

Juicebox V5 Project Management

Create and manage Juicebox V5 projects including deployment, configuration, and ownership.

Project Identity

A Juicebox project is uniquely identified by: projectId + chainId + version

This matters because:

  • V4 and V5 are different protocols. Project #64 on V4 is NOT the same as Project #64 on V5, even on the same chain.
  • Project IDs cannot be coordinated across chains. Each chain assigns the next available ID independently. If you deploy to Ethereum you might get project #42, and deploying to Optimism might give you project #17.
  • Suckers link projects across chains. To create an "omnichain project," you deploy separate projects on each chain (with different IDs) and connect them using Suckers. This enables token bridging while maintaining treasury backing.
  • When referencing a project, always specify the version and chain to avoid confusion.

V5.1 Contract Update (Dec 2025)

Only JBRulesets has a code change (one-line approval hook fix). Other contracts were redeployed due to dependency chains (JBTerminalStore→JBMultiTerminal, JB721TiersHook→JB721TiersHookDeployer→JBOmnichainDeployer).

Deploying...Use These Contracts
New projectV5.1 (JBController5_1, JBMultiTerminal5_1, etc.)
RevnetV5.0 (REVDeployer uses V5.0 JBController)

Do not mix V5.0 and V5.1 contracts - use one complete set or the other.

See references/v5-addresses.md or shared/chain-config.json for addresses.

Before Writing Custom Code

Always check if native mechanics can achieve your goal:

User NeedRecommended Solution
Autonomous tokenized treasuryDeploy a Revnet via revnet-core-v5
Project with structured rules and no EOA ownerUse contract-as-owner pattern
Simple fundraising projectUse this skill to generate deployment
Vesting/time-locked distributionsUse payout limits + cycling rulesets (no custom contracts)
NFT-gated treasuryUse nana-721-hook-v5 with native cash outs
Governance-minimal/immutableTransfer ownership to burn address after setup
One-time treasury accessUse surplus allowance (doesn't reset each cycle)
Custom token mechanicsUse custom ERC20 via setTokenFor()

See /jb-patterns for detailed examples of these patterns. See /jb-simplify for a checklist to reduce custom code.

Project Creation Overview

Projects are created through JBController.launchProjectFor() which:

  1. Creates a new project NFT via JBProjects
  2. Sets the controller for the project
  3. Configures the first ruleset
  4. Sets up terminal configurations

Core Functions

Launch a Project

function launchProjectFor(
    address owner,                              // Project owner (receives NFT)
    string calldata projectUri,                 // IPFS metadata URI
    JBRulesetConfig[] calldata rulesetConfigs,  // Initial ruleset(s)
    JBTerminalConfig[] calldata terminalConfigs, // Terminal setup
    string calldata memo                        // Launch memo
) external returns (uint256 projectId);

Project Metadata (projectUri)

The projectUri should point to a JSON file (typically on IPFS) with:

{
  "name": "Project Name",
  "description": "Project description",
  "logoUri": "ipfs://...",
  "infoUri": "https://...",
  "twitter": "@handle",
  "discord": "https://discord.gg/...",
  "telegram": "https://t.me/..."
}

Configuration Structs

JBRulesetConfig

struct JBRulesetConfig {
    uint256 mustStartAtOrAfter;     // Earliest start time (0 = now)
    uint256 duration;               // Duration in seconds (0 = indefinite)
    uint256 weight;                 // Token minting weight (18 decimals)
    uint256 weightCutPercent;       // Weight cut per cycle (0-1000000000)
    IJBRulesetApprovalHook approvalHook;  // Approval hook (e.g., JBDeadline)
    JBRulesetMetadata metadata;     // Ruleset settings
    JBSplitGroup[] splitGroups;     // Payout and reserved splits
    JBFundAccessLimitGroup[] fundAccessLimitGroups;  // Payout limits
}

JBTerminalConfig

struct JBTerminalConfig {
    IJBTerminal terminal;                   // Terminal contract
    JBAccountingContext[] accountingContexts;  // Accepted tokens
}

JBAccountingContext

struct JBAccountingContext {
    address token;          // Token address (address(0) for native)
    uint8 decimals;         // Token decimals
    uint32 currency;        // Currency ID for accounting
}

Deployment Script Example

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

import {Script} from "forge-std/Script.sol";
import {IJBController} from "@bananapus/core/src/interfaces/IJBController.sol";
import {IJBMultiTerminal} from "@bananapus/core/src/interfaces/IJBMultiTerminal.sol";
import {JBRulesetConfig} from "@bananapus/core/src/structs/JBRulesetConfig.sol";
import {JBRulesetMetadata} from "@bananapus/core/src/structs/JBRulesetMetadata.sol";
import {JBTerminalConfig} from "@bananapus/core/src/structs/JBTerminalConfig.sol";
import {JBAccountingContext} from "@bananapus/core/src/structs/JBAccountingContext.sol";
import {JBSplitGroup} from "@bananapus/core/src/structs/JBSplitGroup.sol";
import {JBSplit} from "@bananapus/core/src/structs/JBSplit.sol";
import {JBFundAccessLimitGroup} from "@bananapus/core/src/structs/JBFundAccessLimitGroup.sol";
import {JBCurrencyAmount} from "@bananapus/core/src/structs/JBCurrencyAmount.sol";
import {JBConstants} from "@bananapus/core/src/libraries/JBConstants.sol";

contract DeployProject is Script {
    // V5.1 Mainnet Addresses (use for new projects)
    // See /references/v5-addresses.md for all networks
    // NOTE: For revnets, use V5.0 addresses instead
    IJBController constant CONTROLLER = IJBController(0xf3cc99b11bd73a2e3b8815fb85fe0381b29987e1);
    IJBMultiTerminal constant TERMINAL = IJBMultiTerminal(0x52869db3d61dde1e391967f2ce5039ad0ecd371c);

    function run() external {
        vm.startBroadcast();

        // Configure ruleset metadata
        JBRulesetMetadata memory metadata = JBRulesetMetadata({
            reservedRate: 0,                    // No reserved tokens
            cashOutTaxRate: 0,                  // No cash out tax
            baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
            pausePay: false,
            pauseCashOut: false,
            pauseTransfers: false,
            allowOwnerMinting: false,
            allowTerminalMigration: false,
            allowSetTerminals: false,
            allowSetController: false,
            allowAddAccountingContexts: false,
            allowAddPriceFeed: false,
            ownerMustSendPayouts: false,
            holdFees: false,
            useTotalSurplusForCashOuts: false,
            useDataHookForPay: false,
            useDataHookForCashOut: false,
            dataHook: address(0),
            metadata: 0
        });

        // Configure splits (empty for now)
        JBSplitGroup[] memory splitGroups = new JBSplitGroup[](0);

        // Configure fund access limits
        JBFundAccessLimitGroup[] memory fundAccessLimits = new JBFundAccessLimitGroup[](0);

        // Build ruleset config
        JBRulesetConfig[] memory rulesetConfigs = new JBRulesetConfig[](1);
        rulesetConfigs[0] = JBRulesetConfig({
            mustStartAtOrAfter: 0,
            duration: 0,                        // Indefinite
            weight: 1e18,                       // 1 token per unit paid
            weightCutPercent: 0,                // No weight cut
            approvalHook: IJBRulesetApprovalHook(address(0)),
            metadata: metadata,
            splitGroups: splitGroups,
            fundAccessLimitGroups: fundAccessLimits
        });

        // Configure terminal to accept ETH
        JBAccountingContext[] memory accountingContexts = new JBAccountingContext[](1);
        accountingContexts[0] = JBAccountingContext({
            token: JBConstants.NATIVE_TOKEN,
            decimals: 18,
            currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
        });

        JBTerminalConfig[] memory terminalConfigs = new JBTerminalConfig[](1);
        terminalConfigs[0] = JBTerminalConfig({
            terminal: TERMINAL,
            accountingContexts: accountingContexts
        });

        // Launch the project
        uint256 projectId = CONTROLLER.launchProjectFor(
            msg.sender,                         // Owner
            "ipfs://...",                       // Project metadata URI
            rulesetConfigs,
            terminalConfigs,
            "Project launch"                    // Memo
        );

        vm.stopBroadcast();
    }
}

Custom ERC20 Project Tokens

By default, Juicebox projects use credits (unclaimed internal balances). You can upgrade to an ERC20 token two ways:

Option 1: Deploy Standard JBERC20

// Deploy the default Juicebox ERC20 token
IJBToken token = CONTROLLER.deployERC20For(
    projectId,
    "Project Token",    // name
    "PROJ",             // symbol
    bytes32(0)          // salt (for deterministic address, or 0)
);

This creates a standard JBERC20 that the controller can mint/burn. Simple and works for most projects.

Option 2: Use a Custom ERC20

For advanced tokenomics, you can bring your own ERC20:

// Set an existing/custom ERC20 as the project token
CONTROLLER.setTokenFor(projectId, IJBToken(myCustomToken));

Requirements for custom tokens:

  1. Must use 18 decimals
  2. Must implement canBeAddedTo(uint256 projectId) returning true
  3. Must not be assigned to another Juicebox project
  4. Controller needs mint/burn permissions (typically via ownership or access control)

Custom Token Interface

interface IJBToken is IERC20 {
    /// @notice Verify this token can be added to a proj

---

*Content truncated.*

You might also like

flutter-development

aj-geddes

Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.

1,4071,302

drawio-diagrams-enhanced

jgtolentino

Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.

1,2201,024

ui-ux-pro-max

nextlevelbuilder

"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."

9001,013

godot

bfollington

This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.

958658

nano-banana-pro

garg-aayush

Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.

970608

pdf-to-markdown

aliceisjustplaying

Convert entire PDF documents to clean, structured Markdown for full context loading. Use this skill when the user wants to extract ALL text from a PDF into context (not grep/search), when discussing or analyzing PDF content in full, when the user mentions "load the whole PDF", "bring the PDF into context", "read the entire PDF", or when partial extraction/grepping would miss important context. This is the preferred method for PDF text extraction over page-by-page or grep approaches.

1,033496

Stay ahead of the MCP ecosystem

Get weekly updates on new skills and servers.