blocto / solana-go-sdk

Solana Golang SDK
https://blocto.github.io/solana-go-sdk/
MIT License
385 stars 101 forks source link

Possible to mint an nft? #42

Closed cdowdall14 closed 2 years ago

cdowdall14 commented 2 years ago

Possible to get an example of purchasing an nft off say magic eden?

yihau commented 2 years ago

mints NFT and purchases NFT on magic eden are different things. for mint NFT I can add some examples because I know how metaplex's program writes. for magic eden's purchasing, I need to know how magic eden serialize its instructions. it will take some time.

cdowdall14 commented 2 years ago

mints NFT and purchases NFT on magic eden are different things. for mint NFT I can add some examples because I know how metaplex's program writes. for magic eden's purchasing, I need to know how magic eden serialize its instructions. it will take some time.

That would be super helpful either way if thats possible!

sparkycj328 commented 2 years ago

Hi, would we able to get more info on this? Really loving this library, thank you!

yihau commented 2 years ago

sorry for the late. I think you can use this code to mint NFT first.

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/portto/solana-go-sdk/client"
    "github.com/portto/solana-go-sdk/common"
    "github.com/portto/solana-go-sdk/program/assotokenprog"
    "github.com/portto/solana-go-sdk/program/metaplex/tokenmeta"
    "github.com/portto/solana-go-sdk/program/sysprog"
    "github.com/portto/solana-go-sdk/program/tokenprog"
    "github.com/portto/solana-go-sdk/rpc"
    "github.com/portto/solana-go-sdk/types"
)

func main() {
    c := client.NewClient(rpc.DevnetRPCEndpoint)

    // init your fee payer
    feePayer, _ = types.AccountFromBase58("")

    mintMinBalance, _ := c.GetMinimumBalanceForRentExemption(context.Background(), 82)
    mint := types.NewAccount()
    ata, _, _ := common.FindAssociatedTokenAddress(feePayer.PublicKey, mint.PublicKey)
    tokenMetadataPubkey, _ := tokenmeta.GetTokenMetaPubkey(mint.PublicKey)
    tokenMasterEditionPubkey, _ := tokenmeta.GetMasterEdition(mint.PublicKey)

    sig, err := c.QuickSendTransaction(context.Background(), client.QuickSendTransactionParam{
        FeePayer: feePayer.PublicKey,
        Signers:  []types.Account{mint, feePayer},
        Instructions: []types.Instruction{
            sysprog.CreateAccount(sysprog.CreateAccountParam{
                From:     feePayer.PublicKey,
                New:      mint.PublicKey,
                Owner:    common.TokenProgramID,
                Lamports: mintMinBalance,
                Space:    82,
            }),
            tokenprog.InitializeMint(tokenprog.InitializeMintParam{
                Decimals: 0,
                Mint:     mint.PublicKey,
                MintAuth: feePayer.PublicKey,
            }),
            tokenmeta.CreateMetadataAccount(tokenmeta.CreateMetadataAccountParam{
                Metadata:                tokenMetadataPubkey,
                Mint:                    mint.PublicKey,
                MintAuthority:           feePayer.PublicKey,
                Payer:                   feePayer.PublicKey,
                UpdateAuthority:         feePayer.PublicKey,
                UpdateAuthorityIsSigner: true,
                IsMutable:               true,
                MintData: tokenmeta.Data{
                    Name:                 "",
                    Symbol:               "",
                    Uri:                  "",
                    SellerFeeBasisPoints: 100,
                    Creators: &[]tokenmeta.Creator{
                        {
                            Address:  feePayer.PublicKey,
                            Verified: true,
                            Share:    100,
                        },
                    },
                },
            }),
            assotokenprog.CreateAssociatedTokenAccount(assotokenprog.CreateAssociatedTokenAccountParam{
                Funder:                 feePayer.PublicKey,
                Owner:                  feePayer.PublicKey,
                Mint:                   mint.PublicKey,
                AssociatedTokenAccount: ata,
            }),
            tokenprog.MintTo(tokenprog.MintToParam{
                Mint:   mint.PublicKey,
                To:     ata,
                Auth:   feePayer.PublicKey,
                Amount: 1,
            }),
            tokenmeta.CreateMasterEdition(tokenmeta.CreateMasterEditionParam{
                Edition:         tokenMasterEditionPubkey,
                Mint:            mint.PublicKey,
                UpdateAuthority: feePayer.PublicKey,
                MintAuthority:   feePayer.PublicKey,
                Metadata:        tokenMetadataPubkey,
                Payer:           feePayer.PublicKey,
                MaxSupply:       nil,
            }),
        },
    })
    if err != nil {
        log.Fatalf("failed to send tx, err: %v", err)
    }
    fmt.Println(sig)

}
sparkycj328 commented 2 years ago

Awesome thank you! Still getting used to interacting with Solana/ its terminology. This seems like code to create new tokens on the blockchain. Would one be able to use this code to also mint an NFT from someone else's program? (for example: metaplex candymachine v2)

yihau commented 2 years ago

This seems like code to create new tokens on the blockchain.

Basically all process of minting NFT is based on this. 1) create mint 2) mint 1 token 3) init metadata and master edition (option). You will find some difference in each program but the main process is the same.

Would one be able to use this code to also mint an NFT from someone else's program?

this code is to call metaplex token metadata program directly. candy machine v2 is a different program. If you want to interact with it. You need to compose instructions by yourself (this lib is not support atm).

sparkycj328 commented 2 years ago

So for a non-candymachine NFT, that has already been created using the instructions from above, how would I go about minting a token using only code after it has been created?

yihau commented 2 years ago

When you create a master edition. You also specific a limit amount which can be copied. The main idea is to use tokenmeta.MintNewEditionFromMasterEditionViaToken

for now you can take a look at these code.

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/portto/solana-go-sdk/client"
    "github.com/portto/solana-go-sdk/common"
    "github.com/portto/solana-go-sdk/program/assotokenprog"
    "github.com/portto/solana-go-sdk/program/metaplex/tokenmeta"
    "github.com/portto/solana-go-sdk/program/sysprog"
    "github.com/portto/solana-go-sdk/program/tokenprog"
    "github.com/portto/solana-go-sdk/rpc"
    "github.com/portto/solana-go-sdk/types"
)

func main() {
    var feePayer, _ = types.AccountFromBytes()

    c := client.NewClient(rpc.DevnetRPCEndpoint)

    masterEdition := common.PublicKeyFromString("")
    metadata := common.PublicKeyFromString("")
    metadataMint := common.PublicKeyFromString("") // master NFT
    oriTokenAccount, _, _ := common.FindAssociatedTokenAddress(feePayer.PublicKey, metadataMint)

    mintMinBalance, _ := c.GetMinimumBalanceForRentExemption(context.Background(), 82)

    mint := types.NewAccount()
    var edition uint64 = 1
    ata, _, _ := common.FindAssociatedTokenAddress(feePayer.PublicKey, mint.PublicKey)
    tokenMetadataPubkey, _ := tokenmeta.GetTokenMetaPubkey(mint.PublicKey)
    tokenMasterEditionPubkey, _ := tokenmeta.GetMasterEdition(mint.PublicKey)
    editionMark, _ := tokenmeta.GetEditionMark(metadataMint, edition)
    fmt.Println(editionMark.ToBase58())
    sig, err := c.QuickSendTransaction(context.Background(), client.QuickSendTransactionParam{
        FeePayer: feePayer.PublicKey,
        Signers:  []types.Account{mint, feePayer},
        Instructions: []types.Instruction{
            sysprog.CreateAccount(sysprog.CreateAccountParam{
                From:     feePayer.PublicKey,
                New:      mint.PublicKey,
                Owner:    common.TokenProgramID,
                Lamports: mintMinBalance,
                Space:    82,
            }),
            tokenprog.InitializeMint(tokenprog.InitializeMintParam{
                Decimals: 0,
                Mint:     mint.PublicKey,
                MintAuth: feePayer.PublicKey,
            }),
            assotokenprog.CreateAssociatedTokenAccount(assotokenprog.CreateAssociatedTokenAccountParam{
                Funder:                 feePayer.PublicKey,
                Owner:                  feePayer.PublicKey,
                Mint:                   mint.PublicKey,
                AssociatedTokenAccount: ata,
            }),
            tokenprog.MintTo(tokenprog.MintToParam{
                Mint:   mint.PublicKey,
                To:     ata,
                Auth:   feePayer.PublicKey,
                Amount: 1,
            }),
            tokenmeta.MintNewEditionFromMasterEditionViaToken(tokenmeta.MintNewEditionFromMasterEditionViaTokeParam{
                NewMetaData:                tokenMetadataPubkey,
                NewEdition:                 tokenMasterEditionPubkey,
                MasterEdition:              masterEdition,
                NewMint:                    mint.PublicKey,
                EditionMark:                editionMark,
                NewMintAuthority:           feePayer.PublicKey,
                Payer:                      feePayer.PublicKey,
                TokenAccountOwner:          feePayer.PublicKey,
                TokenAccount:               oriTokenAccount,
                NewMetadataUpdateAuthority: feePayer.PublicKey,
                MasterMetadata:             metadata,
                Edition:                    edition,
            }),
        },
    })
    if err != nil {
        log.Fatalf("failed to send tx, err: %v", err)
    }
    fmt.Println(sig)

}
yihau commented 2 years ago

https://portto.github.io/solana-go-sdk/nft/mint-a-nft.html

etherhe commented 5 months ago

When you create a master edition. You also specific a limit amount which can be copied. The main idea is to use tokenmeta.MintNewEditionFromMasterEditionViaToken

for now you can take a look at these code.

package main

import (
  "context"
  "fmt"
  "log"

  "github.com/portto/solana-go-sdk/client"
  "github.com/portto/solana-go-sdk/common"
  "github.com/portto/solana-go-sdk/program/assotokenprog"
  "github.com/portto/solana-go-sdk/program/metaplex/tokenmeta"
  "github.com/portto/solana-go-sdk/program/sysprog"
  "github.com/portto/solana-go-sdk/program/tokenprog"
  "github.com/portto/solana-go-sdk/rpc"
  "github.com/portto/solana-go-sdk/types"
)

func main() {
  var feePayer, _ = types.AccountFromBytes()

  c := client.NewClient(rpc.DevnetRPCEndpoint)

  masterEdition := common.PublicKeyFromString("")
  metadata := common.PublicKeyFromString("")
  metadataMint := common.PublicKeyFromString("") // master NFT
  oriTokenAccount, _, _ := common.FindAssociatedTokenAddress(feePayer.PublicKey, metadataMint)

  mintMinBalance, _ := c.GetMinimumBalanceForRentExemption(context.Background(), 82)

  mint := types.NewAccount()
  var edition uint64 = 1
  ata, _, _ := common.FindAssociatedTokenAddress(feePayer.PublicKey, mint.PublicKey)
  tokenMetadataPubkey, _ := tokenmeta.GetTokenMetaPubkey(mint.PublicKey)
  tokenMasterEditionPubkey, _ := tokenmeta.GetMasterEdition(mint.PublicKey)
  editionMark, _ := tokenmeta.GetEditionMark(metadataMint, edition)
  fmt.Println(editionMark.ToBase58())
  sig, err := c.QuickSendTransaction(context.Background(), client.QuickSendTransactionParam{
      FeePayer: feePayer.PublicKey,
      Signers:  []types.Account{mint, feePayer},
      Instructions: []types.Instruction{
          sysprog.CreateAccount(sysprog.CreateAccountParam{
              From:     feePayer.PublicKey,
              New:      mint.PublicKey,
              Owner:    common.TokenProgramID,
              Lamports: mintMinBalance,
              Space:    82,
          }),
          tokenprog.InitializeMint(tokenprog.InitializeMintParam{
              Decimals: 0,
              Mint:     mint.PublicKey,
              MintAuth: feePayer.PublicKey,
          }),
          assotokenprog.CreateAssociatedTokenAccount(assotokenprog.CreateAssociatedTokenAccountParam{
              Funder:                 feePayer.PublicKey,
              Owner:                  feePayer.PublicKey,
              Mint:                   mint.PublicKey,
              AssociatedTokenAccount: ata,
          }),
          tokenprog.MintTo(tokenprog.MintToParam{
              Mint:   mint.PublicKey,
              To:     ata,
              Auth:   feePayer.PublicKey,
              Amount: 1,
          }),
          tokenmeta.MintNewEditionFromMasterEditionViaToken(tokenmeta.MintNewEditionFromMasterEditionViaTokeParam{
              NewMetaData:                tokenMetadataPubkey,
              NewEdition:                 tokenMasterEditionPubkey,
              MasterEdition:              masterEdition,
              NewMint:                    mint.PublicKey,
              EditionMark:                editionMark,
              NewMintAuthority:           feePayer.PublicKey,
              Payer:                      feePayer.PublicKey,
              TokenAccountOwner:          feePayer.PublicKey,
              TokenAccount:               oriTokenAccount,
              NewMetadataUpdateAuthority: feePayer.PublicKey,
              MasterMetadata:             metadata,
              Edition:                    edition,
          }),
      },
  })
  if err != nil {
      log.Fatalf("failed to send tx, err: %v", err)
  }
  fmt.Println(sig)

}

Can you add this example to the document?