Handle Juicebox V5 multi-currency projects (ETH vs USDC accounting).
Use when: (1) building UI that displays currency labels (ETH vs USDC),
(2) sending transactions that require currency parameter,
(3) configuring fund access limits or accounting contexts for new rulesets,
(4) querying project balance/surplus with correct token,
(5) debugging "wrong currency" issues in payout or allowance transactions,
(6) need currency code constants (NATIVE_CURRENCY=61166, USDC varies by chain),
(7) cash out modal shows wrong return currency (ETH instead of USDC),
(8) need shared chain constants (names, explorers) across multiple modals.
Currency in JBAccountingContext is uint32(uint160(tokenAddress)), NOT 1 or 2.
Covers baseCurrency detection, decimal handling, terminal accounting, currency codes,
dynamic labels, cash out return display, and shared chain constants patterns.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Handle Juicebox V5 multi-currency projects (ETH vs USDC accounting).
Use when: (1) building UI that displays currency labels (ETH vs USDC),
(2) sending transactions that require currency parameter,
(3) configuring fund access limits or accounting contexts for new rulesets,
(4) querying project balance/surplus with correct token,
(5) debugging "wrong currency" issues in payout or allowance transactions,
(6) need currency code constants (NATIVE_CURRENCY=61166, USDC varies by chain),
(7) cash out modal shows wrong return currency (ETH instead of USDC),
(8) need shared chain constants (names, explorers) across multiple modals.
Currency in JBAccountingContext is uint32(uint160(tokenAddress)), NOT 1 or 2.
Covers baseCurrency detection, decimal handling, terminal accounting, currency codes,
dynamic labels, cash out return display, and shared chain constants patterns.
Juicebox V5 Multi-Currency Support
Problem
Juicebox V5 projects can be denominated in either ETH (baseCurrency=1) or USD (baseCurrency=2).
UI components and transactions must use the correct currency value, token address, and display
labels. Hardcoding "ETH" or currency=1 causes failures for USDC-based projects.
Context / Trigger Conditions
UI shows "ETH" when project is USDC-based
Payout or allowance transaction fails silently
Fund access limits set with wrong currency
Currency mismatch between ruleset config and terminal accounting
When queuing new rulesets or displaying limits, match the existing project currency.
Use correct decimals: Query from ERC20.decimals() or use 18 for native tokens.
import { parseUnits } from'viem'// Get currency from existing configconst currency = existingConfig?.baseCurrency || 1// Get decimals from the token contract (or 18 for native token)// For USDC: 6 decimals. For native token (ETH): 18 decimals.const decimals = awaitgetTokenDecimals(tokenAddress, publicClient)
// Use in fund access limit configurationconst payoutLimits = [{
amount: parseUnits(limitAmount, decimals).toString(),
currency, // Match project's base currency (1 or 2)
}]
4. Two Different "currency" Concepts (CRITICAL)
Juicebox V5 has TWO different concepts called "currency" that are often confused:
Field
Location
Values
Purpose
baseCurrency
Ruleset metadata
1 = ETH, 2 = USD
Issuance rate calculation
JBCurrencyAmount.currency
Fund access limits
1 = ETH, 2 = USD
Payout/allowance limits
JBAccountingContext.currency
Terminal config
uint32(uint160(token))
Terminal accounting
The currency value in JBAccountingContext is NOT 1 or 2. It's uint32(uint160(tokenAddress)).
// NATIVE_TOKEN (ETH) - same on all chains - from JBConstants.NATIVE_TOKENconstNATIVE_TOKEN = '0x000000000000000000000000000000000000EEEe'constNATIVE_CURRENCY = 61166// uint32(uint160(NATIVE_TOKEN)) = 0x0000EEEe// USDC addresses and currency codes per chainconstUSDC_CONFIG: Record<number, { address: string; currency: number }> = {
1: { // Ethereumaddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
currency: 909516616,
},
10: { // Optimismaddress: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',
currency: 3530704773,
},
8453: { // Baseaddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
currency: 3169378579,
},
42161: { // Arbitrumaddress: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
currency: 1156540465,
},
}
How to calculate currency from any token address:
const calculateCurrency = (tokenAddress: string): number => {
// Take last 4 bytes of address as uint32returnNumber(BigInt(tokenAddress) & BigInt(0xFFFFFFFF))
}
5. Decimal Handling
General rule: Get decimals from ERC20.decimals() for any token. Native tokens (ETH, MATIC, etc.) always use 18 decimals.
Common cases:
Native token (ETH): 18 decimals
USDC: 6 decimals
Most ERC-20s: varies - always query decimals()
import { erc20Abi } from'viem'// For native tokenconstNATIVE_DECIMALS = 18// For ERC-20 tokens - query the contractconstgetTokenDecimals = async (tokenAddress: string, publicClient: PublicClient) => {
if (tokenAddress === NATIVE_TOKEN) returnNATIVE_DECIMALSreturnawait publicClient.readContract({
address: tokenAddress as`0x${string}`,
abi: erc20Abi,
functionName: 'decimals',
})
}
// Shortcut for known tokens (use with caution)constKNOWN_DECIMALS: Record<string, number> = {
[NATIVE_TOKEN]: 18,
// USDC on all chains uses 6 decimals
}
6. Terminal Accounting Contexts
When configuring terminals, set accounting context to match. The currency MUST be derived from the token address.
When cashing out, users burn project tokens and receive funds in the project's base currency.
The modal must show the correct currency for the return amount:
interfaceCashOutModalProps {
projectId: stringtokenAmount: string// Tokens being burnedtokenSymbol: string// e.g., "NANA", "REV"estimatedReturn: number// Amount user will receivecurrencySymbol: 'ETH' | 'USDC'// CRITICAL: matches project's base currency
}
functionCashOutModal({
tokenAmount,
tokenSymbol,
estimatedReturn,
currencySymbol = 'ETH', // Default to ETH for backwards compatibility
}: CashOutModalProps) {
// Format decimals based on currencyconst decimals = currencySymbol === 'USDC' ? 2 : 4return (
<div><div>Burning: {tokenAmount} {tokenSymbol}</div><div>You receive: ~{estimatedReturn.toFixed(decimals)} {currencySymbol}</div></div>
)
}
Key insight: The component receiving cash out data must pass currencySymbol based on the
project's baseCurrency, not hardcode "ETH". For USDC-based projects, show "~5.00 USDC" not "~0.002 ETH".
8. Shared Chain Constants Pattern
Avoid duplicating chain info across modals. Create a shared constants file: