From 746b694a17b8bb666f7ece6b59dac845f3bbf075 Mon Sep 17 00:00:00 2001 From: Yihau Chen Date: Sat, 24 Jun 2023 01:37:31 +0800 Subject: [PATCH] feat: add CreateMetadataAccountV3 (#135) * feat: impl CreateMetadataAccountV3 * docs: update nft example code --- .../mint-a-nft-with-master-edition-v2/main.go | 141 ------------------ .../mint-a-nft-with-master-edition/main.go | 27 ++-- .../metaplex/token_metadata/instruction.go | 98 ++++++++++++ 3 files changed, 116 insertions(+), 150 deletions(-) delete mode 100644 docs/_examples/nft/mint-a-nft-with-master-edition-v2/main.go diff --git a/docs/_examples/nft/mint-a-nft-with-master-edition-v2/main.go b/docs/_examples/nft/mint-a-nft-with-master-edition-v2/main.go deleted file mode 100644 index bfbaaf51..00000000 --- a/docs/_examples/nft/mint-a-nft-with-master-edition-v2/main.go +++ /dev/null @@ -1,141 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - - "github.com/mr-tron/base58" - "github.com/portto/solana-go-sdk/client" - "github.com/portto/solana-go-sdk/common" - "github.com/portto/solana-go-sdk/pkg/pointer" - "github.com/portto/solana-go-sdk/program/associated_token_account" - "github.com/portto/solana-go-sdk/program/metaplex/token_metadata" - "github.com/portto/solana-go-sdk/program/system" - "github.com/portto/solana-go-sdk/program/token" - "github.com/portto/solana-go-sdk/rpc" - "github.com/portto/solana-go-sdk/types" -) - -// FUarP2p5EnxD66vVDL4PWRoWMzA56ZVHG24hpEDFShEz -var feePayer, _ = types.AccountFromBase58("4TMFNY9ntAn3CHzguSAvDNLPRoQTaK3sWbQQXdDXaE6KWRBLufGL6PJdsD2koiEe3gGmMdRK3aAw7sikGNksHJrN") - -func main() { - c := client.NewClient(rpc.DevnetRPCEndpoint) - - mint := types.NewAccount() - fmt.Printf("NFT: %v\n", mint.PublicKey.ToBase58()) - - collection := types.NewAccount() - fmt.Println(base58.Encode(collection.PrivateKey)) - fmt.Printf("collection: %v\n", collection.PublicKey.ToBase58()) - - ata, _, err := common.FindAssociatedTokenAddress(feePayer.PublicKey, mint.PublicKey) - if err != nil { - log.Fatalf("failed to find a valid ata, err: %v", err) - } - - tokenMetadataPubkey, err := token_metadata.GetTokenMetaPubkey(mint.PublicKey) - if err != nil { - log.Fatalf("failed to find a valid token metadata, err: %v", err) - - } - tokenMasterEditionPubkey, err := token_metadata.GetMasterEdition(mint.PublicKey) - if err != nil { - log.Fatalf("failed to find a valid master edition, err: %v", err) - } - - mintAccountRent, err := c.GetMinimumBalanceForRentExemption(context.Background(), token.MintAccountSize) - if err != nil { - log.Fatalf("failed to get mint account rent, err: %v", err) - } - - recentBlockhashResponse, err := c.GetLatestBlockhash(context.Background()) - if err != nil { - log.Fatalf("failed to get recent blockhash, err: %v", err) - } - - tx, err := types.NewTransaction(types.NewTransactionParam{ - Signers: []types.Account{mint, feePayer}, - Message: types.NewMessage(types.NewMessageParam{ - FeePayer: feePayer.PublicKey, - RecentBlockhash: recentBlockhashResponse.Blockhash, - Instructions: []types.Instruction{ - system.CreateAccount(system.CreateAccountParam{ - From: feePayer.PublicKey, - New: mint.PublicKey, - Owner: common.TokenProgramID, - Lamports: mintAccountRent, - Space: token.MintAccountSize, - }), - token.InitializeMint(token.InitializeMintParam{ - Decimals: 0, - Mint: mint.PublicKey, - MintAuth: feePayer.PublicKey, - }), - token_metadata.CreateMetadataAccountV2(token_metadata.CreateMetadataAccountV2Param{ - Metadata: tokenMetadataPubkey, - Mint: mint.PublicKey, - MintAuthority: feePayer.PublicKey, - Payer: feePayer.PublicKey, - UpdateAuthority: feePayer.PublicKey, - UpdateAuthorityIsSigner: true, - IsMutable: true, - Data: token_metadata.DataV2{ - Name: "Fake SMS #1355", - Symbol: "FSMB", - Uri: "https://34c7ef24f4v2aejh75xhxy5z6ars4xv47gpsdrei6fiowptk2nqq.arweave.net/3wXyF1wvK6ARJ_9ue-O58CMuXrz5nyHEiPFQ6z5q02E", - SellerFeeBasisPoints: 100, - Creators: &[]token_metadata.Creator{ - { - Address: feePayer.PublicKey, - Verified: true, - Share: 100, - }, - }, - Collection: &token_metadata.Collection{ - Verified: false, - Key: collection.PublicKey, - }, - Uses: &token_metadata.Uses{ - UseMethod: token_metadata.Burn, - Remaining: 10, - Total: 10, - }, - }, - }), - associated_token_account.CreateAssociatedTokenAccount(associated_token_account.CreateAssociatedTokenAccountParam{ - Funder: feePayer.PublicKey, - Owner: feePayer.PublicKey, - Mint: mint.PublicKey, - AssociatedTokenAccount: ata, - }), - token.MintTo(token.MintToParam{ - Mint: mint.PublicKey, - To: ata, - Auth: feePayer.PublicKey, - Amount: 1, - }), - token_metadata.CreateMasterEditionV3(token_metadata.CreateMasterEditionParam{ - Edition: tokenMasterEditionPubkey, - Mint: mint.PublicKey, - UpdateAuthority: feePayer.PublicKey, - MintAuthority: feePayer.PublicKey, - Metadata: tokenMetadataPubkey, - Payer: feePayer.PublicKey, - MaxSupply: pointer.Get[uint64](0), - }), - }, - }), - }) - if err != nil { - log.Fatalf("failed to new a tx, err: %v", err) - } - - sig, err := c.SendTransaction(context.Background(), tx) - if err != nil { - log.Fatalf("failed to send tx, err: %v", err) - } - - fmt.Println(sig) -} diff --git a/docs/_examples/nft/mint-a-nft-with-master-edition/main.go b/docs/_examples/nft/mint-a-nft-with-master-edition/main.go index 3166314f..0002f7e4 100644 --- a/docs/_examples/nft/mint-a-nft-with-master-edition/main.go +++ b/docs/_examples/nft/mint-a-nft-with-master-edition/main.go @@ -25,6 +25,9 @@ func main() { mint := types.NewAccount() fmt.Printf("NFT: %v\n", mint.PublicKey.ToBase58()) + collection := types.NewAccount() + fmt.Printf("collection: %v\n", collection.PublicKey.ToBase58()) + ata, _, err := common.FindAssociatedTokenAddress(feePayer.PublicKey, mint.PublicKey) if err != nil { log.Fatalf("failed to find a valid ata, err: %v", err) @@ -35,7 +38,6 @@ func main() { log.Fatalf("failed to find a valid token metadata, err: %v", err) } - tokenMasterEditionPubkey, err := token_metadata.GetMasterEdition(mint.PublicKey) if err != nil { log.Fatalf("failed to find a valid master edition, err: %v", err) @@ -65,11 +67,12 @@ func main() { Space: token.MintAccountSize, }), token.InitializeMint(token.InitializeMintParam{ - Decimals: 0, - Mint: mint.PublicKey, - MintAuth: feePayer.PublicKey, + Decimals: 0, + Mint: mint.PublicKey, + MintAuth: feePayer.PublicKey, + FreezeAuth: &feePayer.PublicKey, }), - token_metadata.CreateMetadataAccount(token_metadata.CreateMetadataAccountParam{ + token_metadata.CreateMetadataAccountV3(token_metadata.CreateMetadataAccountV3Param{ Metadata: tokenMetadataPubkey, Mint: mint.PublicKey, MintAuthority: feePayer.PublicKey, @@ -77,7 +80,7 @@ func main() { UpdateAuthority: feePayer.PublicKey, UpdateAuthorityIsSigner: true, IsMutable: true, - MintData: token_metadata.Data{ + Data: token_metadata.DataV2{ Name: "Fake SMS #1355", Symbol: "FSMB", Uri: "https://34c7ef24f4v2aejh75xhxy5z6ars4xv47gpsdrei6fiowptk2nqq.arweave.net/3wXyF1wvK6ARJ_9ue-O58CMuXrz5nyHEiPFQ6z5q02E", @@ -89,9 +92,15 @@ func main() { Share: 100, }, }, + Collection: &token_metadata.Collection{ + Verified: false, + Key: collection.PublicKey, + }, + Uses: nil, }, + CollectionDetails: nil, }), - associated_token_account.Create(associated_token_account.CreateParam{ + associated_token_account.CreateAssociatedTokenAccount(associated_token_account.CreateAssociatedTokenAccountParam{ Funder: feePayer.PublicKey, Owner: feePayer.PublicKey, Mint: mint.PublicKey, @@ -103,7 +112,7 @@ func main() { Auth: feePayer.PublicKey, Amount: 1, }), - token_metadata.CreateMasterEdition(token_metadata.CreateMasterEditionParam{ + token_metadata.CreateMasterEditionV3(token_metadata.CreateMasterEditionParam{ Edition: tokenMasterEditionPubkey, Mint: mint.PublicKey, UpdateAuthority: feePayer.PublicKey, @@ -124,5 +133,5 @@ func main() { log.Fatalf("failed to send tx, err: %v", err) } - fmt.Println(sig) + fmt.Println("txid:", sig) } diff --git a/program/metaplex/token_metadata/instruction.go b/program/metaplex/token_metadata/instruction.go index 4463c978..b71ff1df 100644 --- a/program/metaplex/token_metadata/instruction.go +++ b/program/metaplex/token_metadata/instruction.go @@ -38,6 +38,32 @@ const ( InstructionFreezeDelegatedAccount InstructionThawDelegatedAccount InstructionRemoveCreatorVerification + InstructionBurnNft + InstructionVerifySizedCollectionItem + InstructionUnverifySizedCollectionItem + InstructionSetAndVerifySizedCollectionItem + InstructionCreateMetadataAccountV3 + InstructionSetCollectionSize + InstructionSetTokenStandard + InstructionBubblegumSetCollectionSize + InstructionBurnEditionNft + InstructionCreateEscrowAccount + InstructionCloseEscrowAccount + InstructionTransferOutOfEscrow + InstructionBurn + InstructionCreate + InstructionMint + InstructionDelegate + InstructionRevoke + InstructionLock + InstructionUnlock + InstructionMigrate + InstructionTransfer + InstructionUpdate + InstructionUse + InstructionVerify + InstructionUnverify + InstructionCollect ) type CreateMetadataAccountParam struct { @@ -504,3 +530,75 @@ func CreateMasterEditionV3(param CreateMasterEditionParam) types.Instruction { Data: data, } } + +type CreateMetadataAccountV3Param struct { + Metadata common.PublicKey + Mint common.PublicKey + MintAuthority common.PublicKey + Payer common.PublicKey + UpdateAuthority common.PublicKey + UpdateAuthorityIsSigner bool + IsMutable bool + Data DataV2 + CollectionDetails *CollectionDetails +} + +func CreateMetadataAccountV3(param CreateMetadataAccountV3Param) types.Instruction { + data, err := borsh.Serialize(struct { + Instruction Instruction + Data DataV2 + IsMutable bool + CollectionDetails *CollectionDetails + }{ + Instruction: InstructionCreateMetadataAccountV3, + Data: param.Data, + IsMutable: param.IsMutable, + CollectionDetails: param.CollectionDetails, + }) + + if err != nil { + panic(err) + } + + return types.Instruction{ + ProgramID: common.MetaplexTokenMetaProgramID, + Accounts: []types.AccountMeta{ + { + PubKey: param.Metadata, + IsSigner: false, + IsWritable: true, + }, + { + PubKey: param.Mint, + IsSigner: false, + IsWritable: false, + }, + { + PubKey: param.MintAuthority, + IsSigner: true, + IsWritable: false, + }, + { + PubKey: param.Payer, + IsSigner: true, + IsWritable: true, + }, + { + PubKey: param.UpdateAuthority, + IsSigner: param.UpdateAuthorityIsSigner, + IsWritable: false, + }, + { + PubKey: common.SystemProgramID, + IsSigner: false, + IsWritable: false, + }, + { + PubKey: common.SysVarRentPubkey, + IsSigner: false, + IsWritable: false, + }, + }, + Data: data, + } +}