---
name: jb-query-5fe89ba112f5
description: Query Juicebox V5 project state from the blockchain. Read project configurations, rulesets, terminal balances, token holder data, and splits using cast or ethers.js. Supports mainnet and testnets.
---

# Juicebox V5 Chain Queries

Query on-chain state for Juicebox V5 projects.

## Quick Reference - Contract Functions

### JBProjects (ERC-721)
```solidity
count() → uint256                    // Total projects created
ownerOf(projectId) → address         // Project owner
tokenURI(projectId) → string         // Project metadata URI
```

### JBDirectory
```solidity
controllerOf(projectId) → address              // Project's controller (CRITICAL for version detection!)
terminalsOf(projectId) → IJBTerminal[]         // All terminals
primaryTerminalOf(projectId, token) → address  // Primary terminal for token
isTerminalOf(projectId, terminal) → bool       // Check terminal validity
```

**IMPORTANT**: `controllerOf()` is the ONLY authoritative way to determine which contract version
a project uses. Compare the returned address against known V5/V5.1 controller addresses:
- V5.0: `0x27da30646502e2f642be5281322ae8c394f7668a`
- V5.1: `0xf3cc99b11bd73a2e3b8815fb85fe0381b29987e1`

Some non-revnet projects use V5.0 contracts. Never assume version based on ownership.

### JBController
```solidity
currentRulesetOf(projectId) → (JBRuleset, JBRulesetMetadata)
getRulesetOf(projectId, rulesetId) → (JBRuleset, JBRulesetMetadata)
upcomingRulesetOf(projectId) → (JBRuleset, JBRulesetMetadata)
latestQueuedRulesetOf(projectId) → (JBRuleset, JBRulesetMetadata, approvalStatus)
totalTokenSupplyWithReservedTokensOf(projectId) → uint256
pendingReservedTokenBalanceOf(projectId) → uint256
```

### JBTokens
```solidity
tokenOf(projectId) → address         // ERC-20 token address
totalBalanceOf(holder, projectId) → uint256   // Holder's token balance
totalCreditSupplyOf(projectId) → uint256      // Unclaimed credits
```

### JBMultiTerminal
```solidity
currentSurplusOf(projectId, accountingContexts, decimals, currency) → uint256
```

### JBSplits
```solidity
splitsOf(projectId, rulesetId, groupId) → JBSplit[]
```

### JBFundAccessLimits
```solidity
payoutLimitOf(projectId, rulesetId, terminal, token, currency) → uint256
usedPayoutLimitOf(projectId, terminal, token, rulesetCycleNumber) → uint256
surplusAllowanceOf(projectId, rulesetId, terminal, token, currency) → uint256
usedSurplusAllowanceOf(projectId, terminal, token, rulesetId) → uint256
```

## Cast Commands (Foundry)

### Get Project Owner
```bash
cast call $JB_PROJECTS "ownerOf(uint256)(address)" $PROJECT_ID --rpc-url $RPC_URL
```

### Get Current Ruleset
```bash
cast call $JB_CONTROLLER "currentRulesetOf(uint256)" $PROJECT_ID --rpc-url $RPC_URL
```

### Get Project Token
```bash
cast call $JB_TOKENS "tokenOf(uint256)(address)" $PROJECT_ID --rpc-url $RPC_URL
```

### Get Terminal Balance
```bash
cast call $JB_TERMINAL "currentSurplusOf(uint256,address[],uint256,uint256)" \
    $PROJECT_ID \
    "[$NATIVE_TOKEN]" \
    18 \
    $NATIVE_TOKEN \
    --rpc-url $RPC_URL
```

### Get Splits
```bash
# Reserved token splits (groupId = 1, JBSplitGroupIds.RESERVED_TOKENS)
cast call $JB_SPLITS "splitsOf(uint256,uint256,uint256)" \
    $PROJECT_ID $RULESET_ID 1 \
    --rpc-url $RPC_URL

# Payout splits - groupId = uint256(uint160(token))
# For ETH payouts: groupId = uint256(uint160(0x000000000000000000000000000000000000EEEe))
# The payout split group is derived from the token address being paid out
NATIVE_TOKEN="0x000000000000000000000000000000000000EEEe"
ETH_PAYOUT_GROUP=$(cast --to-uint256 $NATIVE_TOKEN)
cast call $JB_SPLITS "splitsOf(uint256,uint256,uint256)" \
    $PROJECT_ID $RULESET_ID $ETH_PAYOUT_GROUP \
    --rpc-url $RPC_URL

# For USDC payouts (example on mainnet):
USDC_ADDRESS="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
USDC_PAYOUT_GROUP=$(cast --to-uint256 $USDC_ADDRESS)
cast call $JB_SPLITS "splitsOf(uint256,uint256,uint256)" \
    $PROJECT_ID $RULESET_ID $USDC_PAYOUT_GROUP \
    --rpc-url $RPC_URL
```

### Get Token Balance
```bash
cast call $JB_TOKENS "totalBalanceOf(address,uint256)(uint256)" \
    $HOLDER_ADDRESS $PROJECT_ID \
    --rpc-url $RPC_URL
```

## TypeScript Examples (ethers.js)

### Setup
```typescript
import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);

// Contract ABIs (simplified)
const PROJECTS_ABI = ['function ownerOf(uint256) view returns (address)'];
const CONTROLLER_ABI = ['function currentRulesetOf(uint256) view returns (tuple, tuple)'];
const TOKENS_ABI = ['function tokenOf(uint256) view returns (address)'];

const projects = new ethers.Contract(JB_PROJECTS, PROJECTS_ABI, provider);
const controller = new ethers.Contract(JB_CONTROLLER, CONTROLLER_ABI, provider);
const tokens = new ethers.Contract(JB_TOKENS, TOKENS_ABI, provider);
```

### Query Project Info
```typescript
async function getProjectInfo(projectId: number) {
    const owner = await projects.ownerOf(projectId);
    const [ruleset, metadata] = await controller.currentRulesetOf(projectId);
    const tokenAddress = await tokens.tokenOf(projectId);

    return {
        owner,
        ruleset: {
            cycleNumber: ruleset.cycleNumber,
            weight: ruleset.weight,
            duration: ruleset.duration,
        },
        metadata: {
            reservedRate: metadata.reservedRate,
            cashOutTaxRate: metadata.cashOutTaxRate,
            dataHook: metadata.dataHook,
        },
        tokenAddress,
    };
}
```

### Query Token Holders
```typescript
async function getTokenBalance(holder: string, projectId: number) {
    const balance = await tokens.totalBalanceOf(holder, projectId);
    return ethers.formatEther(balance);
}
```

## Common Queries

### "Which contract version does project X use?"
**ALWAYS start here before making any other queries that involve versioned contracts.**
```bash
# Check JBDirectory.controllerOf() - the authoritative source
cast call 0x0061e516886a0540f63157f112c0588ee0651dcf \
  "controllerOf(uint256)(address)" $PROJECT_ID --rpc-url $RPC_URL

# V5.0 controller: 0x27da30646502e2f642be5281322ae8c394f7668a
# V5.1 controller: 0xf3cc99b11bd73a2e3b8815fb85fe0381b29987e1
```
Then use the matching versioned contracts (terminal, rulesets, etc.) for all subsequent queries.

### "What's the current state of project X?"
1. **First**: Get controller version via `JBDirectory.controllerOf(projectId)` - determines which contracts to use
2. Get owner: `JBProjects.ownerOf(projectId)`
3. Get ruleset: Use correct versioned `JBController.currentRulesetOf(projectId)`
4. Get token: `JBTokens.tokenOf(projectId)`
5. Get terminals: `JBDirectory.terminalsOf(projectId)`
6. Get surplus: Use correct versioned `JBMultiTerminal.currentSurplusOf(...)`

### "Who are the split recipients?"
1. Get current ruleset ID from `currentRulesetOf`
2. Query reserved splits: `JBSplits.splitsOf(projectId, rulesetId, 1)` (group 1 = RESERVED_TOKENS)
3. Query payout splits: `JBSplits.splitsOf(projectId, rulesetId, uint256(uint160(token)))`
   - For native token (ETH): group = uint256(uint160(JBConstants.NATIVE_TOKEN))
   - For USDC: group = uint256(uint160(USDC_ADDRESS))

### "How much can be paid out?"
1. Get payout limit: `JBFundAccessLimits.payoutLimitOf(...)`
2. Get used amount: `JBFundAccessLimits.usedPayoutLimitOf(...)`
3. Remaining = limit - used

### "What hooks are configured?"
1. Get ruleset metadata from `currentRulesetOf`
2. Check `useDataHookForPay` and `useDataHookForCashOut`
3. Get hook address from `dataHook`

## Network RPC URLs

| Network | RPC URL |
|---------|---------|
| Ethereum | `https://eth.llamarpc.com` |
| Sepolia | `https://rpc.sepolia.org` |
| Optimism | `https://mainnet.optimism.io` |
| Arbitrum | `https://arb1.arbitrum.io/rpc` |
| Base | `https://mainnet.base.org` |

## Generation Guidelines

1. **Identify the data needed** from user's question
2. **Determine which contracts** to query
3. **Provide cast commands** for quick CLI queries
4. **Provide TypeScript** for programmatic access
5. **Use the /jb-docs skill** to get current contract addresses

## Example Prompts

- "What's the current ruleset for project 123?"
- "Who owns project 456?"
- "How much surplus does project 789 have?"
- "List all payout splits for project 42"
- "What's my token balance in project 100?"


---
Source attribution: modbender
Original project: https://github.com/modbender/skill-library-mcp/blob/d9c8fe903b5b4e82237dbe8d0df8567783022e18/data/juicy/jb-query/SKILL.md
License: MIT
License information: https://opensource.org/license/mit
Original upstream instructions; downloaded from Mega AI Hub.

## Upstream license notice

MIT License

Copyright (c) 2025 skill-library-mcp contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



# Mega AI Hub resource metadata

Creator / publisher: modbender
Original project: https://github.com/modbender/skill-library-mcp/blob/d9c8fe903b5b4e82237dbe8d0df8567783022e18/data/juicy/jb-query/SKILL.md
Attribution basis: Source repository record

Fields of work: Development & Engineering, Product Management
Roles: Backend Developer, Data Engineer, Product Manager
Specialties: API, Backend
Tools: Cast, Ethers.Js
Country applicability: Country not specified
Classification basis: Source catalog labels
Instruction SHA-256: 6c9e11f8acfbdf97b16cf516ae815dd39e1a44a6b0568af343a6a8d362bffb18
