From 3289c1d6d92712484603426aaa7b47f823d940db Mon Sep 17 00:00:00 2001 From: Sofia <62249700+sp-sofi@users.noreply.github.com> Date: Sat, 27 Apr 2024 14:44:10 +0300 Subject: [PATCH 1/2] add lib.rs and client --- client.ts | 80 ++++++++++++++++++++++++++++ lib.rs | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 client.ts create mode 100644 lib.rs diff --git a/client.ts b/client.ts new file mode 100644 index 0000000..1aac8d5 --- /dev/null +++ b/client.ts @@ -0,0 +1,80 @@ +import BN from "bn.js"; +import * as web3 from "@solana/web3.js"; +import * as anchor from "@coral-xyz/anchor"; +import type { NftProgram } from "../target/types/nft_program"; + +// Configure the client to use the local cluster +anchor.setProvider(anchor.AnchorProvider.env()); + +const program = anchor.workspace.NftProgram as anchor.Program; + + +const TOKEN_METADATA_PROGRAM_ID = new anchor.web3.PublicKey( + "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" + ); + + // const mintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate(); + const mintKeypair: anchor.web3.PublicKey = new anchor.web3.PublicKey( + "51kVaJaEU1qs4NwfTAH6b7GWprVCBYWtLSHNKQxY4B1" + ); + const tokenAddress = await anchor.utils.token.associatedAddress({ + mint: mintKeypair, + owner: program.provider.publicKey, + }); + console.log(`New token: ${mintKeypair}`); + + // Derive the metadata and master edition addresses + + const metadataAddress = ( + anchor.web3.PublicKey.findProgramAddressSync( + [ + Buffer.from("metadata"), + TOKEN_METADATA_PROGRAM_ID.toBuffer(), + mintKeypair.toBuffer(), + ], + TOKEN_METADATA_PROGRAM_ID + ) + )[0]; + console.log("Metadata initialized"); + const masterEditionAddress = anchor.web3.PublicKey.findProgramAddressSync( + [ + Buffer.from("metadata"), + TOKEN_METADATA_PROGRAM_ID.toBuffer(), + mintKeypair.toBuffer(), + Buffer.from("edition"), + ], + TOKEN_METADATA_PROGRAM_ID + )[0]; + console.log("Master edition metadata initialized"); + + try { + await program.methods + .createSingleNft( + new BN(1), + "Prochna-Sofia-nft", + "PNFT", + "https://run.mocky.io/v3/9586fda8-b711-42a7-9dae-6b774d207bc4", + 0.01, + new BN(1) + ) + .accounts({ + tokenAccount: tokenAddress, + mint: new anchor.web3.PublicKey( + "51kVaJaEU1qs4NwfTAH6b7GWprVCBYWtLSHNKQxY4B1" + ), + rent: program.provider.wallet.payer, + tokenProgram: new anchor.web3.PublicKey( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + ), + associatedTokenProgram: new anchor.web3.PublicKey( + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + ), + metadataProgram: TOKEN_METADATA_PROGRAM_ID, + masterEditionAccount: masterEditionAddress, + nftMetadata: metadataAddress, + }) + .signers([program.provider.wallet.payer]) + .rpc(); + } catch (e) { + console.log(e); + } \ No newline at end of file diff --git a/lib.rs b/lib.rs new file mode 100644 index 0000000..af2b1ad --- /dev/null +++ b/lib.rs @@ -0,0 +1,155 @@ +use anchor_lang::prelude::*; +use anchor_spl::associated_token::AssociatedToken; +use anchor_spl::metadata::{ + create_master_edition_v3, create_metadata_accounts_v3, CreateMasterEditionV3, + CreateMetadataAccountsV3, Metadata, +}; +use anchor_spl::token::{mint_to, Mint, MintTo, Token, TokenAccount}; +use mpl_token_metadata::types::{Collection, Creator, DataV2}; + +declare_id!("EkEBE7HzP7fkQ3MVGuV2JrADyphAgETGnesLqtP8ZHbR"); + +#[program] +pub mod nft_program { + use super::*; + pub fn create_single_nft( + ctx: Context, + id: u64, + name: String, + symbol: String, + uri: String, + price: f32, + cant: u64, +) -> Result<()> { + msg!("Creating seeds"); + let id_bytes = id.to_le_bytes(); + let seeds = &["mint".as_bytes(),id_bytes.as_ref(),&[ctx.bumps.mint], + ]; + + msg!("Run mint_to"); + + mint_to( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + MintTo { + authority: ctx.accounts.authority.to_account_info(), + to: ctx.accounts.token_account.to_account_info(), + mint: ctx.accounts.mint.to_account_info(), + }, + &[&seeds[..]], + ), + 1, // 1 token + )?; + + msg!("Run create metadata accounts v3"); + + create_metadata_accounts_v3( + CpiContext::new_with_signer( + ctx.accounts.metadata_program.to_account_info(), + CreateMetadataAccountsV3 { + payer: ctx.accounts.payer.to_account_info(), + mint: ctx.accounts.mint.to_account_info(), + metadata: ctx.accounts.nft_metadata.to_account_info(), + mint_authority: ctx.accounts.authority.to_account_info(), + update_authority: ctx.accounts.authority.to_account_info(), + system_program: ctx.accounts.system_program.to_account_info(), + rent: ctx.accounts.rent.to_account_info(), + }, + &[&seeds[..]], + ), + DataV2 { + name, + symbol, + uri, + seller_fee_basis_points: 0, + creators: None, + collection: None, + uses: None, + }, + true, + true, + None, + )?; + + msg!("Run create master edition v3"); + + create_master_edition_v3( + CpiContext::new_with_signer( + ctx.accounts.metadata_program.to_account_info(), + CreateMasterEditionV3 { + edition: ctx.accounts.master_edition_account.to_account_info(), + payer: ctx.accounts.payer.to_account_info(), + mint: ctx.accounts.mint.to_account_info(), + metadata: ctx.accounts.nft_metadata.to_account_info(), + mint_authority: ctx.accounts.authority.to_account_info(), + update_authority: ctx.accounts.authority.to_account_info(), + system_program: ctx.accounts.system_program.to_account_info(), + token_program: ctx.accounts.token_program.to_account_info(), + rent: ctx.accounts.rent.to_account_info(), + }, + &[&seeds[..]], + ), + Some(1), + )?; + + msg!("Minted NFT successfully"); + + Ok(()) + } +} + +#[derive(Accounts)] +#[instruction(id: u64)] +pub struct CreateNFT<'info> { + #[account(mut)] + pub authority: Signer<'info>, + #[account(mut)] + pub payer: Signer<'info>, + #[account( + init, + payer = payer, + mint::decimals = 0, + mint::authority = authority, + mint::freeze_authority = authority, + seeds = ["mint".as_bytes(), id.to_le_bytes().as_ref()], + bump, + )] + pub mint: Account<'info, Mint>, + #[account( + init_if_needed, + payer = payer, + associated_token::mint = mint, + associated_token::authority = payer, + )] + pub token_account: Account<'info, TokenAccount>, + pub associated_token_program: Program<'info, AssociatedToken>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, + pub token_program: Program<'info, Token>, + pub metadata_program: Program<'info, Metadata>, + #[account( + mut, + seeds = [ + b"metadata".as_ref(), + metadata_program.key().as_ref(), + mint.key().as_ref(), + b"edition".as_ref(), + ], + bump, + seeds::program = metadata_program.key() + )] + /// CHECK: + pub master_edition_account: UncheckedAccount<'info>, + #[account( + mut, + seeds = [ + b"metadata".as_ref(), + metadata_program.key().as_ref(), + mint.key().as_ref(), + ], + bump, + seeds::program = metadata_program.key() + )] + /// CHECK: + pub nft_metadata: UncheckedAccount<'info>, +} \ No newline at end of file From 98420701cb8012e5f44843fbedc0001c30b4d5b8 Mon Sep 17 00:00:00 2001 From: Sofia <62249700+sp-sofi@users.noreply.github.com> Date: Sat, 27 Apr 2024 14:44:53 +0300 Subject: [PATCH 2/2] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3bedc30..f310eb9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # NFT_Solana Створити смартконтракт NFT мовою Rust з логотипом НаУКМА завантаженим в IPFS і задеплоїти його в devnet Solana Зробити пул реквест коду та вказати Ваше прізвище та хеш транзакції в readme.md + +Prochna Sofia +Token: 51kVaJaEU1qs4NwfTAH6b7GWprVCBYWtLSHNKQxY4B1 +https://explorer.solana.com/address/51kVaJaEU1qs4NwfTAH6b7GWprVCBYWtLSHNKQxY4B1?cluster=devnet