Add interactive Bubblegum tree cost calculator with merkle tree visua…#468
Add interactive Bubblegum tree cost calculator with merkle tree visua…#468blockiosaurus merged 3 commits intomainfrom
Conversation
…lization Adds an interactive calculator component to the "Creating Bubblegum Trees" pages for both Bubblegum v1 and v2. The calculator has two modes: - Quick Estimate: enter desired cNFT count, get three cost options (min/balanced/max canopy) - Advanced: manually tune maxDepth, maxBufferSize, and canopyDepth with live cost updates Includes an SVG merkle tree visualization that shows canopy nodes (green), proof nodes (gray), and leaf nodes (blue) updating in real-time as parameters change. Math validated against the SPL Account Compression program: - Account size = header(56) + tree(64 + buf*(40+depth*32) + depth*32) + canopy((2^(cd+1)-2)*32) - Rent = (size + 128) * 6960 lamports - All 33 valid depth/buffer pairs from ALL_DEPTH_SIZE_PAIRS included Added to all 4 locales (en, ja, ko, zh) for both bubblegum and bubblegum-v2. https://claude.ai/code/session_01Q2cQRgz6W8xHbm2TewiHzM
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Summary by CodeRabbit
WalkthroughAdds a new BubblegumCalculator React component, registers a self-closing Markdoc tag Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User as User
participant Browser as Browser/Page
participant Markdoc as Markdoc Renderer
participant Component as BubblegumCalculator
participant Helper as Cost & Visualization Logic
User->>Browser: Open create-trees page
Browser->>Markdoc: Render page content (includes `bubblegum-calculator` tag)
Markdoc->>Component: Instantiate BubblegumCalculator
Component->>Helper: Compute sizes, rent, costs, presets
Helper-->>Component: Return computed metrics
Component-->>Browser: Render UI and visualization
User->>Component: Interact (toggle mode, change target NFTs)
Component->>Helper: Recompute metrics
Helper-->>Component: Updated metrics
Component-->>Browser: Update UI and visualization
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/BubblegumCalculator.jsx`:
- Around line 292-299: In BubblegumCalculator.jsx, the clickable button elements
that call setMode('simple') / setMode('advanced') (the buttons that inspect mode
and use the onClick handler) need an explicit type="button" attribute to prevent
them from acting as implicit submit buttons when this component is placed inside
a form; update each <button> (the ones toggling mode—the group using mode ===
'simple' / mode === 'advanced' and the similar buttons around the 368–376 range)
to include type="button" while keeping the existing onClick and className logic
intact.
- Around line 350-352: Multiple <label> elements in BubblegumCalculator.jsx
aren’t bound to their inputs, breaking accessibility; update each label (e.g.,
the label "How many compressed NFTs do you need?" and the other labels around
lines noted) to be programmatically associated by adding htmlFor attributes that
match unique id attributes on the corresponding input/select elements (or
alternatively wrap the input/select inside the label). Locate the related JSX
for each question/input pair in the BubblegumCalculator component, add stable id
values (e.g., countInput, collectionSelect, feeInput, etc.) to the input/select
elements, and set each label’s htmlFor to that id so screen readers and form
controls are correctly linked.
- Around line 134-135: The SVG in BubblegumCalculator.jsx lacks an accessible
name; wrap a <title> and reference it from the <svg> using aria-labelledby (or
set aria-label) so assistive tech can announce the visualization. In the
BubblegumCalculator component, create a stable title id (use React's useId or
generate one) and render <title id={svgTitleId}>Descriptive name</title> inside
the <svg>, then add aria-labelledby={svgTitleId} (and role="img" if not present)
on the <svg> element so the edges map and visual are announced.
- Around line 300-310: The BubblegumCalculator.jsx component currently hardcodes
UI strings like "Quick Estimate" and "Advanced" (inside the button that calls
setMode and reads mode), which breaks localization; replace these literals with
calls to your localization system (e.g., t('calculator.quickEstimate') /
t('calculator.advanced') or a translations prop) wherever text is hardcoded
(including the other affected spots around the component at the ranges you
noted), updating the JSX to use the localized keys and ensure any aria-labels,
placeholders, and button labels use the same keys so ja/ko/zh docs render
translated copy.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 5c289fb3-5916-403a-9a72-689468e59fba
📒 Files selected for processing (10)
markdoc/tags.jssrc/components/BubblegumCalculator.jsxsrc/pages/en/smart-contracts/bubblegum-v2/create-trees.mdsrc/pages/en/smart-contracts/bubblegum/create-trees.mdsrc/pages/ja/smart-contracts/bubblegum-v2/create-trees.mdsrc/pages/ja/smart-contracts/bubblegum/create-trees.mdsrc/pages/ko/smart-contracts/bubblegum-v2/create-trees.mdsrc/pages/ko/smart-contracts/bubblegum/create-trees.mdsrc/pages/zh/smart-contracts/bubblegum-v2/create-trees.mdsrc/pages/zh/smart-contracts/bubblegum/create-trees.md
MarkSackerberg
left a comment
There was a problem hiding this comment.
Code Rabbit is not wrong with the localization, but besides that fine with me. Numbers match with compressed.app
The Bubblegum program's create_tree instruction validates that canopy depth >= maxDepth - 17 (MAX_ACC_PROOFS_SIZE), rejecting trees that would produce proofs too large for a single Solana transaction. The calculator now enforces these on-chain constraints: - Minimum canopy: max(0, maxDepth - 17) per check_canopy_size - Maximum canopy: min(maxDepth, 17) due to Solana 10MB account limit - Simple mode "Minimum cost" uses the program minimum, not zero - Advanced mode slider respects min/max bounds with warning text - Both v1 and v2 share the same canopy validation logic https://claude.ai/code/session_01Q2cQRgz6W8xHbm2TewiHzM
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/BubblegumCalculator.jsx`:
- Around line 8-45: Replace the hardcoded VALID_DEPTH_BUFFER_PAIRS with the
official tuples from the canonical package (`@solana/spl-account-compression`) so
the component only recommends supported on-chain configurations; import or
reference the package's ALL_DEPTH_SIZE_PAIRS (or the equivalent exported
constant) and assign VALID_DEPTH_BUFFER_PAIRS = ALL_DEPTH_SIZE_PAIRS (or a
filtered copy) and regenerate UNIQUE_DEPTHS from that array (keep UNIQUE_DEPTHS
= [...new Set(VALID_DEPTH_BUFFER_PAIRS.map(p => p.maxDepth))]) so only allowed
maxDepth values (3, 5, 14–20, 24, 26, 30) are used.
- Around line 130-146: The code incorrectly treats the root (level === 0) as
canopy when canopyLevel > 0; update both the node type and edge type assignments
in BubblegumCalculator.jsx so canopy is only applied when level > 0 and level <=
canopyLevel (e.g., replace the current checks that use level < canopyLevel /
level <= canopyLevel / level === canopyLevel with a single condition like level
> 0 && level <= canopyLevel for assigning type and edgeType, referencing the
variables type, edgeType, level, and canopyLevel).
- Around line 309-319: The input handler handleNftInput currently only strips
commas and then uses parseInt, which fails for other locale group separators;
update handleNftInput to normalize the input by removing all non-digit
characters (e.g., raw = e.target.value.replace(/\D/g, '')) before parsing to an
integer, then apply the same validation logic (setDesiredNfts(1) for
invalid/empty, clamp to Math.pow(2,30) if too large, otherwise set the parsed
number); keep the rest of the component (including
value={desiredNfts.toLocaleString()}) unchanged so formatting remains
locale-aware while parsing accepts any locale-specific separators.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b97c71c5-c5f9-4e23-849c-b886932b74b5
📒 Files selected for processing (1)
src/components/BubblegumCalculator.jsx
…rsing - Remove unsupported depth/buffer pairs (depths 6-13) not in SPL ALL_DEPTH_SIZE_PAIRS - Add SVG accessibility: role="img" and descriptive <title> for tree visualization - Add type="button" to all buttons to prevent accidental form submissions - Add htmlFor/id bindings for all form labels and inputs - Fix locale number parsing: replace /,/g with /\D/g to handle all locale separators https://claude.ai/code/session_01Q2cQRgz6W8xHbm2TewiHzM
There was a problem hiding this comment.
♻️ Duplicate comments (2)
src/components/BubblegumCalculator.jsx (2)
88-90:⚠️ Potential issue | 🟠 MajorThe component still isn't localized.
BubblegumCalculatorhas no locale/translation input, the UI copy is still hardcoded in English, and the numeric formatting is tied to the runtime default locale. When this widget is embedded in theja/ko/zhdocs, it still won't match the page language.Suggested direction
-function formatNumber(n) { - return new Intl.NumberFormat().format(n) +function formatNumber(n, locale) { + return new Intl.NumberFormat(locale).format(n) } -export function BubblegumCalculator() { +export function BubblegumCalculator({ locale = 'en', copy = COPY[locale] ?? COPY.en }) { @@ - Quick Estimate + {copy.quickEstimate} @@ - Advanced + {copy.advanced}Based on learnings, localized documentation should translate page body prose while keeping Markdoc component names in English.
Also applies to: 232-338, 386-386
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/BubblegumCalculator.jsx` around lines 88 - 90, The BubblegumCalculator component is not localized: update the component (and helper formatNumber) to accept a locale prop (e.g., locale) and use it when formatting numbers (call Intl.NumberFormat(locale).format) and expose or accept translated UI strings (labels/buttons/placeholders) as props or a translations object so all hardcoded English copy in BubblegumCalculator and formatNumber can be replaced; ensure callers pass the page locale (e.g., "ja"/"ko"/"zh") into BubblegumCalculator and update any internal uses (formatNumber, displayed labels, and button text) to use the provided locale/translation props rather than runtime defaults or hardcoded English.
122-138:⚠️ Potential issue | 🟡 MinorDon't count the root as part of the canopy.
The rent math excludes the root (
2^(n+1)-2), but the visualization still marks level0as canopy whenevercanopyDepth > 0. That overstates the cached canopy by one node and colors one extra edge level.Suggested fix
let type = 'proof' - if (level < canopyLevel) type = 'canopy' - else if (level === canopyLevel && canopyLevel > 0) type = 'canopy' + if (level > 0 && level <= canopyLevel) type = 'canopy' if (level === displayDepth) type = 'leaf' @@ let edgeType = 'proof' - if (level <= canopyLevel) edgeType = 'canopy' + if (level > 0 && level <= canopyLevel) edgeType = 'canopy'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/BubblegumCalculator.jsx` around lines 122 - 138, The visualization is counting level 0 as canopy; update the canopy checks so the root (level === 0) is excluded. Replace the node type logic (currently using if (level < canopyLevel) / else if (level === canopyLevel && canopyLevel > 0)) with a single check that marks canopy only when level > 0 and level <= canopyLevel (while preserving the leaf override for displayDepth), and likewise change the edge type assignment (edgeType = 'canopy') to only apply when level > 0 && level <= canopyLevel so edges from the root are not colored as canopy.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/components/BubblegumCalculator.jsx`:
- Around line 88-90: The BubblegumCalculator component is not localized: update
the component (and helper formatNumber) to accept a locale prop (e.g., locale)
and use it when formatting numbers (call Intl.NumberFormat(locale).format) and
expose or accept translated UI strings (labels/buttons/placeholders) as props or
a translations object so all hardcoded English copy in BubblegumCalculator and
formatNumber can be replaced; ensure callers pass the page locale (e.g.,
"ja"/"ko"/"zh") into BubblegumCalculator and update any internal uses
(formatNumber, displayed labels, and button text) to use the provided
locale/translation props rather than runtime defaults or hardcoded English.
- Around line 122-138: The visualization is counting level 0 as canopy; update
the canopy checks so the root (level === 0) is excluded. Replace the node type
logic (currently using if (level < canopyLevel) / else if (level === canopyLevel
&& canopyLevel > 0)) with a single check that marks canopy only when level > 0
and level <= canopyLevel (while preserving the leaf override for displayDepth),
and likewise change the edge type assignment (edgeType = 'canopy') to only apply
when level > 0 && level <= canopyLevel so edges from the root are not colored as
canopy.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: f9de6b3a-dcca-4282-bb69-31bdcbba07cf
📒 Files selected for processing (1)
src/components/BubblegumCalculator.jsx
…lization
Adds an interactive calculator component to the "Creating Bubblegum Trees" pages for both Bubblegum v1 and v2. The calculator has two modes:
Includes an SVG merkle tree visualization that shows canopy nodes (green), proof nodes (gray), and leaf nodes (blue) updating in real-time as parameters change.
Math validated against the SPL Account Compression program:
Added to all 4 locales (en, ja, ko, zh) for both bubblegum and bubblegum-v2.
https://claude.ai/code/session_01Q2cQRgz6W8xHbm2TewiHzM