[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FXGBT1SW4RVS5HT4FR8T15":3,"skill-same:01M6FXGBT1SW4RVS5HT4FR8T15":69},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":43,"linkOnly":44,"markdownContent":45,"markdownBody":46,"frontMatter":47,"refName":48,"commitSha":49,"skillDirectory":50,"forksCount":51,"repositoryHtmlUrl":52,"repositoryHomepageUrl":6,"ownerHtmlUrl":53,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":54,"install":55,"resources":68},"01M6FXGBT1SW4RVS5HT4FR8T15","jb-multi-currency",null,"Handle Juicebox V5 multi-currency projects (ETH vs USDC accounting).\nUse when: (1) building UI that displays currency labels (ETH vs USDC),\n(2) sending transactions that require currency parameter,\n(3) configuring fund access limits or accounting contexts for new rulesets,\n(4) querying project balance\u002Fsurplus with correct token,\n(5) debugging \"wrong currency\" issues in payout or allowance transactions,\n(6) need currency code constants (NATIVE_CURRENCY=61166, USDC varies by chain),\n(7) cash out modal shows wrong return currency (ETH instead of USDC),\n(8) need shared chain constants (names, explorers) across multiple modals.\nCurrency in JBAccountingContext is uint32(uint160(tokenAddress)), NOT 1 or 2.\nCovers baseCurrency detection, decimal handling, terminal accounting, currency codes,\ndynamic labels, cash out return display, and shared chain constants patterns.","kbarbel640-del\u002Fskills","kbarbel640-del","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F255315490?v=4","01M6CJPPQGCCESXMG3K7BBGQ5J","01M6CJPPX2PB2BCZERFVM2C2B3",1,"MIT","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fmejango\u002Fjuicy\u002Fjb-multi-currency\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000040","财务","PROFESSION","适用职业",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42],"jb multi currency","multi","currency","shared","juicebox v5","balance","with","codes","chain","project","debugging","across","usdc","use","projects","correct","access","transactions","issues","code","2026-11-10 10:12:30",false,"---\nname: jb-multi-currency\ndescription: |\n  Handle Juicebox V5 multi-currency projects (ETH vs USDC accounting).\n  Use when: (1) building UI that displays currency labels (ETH vs USDC),\n  (2) sending transactions that require currency parameter,\n  (3) configuring fund access limits or accounting contexts for new rulesets,\n  (4) querying project balance\u002Fsurplus with correct token,\n  (5) debugging \"wrong currency\" issues in payout or allowance transactions,\n  (6) need currency code constants (NATIVE_CURRENCY=61166, USDC varies by chain),\n  (7) cash out modal shows wrong return currency (ETH instead of USDC),\n  (8) need shared chain constants (names, explorers) across multiple modals.\n  Currency in JBAccountingContext is uint32(uint160(tokenAddress)), NOT 1 or 2.\n  Covers baseCurrency detection, decimal handling, terminal accounting, currency codes,\n  dynamic labels, cash out return display, and shared chain constants patterns.\n---\n\n# Juicebox V5 Multi-Currency Support\n\n## Problem\n\nJuicebox V5 projects can be denominated in either ETH (baseCurrency=1) or USD (baseCurrency=2).\nUI components and transactions must use the correct currency value, token address, and display\nlabels. Hardcoding \"ETH\" or currency=1 causes failures for USDC-based projects.\n\n## Context \u002F Trigger Conditions\n\n- UI shows \"ETH\" when project is USDC-based\n- Payout or allowance transaction fails silently\n- Fund access limits set with wrong currency\n- Currency mismatch between ruleset config and terminal accounting\n- Need to display correct currency symbol in forms\n\n## Solution\n\n### 1. Detect Project Currency from Ruleset\n\n```typescript\n\u002F\u002F baseCurrency is in ruleset metadata\n\u002F\u002F 1 = ETH, 2 = USD (USDC)\nconst baseCurrency = ruleset?.metadata?.baseCurrency || 1\nconst currencyLabel = baseCurrency === 2 ? 'USDC' : 'ETH'\n```\n\n### 2. Use Dynamic Currency in Transactions\n\nWhen calling terminal functions (sendPayoutsOf, useAllowanceOf), use the project's baseCurrency:\n\n```typescript\n\u002F\u002F WRONG - hardcoded\nargs: [projectId, token, amount, 1n, minTokensPaidOut, beneficiary]\n\n\u002F\u002F CORRECT - dynamic\nargs: [projectId, token, amount, BigInt(baseCurrency), minTokensPaidOut, beneficiary]\n```\n\n### 3. Fund Access Limits Currency\n\nWhen queuing new rulesets or displaying limits, match the existing project currency.\n**Use correct decimals**: Query from `ERC20.decimals()` or use 18 for native tokens.\n\n```typescript\nimport { parseUnits } from 'viem'\n\n\u002F\u002F Get currency from existing config\nconst currency = existingConfig?.baseCurrency || 1\n\n\u002F\u002F Get decimals from the token contract (or 18 for native token)\n\u002F\u002F For USDC: 6 decimals. For native token (ETH): 18 decimals.\nconst decimals = await getTokenDecimals(tokenAddress, publicClient)\n\n\u002F\u002F Use in fund access limit configuration\nconst payoutLimits = [{\n  amount: parseUnits(limitAmount, decimals).toString(),\n  currency, \u002F\u002F Match project's base currency (1 or 2)\n}]\n```\n\n### 4. Two Different \"currency\" Concepts (CRITICAL)\n\nJuicebox V5 has TWO different concepts called \"currency\" that are often confused:\n\n| Field | Location | Values | Purpose |\n|-------|----------|--------|---------|\n| `baseCurrency` | Ruleset metadata | 1 = ETH, 2 = USD | Issuance rate calculation |\n| `JBCurrencyAmount.currency` | Fund access limits | 1 = ETH, 2 = USD | Payout\u002Fallowance limits |\n| `JBAccountingContext.currency` | Terminal config | `uint32(uint160(token))` | Terminal accounting |\n\n**The `currency` value in JBAccountingContext is NOT 1 or 2. It's `uint32(uint160(tokenAddress))`.**\n\n```typescript\n\u002F\u002F NATIVE_TOKEN (ETH) - same on all chains - from JBConstants.NATIVE_TOKEN\nconst NATIVE_TOKEN = '0x000000000000000000000000000000000000EEEe'\nconst NATIVE_CURRENCY = 61166 \u002F\u002F uint32(uint160(NATIVE_TOKEN)) = 0x0000EEEe\n\n\u002F\u002F USDC addresses and currency codes per chain\nconst USDC_CONFIG: Record\u003Cnumber, { address: string; currency: number }> = {\n  1: {      \u002F\u002F Ethereum\n    address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n    currency: 909516616,\n  },\n  10: {     \u002F\u002F Optimism\n    address: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n    currency: 3530704773,\n  },\n  8453: {   \u002F\u002F Base\n    address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n    currency: 3169378579,\n  },\n  42161: {  \u002F\u002F Arbitrum\n    address: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n    currency: 1156540465,\n  },\n}\n```\n\n**How to calculate currency from any token address:**\n```typescript\nconst calculateCurrency = (tokenAddress: string): number => {\n  \u002F\u002F Take last 4 bytes of address as uint32\n  return Number(BigInt(tokenAddress) & BigInt(0xFFFFFFFF))\n}\n```\n\n### 5. Decimal Handling\n\n**General rule:** Get decimals from `ERC20.decimals()` for any token. Native tokens (ETH, MATIC, etc.) always use 18 decimals.\n\nCommon cases:\n- Native token (ETH): 18 decimals\n- USDC: 6 decimals\n- Most ERC-20s: varies - always query `decimals()`\n\n```typescript\nimport { erc20Abi } from 'viem'\n\n\u002F\u002F For native token\nconst NATIVE_DECIMALS = 18\n\n\u002F\u002F For ERC-20 tokens - query the contract\nconst getTokenDecimals = async (tokenAddress: string, publicClient: PublicClient) => {\n  if (tokenAddress === NATIVE_TOKEN) return NATIVE_DECIMALS\n  return await publicClient.readContract({\n    address: tokenAddress as `0x${string}`,\n    abi: erc20Abi,\n    functionName: 'decimals',\n  })\n}\n\n\u002F\u002F Shortcut for known tokens (use with caution)\nconst KNOWN_DECIMALS: Record\u003Cstring, number> = {\n  [NATIVE_TOKEN]: 18,\n  \u002F\u002F USDC on all chains uses 6 decimals\n}\n```\n\n### 6. Terminal Accounting Contexts\n\nWhen configuring terminals, set accounting context to match. **The currency MUST be derived from the token address.**\n\n```typescript\n\u002F\u002F ETH-based project\n{\n  terminal: JB_MULTI_TERMINAL,\n  accountingContextsToAccept: [{\n    token: NATIVE_TOKEN,        \u002F\u002F 0x000000000000000000000000000000000000EEEe\n    decimals: 18,\n    currency: 61166,            \u002F\u002F uint32(uint160(NATIVE_TOKEN)) = 0x0000EEEe\n  }]\n}\n\n\u002F\u002F USDC-based project (example: Ethereum)\n{\n  terminal: JB_MULTI_TERMINAL,\n  accountingContextsToAccept: [{\n    token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n    decimals: 6,\n    currency: 909516616,        \u002F\u002F uint32(uint160(USDC_ADDRESS))\n  }]\n}\n```\n\n**WRONG:** Using currency: 1 for ETH or currency: 2 for USD\n**RIGHT:** Using the calculated uint32 value from the token address\n\n## Component Pattern\n\nFor React components that handle multiple currencies:\n\n```typescript\ninterface ChainData {\n  chainId: number\n  projectId: number\n  baseCurrency: number \u002F\u002F 1 = ETH, 2 = USD\n  \u002F\u002F ... other fields\n}\n\nfunction MyComponent({ chainData }: { chainData: ChainData }) {\n  const baseCurrency = chainData?.baseCurrency || 1\n  const currencyLabel = baseCurrency === 2 ? 'USDC' : 'ETH'\n\n  return (\n    \u003Cdiv>\n      \u003Cspan>Amount: {amount} {currencyLabel}\u003C\u002Fspan>\n      {\u002F* Use currencyLabel throughout, never hardcode \"ETH\" *\u002F}\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n### 7. Cash Out Modal Currency Display\n\nWhen cashing out, users burn project tokens and receive funds **in the project's base currency**.\nThe modal must show the correct currency for the return amount:\n\n```typescript\ninterface CashOutModalProps {\n  projectId: string\n  tokenAmount: string      \u002F\u002F Tokens being burned\n  tokenSymbol: string      \u002F\u002F e.g., \"NANA\", \"REV\"\n  estimatedReturn: number  \u002F\u002F Amount user will receive\n  currencySymbol: 'ETH' | 'USDC'  \u002F\u002F CRITICAL: matches project's base currency\n}\n\nfunction CashOutModal({\n  tokenAmount,\n  tokenSymbol,\n  estimatedReturn,\n  currencySymbol = 'ETH',  \u002F\u002F Default to ETH for backwards compatibility\n}: CashOutModalProps) {\n  \u002F\u002F Format decimals based on currency\n  const decimals = currencySymbol === 'USDC' ? 2 : 4\n\n  return (\n    \u003Cdiv>\n      \u003Cdiv>Burning: {tokenAmount} {tokenSymbol}\u003C\u002Fdiv>\n      \u003Cdiv>You receive: ~{estimatedReturn.toFixed(decimals)} {currencySymbol}\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n**Key insight**: The component receiving cash out data must pass `currencySymbol` based on the\nproject's `baseCurrency`, not hardcode \"ETH\". For USDC-based projects, show \"~5.00 USDC\" not \"~0.002 ETH\".\n\n### 8. Shared Chain Constants Pattern\n\nAvoid duplicating chain info across modals. Create a shared constants file:\n\n```typescript\n\u002F\u002F constants\u002Findex.ts\nexport const CHAINS: Record\u003Cnumber, {\n  name: string\n  shortName: string\n  explorerTx: string\n  explorerAddress: string\n}> = {\n  1: {\n    name: 'Ethereum',\n    shortName: 'ETH',\n    explorerTx: 'https:\u002F\u002Fetherscan.io\u002Ftx\u002F',\n    explorerAddress: 'https:\u002F\u002Fetherscan.io\u002Faddress\u002F',\n  },\n  10: {\n    name: 'Optimism',\n    shortName: 'OP',\n    explorerTx: 'https:\u002F\u002Foptimistic.etherscan.io\u002Ftx\u002F',\n    explorerAddress: 'https:\u002F\u002Foptimistic.etherscan.io\u002Faddress\u002F',\n  },\n  8453: {\n    name: 'Base',\n    shortName: 'BASE',\n    explorerTx: 'https:\u002F\u002Fbasescan.org\u002Ftx\u002F',\n    explorerAddress: 'https:\u002F\u002Fbasescan.org\u002Faddress\u002F',\n  },\n  42161: {\n    name: 'Arbitrum',\n    shortName: 'ARB',\n    explorerTx: 'https:\u002F\u002Farbiscan.io\u002Ftx\u002F',\n    explorerAddress: 'https:\u002F\u002Farbiscan.io\u002Faddress\u002F',\n  },\n}\n\nexport const NATIVE_TOKEN = '0x000000000000000000000000000000000000EEEe' as const\n```\n\nThen import in modals:\n```typescript\nimport { CHAINS, NATIVE_TOKEN } from '..\u002Fconstants'\n\nconst chainInfo = CHAINS[chainId] || CHAINS[1]\nconst explorerLink = `${chainInfo.explorerTx}${txHash}`\n```\n\n## Verification\n\n- USDC-based projects display \"USDC\" labels (not \"ETH\")\n- Cash out modals show return in correct currency (ETH or USDC)\n- Transactions use correct currency parameter\n- Fund access limits store correct currency\n- Balance queries use correct token address\n\n## Example\n\nFor Artizen (project 6 on Base):\n- baseCurrency = 2 (USD)\n- Display \"USDC\" in all labels\n- Use USDC token address for balance queries: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`\n- Fund access limits use currency: 2\n\n## Common Mistakes\n\n1. **Hardcoded labels**: Using \"ETH\" string instead of `currencyLabel`\n2. **Hardcoded currency**: Using `1n` instead of `BigInt(baseCurrency)`\n3. **Wrong decimals**: Using 18 decimals for USDC (should be 6)\n4. **Token mismatch**: Querying with NATIVE_TOKEN for USDC project\n\n## Notes\n\n- Default to ETH (baseCurrency=1) if not specified\n- JBSwapTerminal accepts any token and swaps to project's base currency\n- Cash out returns funds in the project's base currency\n- Price feeds convert between currencies when needed\n\n## References\n\n- JBMultiTerminal5_1: `0x52869db3d61dde1e391967f2ce5039ad0ecd371c`\n- JBSwapTerminal: `0x0c02e48e55f4451a499e48a53595de55c40f3574`\n- JBPrices: `0x6e92e3b5ce1e7a4344c6d27c0c54efd00df92fb6`\n","# Juicebox V5 Multi-Currency Support\n\n## Problem\n\nJuicebox V5 projects can be denominated in either ETH (baseCurrency=1) or USD (baseCurrency=2).\nUI components and transactions must use the correct currency value, token address, and display\nlabels. Hardcoding \"ETH\" or currency=1 causes failures for USDC-based projects.\n\n## Context \u002F Trigger Conditions\n\n- UI shows \"ETH\" when project is USDC-based\n- Payout or allowance transaction fails silently\n- Fund access limits set with wrong currency\n- Currency mismatch between ruleset config and terminal accounting\n- Need to display correct currency symbol in forms\n\n## Solution\n\n### 1. Detect Project Currency from Ruleset\n\n```typescript\n\u002F\u002F baseCurrency is in ruleset metadata\n\u002F\u002F 1 = ETH, 2 = USD (USDC)\nconst baseCurrency = ruleset?.metadata?.baseCurrency || 1\nconst currencyLabel = baseCurrency === 2 ? 'USDC' : 'ETH'\n```\n\n### 2. Use Dynamic Currency in Transactions\n\nWhen calling terminal functions (sendPayoutsOf, useAllowanceOf), use the project's baseCurrency:\n\n```typescript\n\u002F\u002F WRONG - hardcoded\nargs: [projectId, token, amount, 1n, minTokensPaidOut, beneficiary]\n\n\u002F\u002F CORRECT - dynamic\nargs: [projectId, token, amount, BigInt(baseCurrency), minTokensPaidOut, beneficiary]\n```\n\n### 3. Fund Access Limits Currency\n\nWhen queuing new rulesets or displaying limits, match the existing project currency.\n**Use correct decimals**: Query from `ERC20.decimals()` or use 18 for native tokens.\n\n```typescript\nimport { parseUnits } from 'viem'\n\n\u002F\u002F Get currency from existing config\nconst currency = existingConfig?.baseCurrency || 1\n\n\u002F\u002F Get decimals from the token contract (or 18 for native token)\n\u002F\u002F For USDC: 6 decimals. For native token (ETH): 18 decimals.\nconst decimals = await getTokenDecimals(tokenAddress, publicClient)\n\n\u002F\u002F Use in fund access limit configuration\nconst payoutLimits = [{\n  amount: parseUnits(limitAmount, decimals).toString(),\n  currency, \u002F\u002F Match project's base currency (1 or 2)\n}]\n```\n\n### 4. Two Different \"currency\" Concepts (CRITICAL)\n\nJuicebox V5 has TWO different concepts called \"currency\" that are often confused:\n\n| Field | Location | Values | Purpose |\n|-------|----------|--------|---------|\n| `baseCurrency` | Ruleset metadata | 1 = ETH, 2 = USD | Issuance rate calculation |\n| `JBCurrencyAmount.currency` | Fund access limits | 1 = ETH, 2 = USD | Payout\u002Fallowance limits |\n| `JBAccountingContext.currency` | Terminal config | `uint32(uint160(token))` | Terminal accounting |\n\n**The `currency` value in JBAccountingContext is NOT 1 or 2. It's `uint32(uint160(tokenAddress))`.**\n\n```typescript\n\u002F\u002F NATIVE_TOKEN (ETH) - same on all chains - from JBConstants.NATIVE_TOKEN\nconst NATIVE_TOKEN = '0x000000000000000000000000000000000000EEEe'\nconst NATIVE_CURRENCY = 61166 \u002F\u002F uint32(uint160(NATIVE_TOKEN)) = 0x0000EEEe\n\n\u002F\u002F USDC addresses and currency codes per chain\nconst USDC_CONFIG: Record\u003Cnumber, { address: string; currency: number }> = {\n  1: {      \u002F\u002F Ethereum\n    address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n    currency: 909516616,\n  },\n  10: {     \u002F\u002F Optimism\n    address: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n    currency: 3530704773,\n  },\n  8453: {   \u002F\u002F Base\n    address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n    currency: 3169378579,\n  },\n  42161: {  \u002F\u002F Arbitrum\n    address: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n    currency: 1156540465,\n  },\n}\n```\n\n**How to calculate currency from any token address:**\n```typescript\nconst calculateCurrency = (tokenAddress: string): number => {\n  \u002F\u002F Take last 4 bytes of address as uint32\n  return Number(BigInt(tokenAddress) & BigInt(0xFFFFFFFF))\n}\n```\n\n### 5. Decimal Handling\n\n**General rule:** Get decimals from `ERC20.decimals()` for any token. Native tokens (ETH, MATIC, etc.) always use 18 decimals.\n\nCommon cases:\n- Native token (ETH): 18 decimals\n- USDC: 6 decimals\n- Most ERC-20s: varies - always query `decimals()`\n\n```typescript\nimport { erc20Abi } from 'viem'\n\n\u002F\u002F For native token\nconst NATIVE_DECIMALS = 18\n\n\u002F\u002F For ERC-20 tokens - query the contract\nconst getTokenDecimals = async (tokenAddress: string, publicClient: PublicClient) => {\n  if (tokenAddress === NATIVE_TOKEN) return NATIVE_DECIMALS\n  return await publicClient.readContract({\n    address: tokenAddress as `0x${string}`,\n    abi: erc20Abi,\n    functionName: 'decimals',\n  })\n}\n\n\u002F\u002F Shortcut for known tokens (use with caution)\nconst KNOWN_DECIMALS: Record\u003Cstring, number> = {\n  [NATIVE_TOKEN]: 18,\n  \u002F\u002F USDC on all chains uses 6 decimals\n}\n```\n\n### 6. Terminal Accounting Contexts\n\nWhen configuring terminals, set accounting context to match. **The currency MUST be derived from the token address.**\n\n```typescript\n\u002F\u002F ETH-based project\n{\n  terminal: JB_MULTI_TERMINAL,\n  accountingContextsToAccept: [{\n    token: NATIVE_TOKEN,        \u002F\u002F 0x000000000000000000000000000000000000EEEe\n    decimals: 18,\n    currency: 61166,            \u002F\u002F uint32(uint160(NATIVE_TOKEN)) = 0x0000EEEe\n  }]\n}\n\n\u002F\u002F USDC-based project (example: Ethereum)\n{\n  terminal: JB_MULTI_TERMINAL,\n  accountingContextsToAccept: [{\n    token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n    decimals: 6,\n    currency: 909516616,        \u002F\u002F uint32(uint160(USDC_ADDRESS))\n  }]\n}\n```\n\n**WRONG:** Using currency: 1 for ETH or currency: 2 for USD\n**RIGHT:** Using the calculated uint32 value from the token address\n\n## Component Pattern\n\nFor React components that handle multiple currencies:\n\n```typescript\ninterface ChainData {\n  chainId: number\n  projectId: number\n  baseCurrency: number \u002F\u002F 1 = ETH, 2 = USD\n  \u002F\u002F ... other fields\n}\n\nfunction MyComponent({ chainData }: { chainData: ChainData }) {\n  const baseCurrency = chainData?.baseCurrency || 1\n  const currencyLabel = baseCurrency === 2 ? 'USDC' : 'ETH'\n\n  return (\n    \u003Cdiv>\n      \u003Cspan>Amount: {amount} {currencyLabel}\u003C\u002Fspan>\n      {\u002F* Use currencyLabel throughout, never hardcode \"ETH\" *\u002F}\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n### 7. Cash Out Modal Currency Display\n\nWhen cashing out, users burn project tokens and receive funds **in the project's base currency**.\nThe modal must show the correct currency for the return amount:\n\n```typescript\ninterface CashOutModalProps {\n  projectId: string\n  tokenAmount: string      \u002F\u002F Tokens being burned\n  tokenSymbol: string      \u002F\u002F e.g., \"NANA\", \"REV\"\n  estimatedReturn: number  \u002F\u002F Amount user will receive\n  currencySymbol: 'ETH' | 'USDC'  \u002F\u002F CRITICAL: matches project's base currency\n}\n\nfunction CashOutModal({\n  tokenAmount,\n  tokenSymbol,\n  estimatedReturn,\n  currencySymbol = 'ETH',  \u002F\u002F Default to ETH for backwards compatibility\n}: CashOutModalProps) {\n  \u002F\u002F Format decimals based on currency\n  const decimals = currencySymbol === 'USDC' ? 2 : 4\n\n  return (\n    \u003Cdiv>\n      \u003Cdiv>Burning: {tokenAmount} {tokenSymbol}\u003C\u002Fdiv>\n      \u003Cdiv>You receive: ~{estimatedReturn.toFixed(decimals)} {currencySymbol}\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n**Key insight**: The component receiving cash out data must pass `currencySymbol` based on the\nproject's `baseCurrency`, not hardcode \"ETH\". For USDC-based projects, show \"~5.00 USDC\" not \"~0.002 ETH\".\n\n### 8. Shared Chain Constants Pattern\n\nAvoid duplicating chain info across modals. Create a shared constants file:\n\n```typescript\n\u002F\u002F constants\u002Findex.ts\nexport const CHAINS: Record\u003Cnumber, {\n  name: string\n  shortName: string\n  explorerTx: string\n  explorerAddress: string\n}> = {\n  1: {\n    name: 'Ethereum',\n    shortName: 'ETH',\n    explorerTx: 'https:\u002F\u002Fetherscan.io\u002Ftx\u002F',\n    explorerAddress: 'https:\u002F\u002Fetherscan.io\u002Faddress\u002F',\n  },\n  10: {\n    name: 'Optimism',\n    shortName: 'OP',\n    explorerTx: 'https:\u002F\u002Foptimistic.etherscan.io\u002Ftx\u002F',\n    explorerAddress: 'https:\u002F\u002Foptimistic.etherscan.io\u002Faddress\u002F',\n  },\n  8453: {\n    name: 'Base',\n    shortName: 'BASE',\n    explorerTx: 'https:\u002F\u002Fbasescan.org\u002Ftx\u002F',\n    explorerAddress: 'https:\u002F\u002Fbasescan.org\u002Faddress\u002F',\n  },\n  42161: {\n    name: 'Arbitrum',\n    shortName: 'ARB',\n    explorerTx: 'https:\u002F\u002Farbiscan.io\u002Ftx\u002F',\n    explorerAddress: 'https:\u002F\u002Farbiscan.io\u002Faddress\u002F',\n  },\n}\n\nexport const NATIVE_TOKEN = '0x000000000000000000000000000000000000EEEe' as const\n```\n\nThen import in modals:\n```typescript\nimport { CHAINS, NATIVE_TOKEN } from '..\u002Fconstants'\n\nconst chainInfo = CHAINS[chainId] || CHAINS[1]\nconst explorerLink = `${chainInfo.explorerTx}${txHash}`\n```\n\n## Verification\n\n- USDC-based projects display \"USDC\" labels (not \"ETH\")\n- Cash out modals show return in correct currency (ETH or USDC)\n- Transactions use correct currency parameter\n- Fund access limits store correct currency\n- Balance queries use correct token address\n\n## Example\n\nFor Artizen (project 6 on Base):\n- baseCurrency = 2 (USD)\n- Display \"USDC\" in all labels\n- Use USDC token address for balance queries: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`\n- Fund access limits use currency: 2\n\n## Common Mistakes\n\n1. **Hardcoded labels**: Using \"ETH\" string instead of `currencyLabel`\n2. **Hardcoded currency**: Using `1n` instead of `BigInt(baseCurrency)`\n3. **Wrong decimals**: Using 18 decimals for USDC (should be 6)\n4. **Token mismatch**: Querying with NATIVE_TOKEN for USDC project\n\n## Notes\n\n- Default to ETH (baseCurrency=1) if not specified\n- JBSwapTerminal accepts any token and swaps to project's base currency\n- Cash out returns funds in the project's base currency\n- Price feeds convert between currencies when needed\n\n## References\n\n- JBMultiTerminal5_1: `0x52869db3d61dde1e391967f2ce5039ad0ecd371c`\n- JBSwapTerminal: `0x0c02e48e55f4451a499e48a53595de55c40f3574`\n- JBPrices: `0x6e92e3b5ce1e7a4344c6d27c0c54efd00df92fb6`\n",{"name":5,"description":7},"main","e7e336ac628c3e3bd771aff1aaa469c93778f94a","skills\u002Fmejango\u002Fjuicy\u002Fjb-multi-currency",0,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del","2026-08-23 22:39:37",{"source":8,"skillName":5,"commands":56,"prompt":66,"zipAvailable":67},[57,60,63],{"tool":58,"command":59},"npx","npx skills add kbarbel640-del\u002Fskills --skill jb-multi-currency",{"tool":61,"command":62},"bunx","bunx skills add kbarbel640-del\u002Fskills --skill jb-multi-currency",{"tool":64,"command":65},"pnpm","pnpm dlx skills add kbarbel640-del\u002Fskills --skill jb-multi-currency","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fmejango\u002Fjuicy\u002Fjb-multi-currency\u002FSKILL.md",true,[],[70,98,126,147,153,173],{"skillNo":71,"name":72,"nameZh":6,"description":73,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":79,"publishedAt":43},"01M6G8J55967D6281ACMKAKTEQ","crowd-prompting","A marketplace where AI agents improve prompts, system instructions, tool descriptions, and other text-based content with domain expertise from real-world operations — and earn tokens for valuable contributions.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzzadrian\u002Fcrowd-prompting\u002FSKILL.md",[76],{"categoryNo":77,"categoryName":78,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000036","内容创作者",[80,81,82,29,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97],"crowd prompting","prompting","api","tokens","domain","world","prompts","operations","instructions","text","tool","system","improve","productivity","marketplace","https","content","ai agents",{"skillNo":99,"name":100,"nameZh":6,"description":101,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":109,"publishedAt":43},"01M6G8J0PKPAYVET6BWE8W4C26","dilemm-ai","Compete in DilemmAI, the prisoner's dilemma AI arena at dilemm.ai. Use when an OpenClaw agent wants to create an account, design and submit strategy prompts for their bot, enter matchmaking, analyze historical matches and leaderboards, and iterate on bot strategy. Requires headless browser automation (no API available yet).","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzyori\u002Fdilemm-ai\u002FSKILL.md",[104],{"categoryNo":105,"categoryName":106,"taxonomyType":107,"taxonomyTypeDesc":108},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[110,82,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,86,36],"dilemm ai","arena","analyze","browser","openclaw agent","create","automation","browser automation","bot","openclaw","design","strategy","headless","compete","submit","matchmaking",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":135,"publishedAt":43},"01M6G8HWAF3K9SW7NP3Z83CPJ6","arxiv-paper-reviews","Interact with arXiv Crawler API to fetch papers, read reviews, and submit comments. Use when working with arXiv papers, fetching paper lists by date\u002Fcategory\u002Finterest, viewing paper details with comments, or submitting paper reviews via API at http:\u002F\u002F150.158.152.82:8000.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Fweak-accept\u002FSKILL.md",[132],{"categoryNo":133,"categoryName":134,"taxonomyType":107,"taxonomyTypeDesc":108},"01JBSEEDCAT000000000000021","资料检索与研究",[136,137,138,139,140,141,142,29,143,124,36,144,82,145,146],"arxiv paper reviews","reviews","arxiv","paper","crawler","papers","comments","fetch","read","http","via",{"skillNo":148,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":149,"categories":150,"keywords":152,"publishedAt":43},"01M6G8HQJ7N7WMY6YV7D7SSJ16","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Farxiv-paper-reviews\u002FSKILL.md",[151],{"categoryNo":133,"categoryName":134,"taxonomyType":107,"taxonomyTypeDesc":108},[139,138,137,136,146,141,142,29,140,124,36,143,144,82,145],{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":157,"categories":158,"keywords":159,"publishedAt":43},"01M6G8HM95Y64JNVFC2HN4E2BG","git-summary","Get a quick summary of the current Git repository including status, recent commits, branches, and contributors.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzweack\u002Fgit-summary\u002FSKILL.md",[],[160,161,162,163,164,165,166,167,168,169,170,171,172],"git","summary","git summary","commits","repository","win32","status","linux","contributors","true","quick","get","branches",{"skillNo":174,"name":175,"nameZh":6,"description":176,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":177,"categories":178,"keywords":183,"publishedAt":43},"01M6G8HGEGF05CNEJCGVYFSC4R","agent-constitution","Interact with AgentConstitution governance contracts on Base Sepolia. Check compliance, read rules, log actions, query governance state.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fztsalexey\u002Fagent-constitution\u002FSKILL.md",[179,180],{"categoryNo":105,"categoryName":106,"taxonomyType":107,"taxonomyTypeDesc":108},{"categoryNo":181,"categoryName":182,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000037","律师与法务",[184,185,186,187,29,188,189,48,190,144,191,192,37,193,194,95,195,196,197],"agent constitution","constitution","contracts","tree","query","base","log","check","Rules","compliance","actions","state","governance","github"]