Metaplex Bubblegum SDK

Rust library for interacting with Metaplex Bublegum program.

## Getting started From your project folder: ```bash cargo add mpl-bubblegum ``` > **Note** > If you are using a `solana-program` version prior to `1.16`, first add the `solana-program` dependency to your project and then add `mpl-bubblegum`. This will make sure you only have a single copy of the `borsh` crate. ## Structure The client SDK is divided into several modules: - `accounts`: structs representing the accounts of the program - `errors`: enums representing the program errors - `instructions`: structs to facilitate the creation of instructions, instruction arguments and CPI instructions - `types`: structs representing types used by the program ## Instruction Builders One of the main features of the client SDK is to facilitate the creation of instructions. There are two "types" of instruction builders automatically generated – both support passing accounts by name and optional positional. ### _Client_ instruction builders This are intended to be used by off-chain client code. Each instruction is represented by a corresponding struct – e.g., `MintV1`: ```rust pub struct MintV1 { pub tree_config: solana_program::pubkey::Pubkey, pub leaf_owner: solana_program::pubkey::Pubkey, pub leaf_delegate: solana_program::pubkey::Pubkey, pub merkle_tree: solana_program::pubkey::Pubkey, pub payer: solana_program::pubkey::Pubkey, pub tree_creator_or_delegate: solana_program::pubkey::Pubkey, pub log_wrapper: solana_program::pubkey::Pubkey, pub compression_program: solana_program::pubkey::Pubkey, pub system_program: solana_program::pubkey::Pubkey, } ``` After filling in the instruction account fields, you can use the `instruction(...)` method to generate the corresponding `solana_program::instruction::Instruction`: ```rust // instruction args let metadata = MetadataArgs { name, uri, creators, ... }; // instruction accounts let mint_ix = MintV1 { tree_config, leaf_owner, leaf_delegate, merkle_tree, payer, tree_creator_or_delegate, log_wrapper: spl_noop::ID, compression_program: spl_account_compression::ID, system_program: system_program::ID, }; // creates the instruction let create_ix = create_ix.instruction( MintV1InstructionArgs { metadata, }); ``` Alternatively, you can use the `MintV1Builder` to create the appropriate instruction: ```rust let mint_ix = MintV1Builder::new() .tree_config(tree_config) .leaf_owner(leaf_owner) .leaf_delegate(leaf_delegate) .merkle_tree(merkle_tree) .payer(payer_pubkey) .tree_creator_or_delegate(tree_creator) .metadata(metadata) .instruction(); ``` ### _CPI_ instruction builders These are builders to be used by on-chain code, which will CPI into Bubblegum. Similarly to "off-chain" builders, each instruction has a struct to invoke CPI instructions – e.g., `MintV1Cpi`: ```rust pub struct MintV1Cpi<'a, 'b> { /// The program to invoke. pub __program: &'b solana_program::account_info::AccountInfo<'a>, pub tree_config: &'b solana_program::account_info::AccountInfo<'a>, pub leaf_owner: &'b solana_program::account_info::AccountInfo<'a>, pub leaf_delegate: &'b solana_program::account_info::AccountInfo<'a>, pub merkle_tree: &'b solana_program::account_info::AccountInfo<'a>, pub payer: &'b solana_program::account_info::AccountInfo<'a>, pub tree_creator_or_delegate: &'b solana_program::account_info::AccountInfo<'a>, pub log_wrapper: &'b solana_program::account_info::AccountInfo<'a>, pub compression_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. pub __args: MintV1InstructionArgs, } ``` After filling in the program, instruction accounts and argument fields, you can use the `invoke()` or `invoke_signed(...)` method to perform the CPI: ```rust // instruction args let metadata = MetadataArgs { name, uri, creators, ... }; // instruction accounts let cpi_mint = MintV1Cpi::new( bubblegum_info, MintV1CpiAccounts { compression_program: spl_account_compression_info, leaf_delegate: authority_info, leaf_owner: authority_info, log_wrapper: spl_noop_info, merkle_tree: merkle_tree_info, payer: payer_info, system_program: system_program_info, tree_config: tree_config_info, tree_creator_or_delegate: delegate_info, }, MintV1InstructionArgs { metadata }, ); // performs the CPI cpi_mint.invoke_signed(&[&signer_seeds]) ``` You can also use the `MintV1CpiBuilder` to simplify the process: ```rust let cpi_mint = MintV1CpiBuilder::new(ctx.accounts.bubblegum) .compression_program(compression_program_info) .leaf_delegate(leaf_delegate_info) .leaf_owner(leaf_owner_info) .log_wrapper(log_wrapper_info) .merkle_tree(merkle_tree_info) .payer(payer_info) .system_program(system_program_info) .tree_config(tree_config_info) .metadata(metadata); // performs the CPI cpi_mint.invoke_signed(&[&signer_seeds]) ``` > **Note** > `*Builder` provide a simplified way to create the required structs, since they take advantage of any default value set on the Kinobi config and do not require to set a `None` value to optional fields. ## PDA helpers Account types (e.g., `TreeConfig`) have associated functions to find PDA or to create PDA `TreeConfig`s: ```rust impl TreeConfig { pub fn create_pda( merkle_tree: Pubkey, bump: u8, ) -> Result { solana_program::pubkey::Pubkey::create_program_address( &[merkle_tree.as_ref(), &[bump]], &crate::MPL_BUBBLEGUM_ID, ) } pub fn find_pda(merkle_tree: &Pubkey) -> (solana_program::pubkey::Pubkey, u8) { solana_program::pubkey::Pubkey::find_program_address( &[merkle_tree.as_ref()], &crate::MPL_BUBBLEGUM_ID, ) } } ``` > If a bump seed is known, it is _cheaper_ (in terms of compute units) to use the `create_pda` function, in particular for on-chain code. ## Testing To run the SDK tests, run the following from the root directory of the repository: ```bash pnpm install ``` and then: ```bash pnpm clients:rust:test ``` ## Documentation The crate documentation can be found [here](https://docs.rs/mpl-bubblegum/latest/mpl_bubblegum/).