Skip to content

Instantly share code, notes, and snippets.

@what-name
Created October 6, 2022 11:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save what-name/f948f8def57206839816047e30587914 to your computer and use it in GitHub Desktop.
Save what-name/f948f8def57206839816047e30587914 to your computer and use it in GitHub Desktop.
How to create SFTs on Solana (TypeScript)
// This Gist is the code for the tutorial "How to create SFTs on Solana".
// See the tutorial on Youtube: https://youtu.be/BYmcw0LThGE
// Check out SOAP - https://solanasoap.lol - https://twitter.com/solanasoap
// yarn add @metaplex-foundation/js@0.16.0 @solana/web3.js@1.63.1
import { bundlrStorage, keypairIdentity, Metaplex, CreatorInput, KeypairSigner, JsonMetadata, CreateSftInput } from '@metaplex-foundation/js';
import { Keypair, clusterApiUrl, Connection, PublicKey } from '@solana/web3.js';
import * as fs from "fs"
const clusterString = "devnet"
// sftkeypair.json (create and use your own keypair)
// Load a local keypair
const keypairFile = fs.readFileSync('sftkeypair.json');
const keypair = Keypair.fromSecretKey(Buffer.from(JSON.parse(keypairFile.toString())));
// Set up foundation
const connection = new Connection(clusterApiUrl(clusterString))
const metaplex = Metaplex.make(connection)
.use(keypairIdentity(keypair))
.use(bundlrStorage({
address: 'https://devnet.bundlr.network',
providerUrl: 'https://api.devnet.solana.com',
timeout: 60000,
}))
console.log("Public key of keypair being used: ", keypair.publicKey.toBase58())
// Create keypair to add as first verified creator
const randomCreatorKeypair = Keypair.generate()
const randomCreatorKeypairSigner: KeypairSigner = {
publicKey: randomCreatorKeypair.publicKey,
secretKey: randomCreatorKeypair.secretKey
}
// Assemble verified creators object
const soapCreator: CreatorInput[] = [
{
// Unique first verified creator per soap
address: randomCreatorKeypair.publicKey,
share: 0,
authority: randomCreatorKeypairSigner
},
{
// main soap creator
address: metaplex.identity().publicKey,
share: 100,
}
]
// Create collection signer object
const collectionSigner: KeypairSigner = {
publicKey: metaplex.identity().publicKey,
secretKey: metaplex.identity().secretKey
}
// NFT Metadata
const jsonMetadata: JsonMetadata = {
name: "SFT SOAP Tutorial",
symbol: "SOAP",
description: "You really did grind it out. Well, this diamond lootbox you got was well deserved. Here's a memento to show your friends, as if they wouldn't know you spend all day on Twitter anyways.",
seller_fee_basis_points: 500,
image: "https://i.pinimg.com/736x/0a/bb/e5/0abbe546e479edc1eb62f5a8ccd66328.jpg",
external_url: "http://solanasoap.lol",
attributes: [
{
trait_type: "What Dis",
value: "A soap"
},
{
trait_type: "Twitter",
value: "All day errday"
},
],
properties: {
creators: [
{
// Unique first verified creator per soap
address: randomCreatorKeypair.publicKey.toBase58(),
share: 0,
},
{
// main soap creator
address: metaplex.identity().publicKey.toBase58(),
share: 100,
}
],
files: [
{
type: "image/jpg",
uri: "https://i.pinimg.com/736x/0a/bb/e5/0abbe546e479edc1eb62f5a8ccd66328.jpg",
}
],
category: "image"
},
collection: {
name: "SOAP",
family: "SOAP"
}
}
// Upload off-chain metadata to ARWeave
const { uri } = await metaplex
.nfts()
.uploadMetadata(jsonMetadata)
.run();
console.log("URI of SFT metadata", uri)
// Create CreateSftInput object
const createSftInput: CreateSftInput = {
payer: metaplex.identity(),
tokenOwner: metaplex.identity().publicKey,
// tokenAmount: ({basisPoints: 10, currency: null}),
uri: uri,
name: jsonMetadata.name,
sellerFeeBasisPoints: jsonMetadata.seller_fee_basis_points,
symbol: jsonMetadata.symbol,
creators: soapCreator,
isCollection: true,
collection: new PublicKey("6AVMuYXFRDkM1JC2szHFMJwCG3kYKLMEh3duz6eGu4oP"),
collectionAuthority: collectionSigner,
collectionIsSized: false
}
// Create SFT
const sft = await metaplex.nfts().createSft(createSftInput).run()
console.log("SFT Mint Address: ", sft.mintAddress.toBase58())
console.log("SFT Mint: ", "https://solscan.io/token/" + sft.mintAddress.toBase58() + "?cluster=" + clusterString)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment