Skip to content

feat: add decompress_v2 to convert Bubblegum v2 leaves into MPL Core assets - #159

Draft
blockiosaurus wants to merge 2 commits into
mainfrom
claude/bubblegum-decompress-core-ZJRx9
Draft

feat: add decompress_v2 to convert Bubblegum v2 leaves into MPL Core assets#159
blockiosaurus wants to merge 2 commits into
mainfrom
claude/bubblegum-decompress-core-ZJRx9

Conversation

@blockiosaurus

Copy link
Copy Markdown
Contributor

Adds a decompress_v2 instruction that lets the holder of a v2 compressed
leaf turn it into a regular MPL Core asset that lives in the same MPL Core
collection the leaf was associated with. Verifies the leaf via merkle proof,
zeroes it in the tree (same path as burn_v2), then CPIs into mpl-core to
decrement the compressed-asset counter and create the new asset.

Requires the matching mpl-core change so the bubblegum cpi-signer PDA is
authorized to create assets into a collection gated by the BubblegumV2
plugin. Without that change, the CreateV2 CPI will be rejected at runtime
by mpl-core's collection authority check.

https://claude.ai/code/session_01PpQaFSbCYHCqsTb2hwuBwq

…assets

Adds a `decompress_v2` instruction that lets the holder of a v2 compressed
leaf turn it into a regular MPL Core asset that lives in the same MPL Core
collection the leaf was associated with. Verifies the leaf via merkle proof,
zeroes it in the tree (same path as burn_v2), then CPIs into mpl-core to
decrement the compressed-asset counter and create the new asset.

Requires the matching mpl-core change so the bubblegum cpi-signer PDA is
authorized to create assets into a collection gated by the BubblegumV2
plugin. Without that change, the CreateV2 CPI will be rejected at runtime
by mpl-core's collection authority check.

https://claude.ai/code/session_01PpQaFSbCYHCqsTb2hwuBwq
@vercel

vercel Bot commented Apr 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mpl-bubblegum-js-docs Ready Ready Preview, Comment Apr 26, 2026 4:11pm

Request Review

@coderabbitai

coderabbitai Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a98d532f-75f0-4d30-99ea-dfa2b9716231

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds a new V2 decompression instruction to the Bubblegum program. The instruction includes a new identifier and program entrypoint in the main library file, alongside processor logic that validates ownership, handles V2-specific metadata, manages merkle tree operations, and coordinates with MPL Core for asset creation.

Changes

Cohort / File(s) Summary
Instruction Interface
programs/bubblegum/program/src/lib.rs
Added DecompressV2 instruction identifier variant and new public program entrypoint decompress_v2 that accepts V2-specific metadata arguments including MetadataArgsV2, optional asset data hash, and optional flags.
V2 Decompression Logic
programs/bubblegum/program/src/processor/decompress.rs
Added DecompressV2 accounts struct and decompress_v2 function implementing V2-only tree validation, owner/delegate authorization, leaf hashing/reconstruction, merkle tree leaf burning, MPL Core collection verification with plugin requirements, royalty plugin assembly, and CPIs for collection counter decrement and asset materialization.

Sequence Diagram(s)

sequenceDiagram
    actor Caller
    participant BubblegumProgram as Bubblegum Program
    participant MerkleTree as Merkle Tree
    participant MPLCore as MPL Core
    
    Caller->>BubblegumProgram: decompress_v2(root, nonce, index, metadata, ...)
    
    BubblegumProgram->>BubblegumProgram: Validate caller is owner/delegate
    BubblegumProgram->>BubblegumProgram: Verify V2 tree
    BubblegumProgram->>BubblegumProgram: Validate metadata collection
    
    BubblegumProgram->>BubblegumProgram: Hash/reconstruct V2 leaf
    BubblegumProgram->>MerkleTree: Verify leaf proof & burn leaf
    MerkleTree-->>BubblegumProgram: Leaf verified & removed
    
    BubblegumProgram->>MPLCore: Verify collection has BubblegumV2 plugin
    MPLCore-->>BubblegumProgram: Plugin verified
    
    BubblegumProgram->>BubblegumProgram: Assemble royalty plugins
    
    BubblegumProgram->>MPLCore: CPI to decrement collection counter
    MPLCore-->>BubblegumProgram: Counter decremented
    
    BubblegumProgram->>MPLCore: CPI to create asset with plugins
    MPLCore-->>BubblegumProgram: Asset created
    
    BubblegumProgram->>BubblegumProgram: Emit V2 leaf event
    BubblegumProgram-->>Caller: Success
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: adding a decompress_v2 instruction to convert Bubblegum v2 leaves into MPL Core assets.
Description check ✅ Passed The description is directly related to the changeset, explaining the purpose of the new decompress_v2 instruction, its workflow, and dependencies with clear technical details.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/bubblegum-decompress-core-ZJRx9

Comment @coderabbitai help to get the list of available commands and usage tips.

@blockiosaurus
blockiosaurus marked this pull request as draft April 26, 2026 15:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@programs/bubblegum/program/src/processor/decompress.rs`:
- Around line 425-457: The CreateV2CpiBuilder call in decompress.rs currently
sets owner but never sets a delegate, so any delegate on the compressed leaf is
dropped during materialization; either preserve the delegate by reading the
leaf's delegate and passing it into CreateV2CpiBuilder::delegate(...) (using the
same ctx.accounts/new_asset and any relevant leaf metadata), or if you intend to
drop delegations, add a clear note to the decompress instruction's docstring (in
the function that performs the materialization) stating that delegate
authorization on compressed assets is not preserved when creating the Core
asset; reference CreateV2CpiBuilder, .owner(...), and add or use .delegate(...)
or the docstring in the decompress function accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: af7c0262-29b0-4349-a9ed-548823a5a22d

📥 Commits

Reviewing files that changed from the base of the PR and between e9fde97 and 3446636.

📒 Files selected for processing (2)
  • programs/bubblegum/program/src/lib.rs
  • programs/bubblegum/program/src/processor/decompress.rs

Comment on lines +425 to +457
// Decrement the compressed-asset counter on the collection. The matching
// increment for the materialized Core asset happens inside CreateV2 itself.
UpdateCollectionInfoV1CpiBuilder::new(&ctx.accounts.mpl_core_program)
.collection(&ctx.accounts.core_collection)
.bubblegum_signer(&ctx.accounts.mpl_core_cpi_signer)
.update_type(UpdateType::Remove)
.amount(1)
.invoke_signed(&[&[
MPL_CORE_CPI_SIGNER_PREFIX.as_bytes(),
&[ctx.bumps.mpl_core_cpi_signer],
]])?;

// Materialize the Core asset inside the same collection. The bubblegum cpi
// signer is passed as the `authority` so collections gated by the
// BubblegumV2 plugin can authorize the create. NOTE: requires a matching
// mpl-core change that recognizes the bubblegum cpi signer for CreateV2 on
// a BubblegumV2-plugged collection (see PR description).
CreateV2CpiBuilder::new(&ctx.accounts.mpl_core_program)
.asset(&ctx.accounts.new_asset)
.collection(Some(&ctx.accounts.core_collection))
.authority(Some(&ctx.accounts.mpl_core_cpi_signer))
.payer(&ctx.accounts.payer)
.owner(Some(&ctx.accounts.leaf_owner))
.system_program(&ctx.accounts.system_program)
.log_wrapper(Some(&ctx.accounts.log_wrapper))
.data_state(DataState::AccountState)
.name(metadata.name.clone())
.uri(metadata.uri.clone())
.plugins(plugins)
.invoke_signed(&[&[
MPL_CORE_CPI_SIGNER_PREFIX.as_bytes(),
&[ctx.bumps.mpl_core_cpi_signer],
]])?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Delegate not preserved on decompressed asset.

The CreateV2CpiBuilder sets owner but does not set a delegate. If a leaf had a delegate, that delegation is lost post-decompression. This appears intentional (delegate authorization was for the compressed asset, not the new Core asset), but consider documenting this behavior in the instruction's docstring.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@programs/bubblegum/program/src/processor/decompress.rs` around lines 425 -
457, The CreateV2CpiBuilder call in decompress.rs currently sets owner but never
sets a delegate, so any delegate on the compressed leaf is dropped during
materialization; either preserve the delegate by reading the leaf's delegate and
passing it into CreateV2CpiBuilder::delegate(...) (using the same
ctx.accounts/new_asset and any relevant leaf metadata), or if you intend to drop
delegations, add a clear note to the decompress instruction's docstring (in the
function that performs the materialization) stating that delegate authorization
on compressed assets is not preserved when creating the Core asset; reference
CreateV2CpiBuilder, .owner(...), and add or use .delegate(...) or the docstring
in the decompress function accordingly.

…ient and tests

Program changes:
* Carry the leaf delegate over to the new Core asset as TransferDelegate +
  BurnDelegate plugins (a Bubblegum leaf delegate can do both).
* Carry the leaf-level frozen flag over as FreezeDelegate { frozen: true },
  scoped to the leaf delegate so they retain thaw authority. Only reject
  collection-permanent-frozen and non-transferable leaves (no clean Core
  primitive for those).

JS:
* Add decompressV2 instruction client (mirrors the kinobi-generated style).
* Re-export from generated/instructions/index.
* Add a decompressV2 ava test suite covering:
  - happy path (owner decompress, asset lands in same collection)
  - leaf delegate as authority
  - non-owner / non-delegate rejection
  - collection mismatch / leaf without collection
  - delegate preservation (TransferDelegate + BurnDelegate plugins)
  - frozen state preservation (FreezeDelegate plugin)
  - soulbound + collection-permanent-frozen rejection
  - royalties / creator splits preservation
  - v1 tree rejection
  - tampered metadata, double-decompress
  - payer / leafAuthority separation

https://claude.ai/code/session_01PpQaFSbCYHCqsTb2hwuBwq
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants