-
Notifications
You must be signed in to change notification settings - Fork 45
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
Batch minting #113
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
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
@@ -12,6 +12,21 @@ pub const VOUCHER_PREFIX: &str = "voucher"; | |||
pub const ASSET_PREFIX: &str = "asset"; | |||
pub const COLLECTION_CPI_PREFIX: &str = "collection_cpi"; | |||
|
|||
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
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.
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?
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?
@@ -276,6 +273,26 @@ async fn test_cannot_create_tree_needing_too_many_proofs_with_too_small_canopy() | |||
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?
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.
@@ -72,6 +77,52 @@ Compressed NFTs support transferring ownership, delegating authority, and burnin | |||
|
|||
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_tree
method to initialize an account with a tree header and an empty tree body and empty canopy buffer.add_canopy
method is invoked, tree body at this stage stays emptyfinalize_tree_with_root
for a tree without verified collections orfinalize_tree_with_root_and_collection
for a tree with one verified collection are used. Signatures from both the tree owner and a designated staker are required.📄
prepare_tree
Prepare 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_authority
TreeConfig
PDA account that is initialized by this instruction.merkle_tree
payer
tree_creator
log_wrapper
spl-noop
) program ID for logging.compression_program
spl-account-compression
program ID.system_program
Arguments
max_depth
max_buffer_size
public
📄
add_canopy
Add 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_authority
TreeConfig
PDA account previously initialized byprepare_tree
.merkle_tree
tree_delegate
log_wrapper
spl-noop
) program ID for logging.compression_program
spl-account-compression
program ID.system_program
Arguments
start_index
canopy_nodes
📄
finalize_tree_with_root
Finalize 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_authority
TreeConfig
PDA account previously initialized byprepare_tree
.merkle_tree
payer
tree_delegate
staker
registrar
voter
mining
fee_receiver
log_wrapper
spl-noop
) program ID for logging.compression_program
spl-account-compression
program ID.system_program
Pubkeys
(s) that are 32-byte Keccak256 hash values that represent the nodes for this cNFT's Merkle proof.Arguments
root
rightmost_leaf
rightmost_index
_metadata_url
_metadata_hash
📄
finalize_tree_with_root_and_collection
Finalize 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_authority
TreeConfig
PDA account previously initialized byprepare_tree
.merkle_tree
payer
tree_delegate
staker
collection_authority
registrar
voter
mining
fee_receiver
collection_authority_record_pda
collection_mint
collection_metadata
edition_account
log_wrapper
spl-noop
) program ID for logging.compression_program
spl-account-compression
program ID.system_program
Pubkeys
(s) that are 32-byte Keccak256 hash values that represent the nodes for this cNFT's Merkle proof.Arguments
root
rightmost_leaf
rightmost_index
_metadata_url
_metadata_hash