use crate::{
primitives::{DeployedData, NFTMetadata},
SolanaAgentKit,
};
use mpl_token_metadata::{
instructions::{CreateMasterEditionV3, CreateMetadataAccountV3, CreateMetadataAccountV3InstructionArgs},
types::{Collection, DataV2},
};
use solana_client::client_error::ClientError;
use solana_sdk::{
program_pack::Pack,
pubkey::Pubkey,
signature::{Keypair, Signer},
sysvar,
transaction::Transaction,
};
pub async fn mint_nft_to_collection(
agent: &SolanaAgentKit,
collection: Pubkey,
metadata: NFTMetadata,
) -> Result<DeployedData, ClientError> {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let min_rent = agent.connection.get_minimum_balance_for_rent_exemption(spl_token::state::Mint::LEN)?;
let metadata_seeds = &["metadata".as_bytes(), mpl_token_metadata::ID.as_ref(), mint_pubkey.as_ref()];
let (metadata_account, _) = Pubkey::find_program_address(metadata_seeds, &mpl_token_metadata::ID);
let create_mint_account_ix = solana_sdk::system_instruction::create_account(
&agent.wallet.address,
&mint_pubkey,
min_rent,
82,
&spl_token::id(),
);
let init_mint_ix = spl_token::instruction::initialize_mint(
&spl_token::id(),
&mint_pubkey,
&agent.wallet.address,
Some(&agent.wallet.address),
0,
)
.expect("initialize_mint");
let associated_token_account =
spl_associated_token_account::get_associated_token_address(&agent.wallet.address, &mint_pubkey);
let create_assoc_account_ix = spl_associated_token_account::instruction::create_associated_token_account(
&agent.wallet.address,
&agent.wallet.address,
&mint_pubkey,
&spl_token::id(),
);
let mint_to_ix = spl_token::instruction::mint_to(
&spl_token::id(),
&mint_pubkey,
&associated_token_account,
&agent.wallet.address,
&[&agent.wallet.address],
1,
)
.expect("mint_to");
let create_metadata_ix = CreateMetadataAccountV3 {
metadata: metadata_account,
mint: mint_pubkey,
mint_authority: agent.wallet.address,
payer: agent.wallet.address,
update_authority: (agent.wallet.address, false),
system_program: solana_program::system_program::id(),
rent: Some(sysvar::rent::id()),
}
.instruction(CreateMetadataAccountV3InstructionArgs {
data: DataV2 {
name: metadata.name.clone(),
symbol: "SOLAGENT".to_string(),
uri: metadata.uri.clone(),
seller_fee_basis_points: metadata.basis_points.unwrap_or(0),
creators: metadata.creators,
collection: Some(Collection { verified: false, key: collection }),
uses: None,
},
is_mutable: true,
collection_details: None,
});
let master_edition_seeds =
&["metadata".as_bytes(), mpl_token_metadata::ID.as_ref(), mint_pubkey.as_ref(), "edition".as_bytes()];
let (master_edition_account, _) = Pubkey::find_program_address(master_edition_seeds, &mpl_token_metadata::ID);
let create_master_edition_ix = CreateMasterEditionV3 {
edition: master_edition_account,
mint: mint_pubkey,
update_authority: agent.wallet.address,
mint_authority: agent.wallet.address,
payer: agent.wallet.address,
metadata: metadata_account,
token_program: spl_token::id(),
system_program: solana_program::system_program::id(),
rent: Some(sysvar::rent::id()),
}
.instruction(mpl_token_metadata::instructions::CreateMasterEditionV3InstructionArgs { max_supply: Some(1) });
use mpl_token_metadata::instructions::VerifyCollection;
let collection_metadata_seeds = &["metadata".as_bytes(), mpl_token_metadata::ID.as_ref(), collection.as_ref()];
let (collection_metadata_account, _) =
Pubkey::find_program_address(collection_metadata_seeds, &mpl_token_metadata::ID);
let collection_master_edition_seeds =
&["metadata".as_bytes(), mpl_token_metadata::ID.as_ref(), collection.as_ref(), "edition".as_bytes()];
let (collection_master_edition_account, _) =
Pubkey::find_program_address(collection_master_edition_seeds, &mpl_token_metadata::ID);
let verify_collection_ix = VerifyCollection {
metadata: metadata_account,
collection_authority: agent.wallet.address,
payer: agent.wallet.address,
collection_mint: collection,
collection: collection_metadata_account,
collection_master_edition_account,
collection_authority_record: None,
}
.instruction();
let recent_blockhash = agent.connection.get_latest_blockhash()?;
let transaction = Transaction::new_signed_with_payer(
&[
create_mint_account_ix,
init_mint_ix,
create_assoc_account_ix,
mint_to_ix,
create_metadata_ix,
create_master_edition_ix,
verify_collection_ix,
],
Some(&agent.wallet.address),
&[&agent.wallet.wallet, &mint_keypair],
recent_blockhash,
);
let signature = agent.connection.send_and_confirm_transaction(&transaction)?;
Ok(DeployedData { mint: mint_pubkey.to_string(), signature: signature.to_string() })
}