-
Notifications
You must be signed in to change notification settings - Fork 69
Batch minting #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Batch minting #113
Conversation
# Conflicts: # programs/bubblegum/program/src/processor/create_tree_with_root.rs
# Conflicts: # programs/bubblegum/program/src/processor/create_tree_with_root.rs # programs/bubblegum/program/tests/rollup.rs # programs/bubblegum/program/tests/utils/tree.rs
# Conflicts: # clients/js/src/generated/instructions/prepareTree.ts # clients/rust/src/generated/instructions/finalize_tree_with_root.rs # idls/bubblegum.json # programs/bubblegum/program/src/processor/finalize_tree_with_root.rs # programs/bubblegum/program/tests/rollup.rs # programs/bubblegum/program/tests/utils/tree.rs
Add canopy size check
# Conflicts: # programs/bubblegum/program/tests/rollup.rs
The reason for adding prep_tree are still unknown, but keeping it for now. As the next steps I'd suggest to get rid of it to keep the styling consistent across bubblegum methods
next steps: - test are really shitty, we need to create test helpers to build this - when the SDK is ready - use it in tests
[MTG-545] feat: update client
…cleanup # Conflicts: # clients/rust/Cargo.lock # clients/rust/Cargo.toml # programs/bubblegum/Cargo.lock # programs/bubblegum/program/Cargo.toml # programs/bubblegum/program/src/processor/create_tree.rs
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
…on is not available on mainnet yet
danenbm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice clean code change, looks good. Left a few comments. Still need to read through the tests though, will review those tomorrow morning.
| codeToErrorMap.set(0x179c, StakingVoterMismatchError); | ||
| nameToErrorMap.set('StakingVoterMismatch', StakingVoterMismatchError); | ||
|
|
||
| /** FeeReceiverMismatch: Fee receiver mismatch */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: It would be nice if some of these new Bubblegum errors were a bit more descriptive. For example, if this one said something more like who the fee receiver is mismatched with.
Like some of the spl-account compression ones have a bit of wording that really helps with the clarity, i.e.:
BatchNotInitializedError: Tree header was not initialized for batch processing
CanopyRootMismatchError: Canopy root does not match the root of the tree
|
|
||
| pub const MAX_ACC_PROOFS_SIZE: u32 = 17; | ||
|
|
||
| // TODO: set real keys before mainnet deploy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I see this looks like it is fixed in #114
| [package] | ||
| name = "bubblegum" | ||
| version = "0.12.0" | ||
| version = "0.13.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we actually normally don't version the program package now given that we don't publish it ever, so you could leave this at 12 unless there's another reason.
| )] | ||
| pub tree_authority: Account<'info, TreeConfig>, | ||
| #[account(mut)] | ||
| /// CHECK: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: no comment detail
| // incoming_tree_delegate is the tree owner as set in prepare tree, it's required to do any modificaitons to the tree, | ||
| // including the canopy setup | ||
| require!( | ||
| incoming_tree_delegate == authority.tree_delegate, | ||
| BubblegumError::TreeAuthorityIncorrect, | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why doesn't this allow authority.tree_creator in addition to authority.tree_delegate?
| export * from './addCanopy'; | ||
| export * from './appendCanopyNodes'; | ||
| export * from './burn'; | ||
| export * from './cancelRedeem'; | ||
| export * from './createTreeConfig'; | ||
| export * from './decompressV1'; | ||
| export * from './delegate'; | ||
| export * from './finalizeTreeWithRoot'; | ||
| export * from './finalizeTreeWithRootAndCollection'; | ||
| export * from './initPreparedTreeWithRoot'; | ||
| export * from './mintToCollectionV1'; | ||
| export * from './mintV1'; | ||
| export * from './prepareBatchMerkleTree'; | ||
| export * from './prepareTree'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these spl-account-compression instructions such as appendCanopyNodes do not need to be included in our JS and Rust clients. They are added by default and can be removed in kinobi. See kinobi.cjs where other spl-account-compression instructions such as append and closeEmptyTree are marked for deletion.
| [package] | ||
| name = "mpl-bubblegum" | ||
| version = "1.4.0" | ||
| version = "1.5.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: you don't need to update this version as cargo release does this as part of our client publish CI.
| solana-program = "^1.14" | ||
| thiserror = "^1.0" | ||
| solana-program = "~1.18.11" | ||
| thiserror = "1.0.63" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Rust client is designed to not require regular Solana program dependency updates. Can it be left at ^1.14 in the client?
|
|
||
| if [ -z ${RPC+x} ]; then | ||
| RPC="https://api.mainnet-beta.solana.com" | ||
| RPC="https://api.devnet.solana.com" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm I think in general we want to be testing with mainnet-beta programs. But I think spl-account-compression you must use the devnet version for this. We did this in mpl-core with the oracle-test-program on devnet, I think we just cloned the script. Can you do that here as well?
| async fn test_cannot_create_tree_needing_too_many_proofs_with_no_canopy() { | ||
| let context = BubblegumTestContext::new().await.unwrap(); | ||
|
|
||
| let tree_create_result = context.create_tree_with_canopy::<19, 64>(1, true).await; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be called with 0 correct?
danenbm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple last comments. There's also some CI failures that need to be fixed. Overall code change looks great. As mentioned before, this is a clean code change. Good documentation and good testing as well.
|
|
||
| Redeeming a cNFT removes the leaf from the Merkle tree and creates a voucher PDA account. The voucher account can be sent to the `decompress_v1` instruction to decompress the cNFT into a Token Metadata NFT. As mentioned above this will cost rent for the Metadata and Master Edition `token-metadata` accounts that are created during the decompression process. Note that after a cNFT is redeemed but before it is decompressed, the process can be reversed using `cancel_redeem`. This puts the cNFT back into the Merkle tree. | ||
|
|
||
| ## Batch-Mint Operations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great README additions!
| // TODO: good luck trying to make it work with those allignment requirements of the WrappedMining struct, | ||
| // let account_type:u8 = mplx_rewards::state::AccountType::Mining.into(); | ||
| // mining_acc_data[0] = account_type; | ||
| // let mining_acc = mplx_rewards::state::WrappedMining::from_bytes_mut(&mut mining_acc_data) | ||
| // .expect("Failed to create mining account"); | ||
| // mining_acc.mining.owner = voter_authority; | ||
| // mining_acc.mining.stake_from_others = 0; | ||
| // so here is a hacky way to set the owner of the mining account directly | ||
| mining_acc_data[32..64].copy_from_slice(&voter_authority.to_bytes()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think this should be resolved or cleaned up with however we want to solve it for the medium/long term, before going into main.
| mplx-staking-states = { git = "https://github.com/metaplex-foundation/aura-staking.git" } | ||
| mplx-rewards = { git = "https://github.com/metaplex-foundation/aura-rewards.git", features = ["no-entrypoint"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these should be published now right?
* feat: use constants from external crate * feat: change after change in imported crate * chore: drop useless error and use into() for type convertion * chore: move keys cast out of runtime * chore: drop unused import
A finalized version of the Bubblegum update for batch minting
Batch operations
As was observed, minting of assets constitutes over 90% of all operations pertaining to digital assets. In order to reduce the number of transactions and optimize the time and cost it takes to put your tree on-chain during the Solana heavy load events Metaplex has introduced the batch-mint operations. The batch extension to the Bubblegum program introduces offline Merkle tree creation, enabling users to prepare and manage Merkle trees offline before finalizing them on-chain. The resulting trees are fully compatible with the regular trees. The snapshot of the tree created is required to be stored off-chain so the replay of the tree creation is possible on any indexer.
Batch-Mint Operations
Introduction
The latest extension to the Bubblegum contract introduces batch-mint operations, allowing users to mint multiple cNFTs in just several transactions, which significantly reduces on-chain overhead and optimizes minting processes for large collections.
How It Works
With the batch-mint operations, users can prepare an entire set of NFTs off-chain, populate them within a Merkle tree structure, and then mint them to the tree in a small number of transactions. This process is designed to handle large-scale NFT collections more efficiently.
Steps to Perform a Batch-Mint
In order to simplify the Merkle tree creation and interactions we recommend using the SDK.
To understand the batch-mint flow, let's recall the structure of a tree data account:
where n is the depth of the canopy.
prepare_treemethod to initialize an account with a tree header and an empty tree body and empty canopy buffer.add_canopymethod is invoked, tree body at this stage stays emptyfinalize_tree_with_rootfor a tree without verified collections orfinalize_tree_with_root_and_collectionfor a tree with one verified collection are used. Signatures from both the tree owner and a designated staker are required.📄
prepare_treePrepare a tree structure that will be used to hold multiple NFTs in a batch-mint operation. This step initializes the tree and allocates the necessary resources for subsequent operations.
Accounts
tree_authorityTreeConfigPDA account that is initialized by this instruction.merkle_treepayertree_creatorlog_wrapperspl-noop) program ID for logging.compression_programspl-account-compressionprogram ID.system_programArguments
max_depthmax_buffer_sizepublic📄
add_canopyAdd an optional canopy to the tree structure. A canopy is used to optimize the verification process for the tree, making it easier to validate NFT ownership.
Accounts
tree_authorityTreeConfigPDA account previously initialized byprepare_tree.merkle_treetree_delegatelog_wrapperspl-noop) program ID for logging.compression_programspl-account-compressionprogram ID.system_programArguments
start_indexcanopy_nodes📄
finalize_tree_with_rootFinalize the tree structure by setting the Merkle root, which represents the entire batch of NFTs. This operation completes the preparation phase and makes the tree ready for usage.
Accounts
tree_authorityTreeConfigPDA account previously initialized byprepare_tree.merkle_treepayertree_delegatestakerregistrarvoterminingfee_receiverlog_wrapperspl-noop) program ID for logging.compression_programspl-account-compressionprogram ID.system_programPubkeys(s) that are 32-byte Keccak256 hash values that represent the nodes for this cNFT's Merkle proof.Arguments
rootrightmost_leafrightmost_index_metadata_url_metadata_hash📄
finalize_tree_with_root_and_collectionFinalize the tree structure by setting the Merkle root and associating it with a specific NFT collection. This operation allows having a verified collection for NFTs in the batch.
Accounts
tree_authorityTreeConfigPDA account previously initialized byprepare_tree.merkle_treepayertree_delegatestakercollection_authorityregistrarvoterminingfee_receivercollection_authority_record_pdacollection_mintcollection_metadataedition_accountlog_wrapperspl-noop) program ID for logging.compression_programspl-account-compressionprogram ID.system_programPubkeys(s) that are 32-byte Keccak256 hash values that represent the nodes for this cNFT's Merkle proof.Arguments
rootrightmost_leafrightmost_index_metadata_url_metadata_hash