create-token.mdx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. ---
  2. title: Create a Token with Metadata
  3. description:
  4. Learn how to create a new Solana token, with metadata, using the gill JavaScript library.
  5. ---
  6. Tokens are digital assets that represent ownership over diverse categories of assets. Tokenization
  7. enables the digitalization of property rights. Tokens on Solana are referred to as SPL
  8. ([Solana Program Library](https://github.com/solana-program)) Tokens.
  9. This article will demonstrate [how to create a new SPL token](./create-token) using the
  10. [`gill` package](https://www.npmjs.com/package/gill), including attaching metadata to the token for
  11. users to see and applications to display.
  12. ## Install gill
  13. Install gill using the core `gill` library:
  14. ```package-install
  15. gill
  16. ```
  17. import { PackageBadges } from "@/components/package-badges";
  18. <PackageBadges packageName="gill" />
  19. ## Create an RPC connection
  20. In order to send transactions and/or fetch data from the Solana blockchain, you will need an client
  21. connection. You can easily create a Solana client connection using the `createSolanaClient()`
  22. function.
  23. The `urlOrMoniker` can be either a Solana network moniker (e.g. `devnet`, `mainnet`, `localnet`) or
  24. a full URL of your RPC provider.
  25. ```ts twoslash
  26. import { createSolanaClient } from "gill";
  27. const { rpc, sendAndConfirmTransaction } = createSolanaClient({
  28. urlOrMoniker: "devnet", // `mainnet`, `localnet`, etc
  29. });
  30. ```
  31. <Callout title="Public RPC endpoints are subject to rate limits">
  32. Using a Solana moniker will connect to the public RPC endpoints. These are subject to rate limits
  33. and should not be used in production applications. Applications should find their own RPC provider
  34. and the URL provided from them.
  35. </Callout>
  36. ## Prepare a Signer
  37. Every Solana transaction requires at least one "signer" to be the fee payer for the transaction. The
  38. following are common practices:
  39. - load a signer from a local keypair file (like `~/.config/solana/id.json`, the one used by the
  40. Solana CLI)
  41. - loading the signer from an ENV variable (e.g. `process.env.SERVER_SIGNER`)
  42. - having a user's wallet be the signer via a front end application
  43. ### Load a signer from a local keypair file
  44. For backend scripts and some server environments, you can load a signer from your local filesystem:
  45. ```ts twoslash
  46. import { type KeyPairSigner } from "gill";
  47. import { loadKeypairSignerFromFile } from "gill/node";
  48. // This defaults to the file path used by the Solana CLI: `~/.config/solana/id.json`
  49. const signer: KeyPairSigner = await loadKeypairSignerFromFile();
  50. console.log("signer:", signer.address);
  51. ```
  52. ## Decide which Token Program to use
  53. To use the legacy Token Program:
  54. ```ts twoslash
  55. import { TOKEN_PROGRAM_ADDRESS } from "gill/programs";
  56. const tokenProgram = TOKEN_PROGRAM_ADDRESS;
  57. ```
  58. To use the Token Extensions Program (aka Token22):
  59. ```ts twoslash
  60. import { TOKEN_2022_PROGRAM_ADDRESS } from "gill/programs";
  61. const tokenProgram = TOKEN_2022_PROGRAM_ADDRESS;
  62. ```
  63. ## Generate a Mint and metadata address
  64. ```ts twoslash
  65. import { generateKeyPairSigner } from "gill";
  66. const mint = await generateKeyPairSigner();
  67. ```
  68. If you are using the legacy Token Program, you will need to derive the "metadata address" from
  69. Metaplex's Token Metadata program.
  70. ```ts twoslash
  71. import { generateKeyPairSigner } from "gill";
  72. import { getTokenMetadataAddress } from "gill/programs";
  73. const mint = await generateKeyPairSigner();
  74. const metadataAddress = await getTokenMetadataAddress(mint);
  75. ```
  76. ## Get the latest blockhash
  77. ```ts
  78. const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
  79. ```
  80. ## Create a transaction that creates a token
  81. <Callout>
  82. Instead of manually crafting all of these instructions, you can also use gill's instruction
  83. builder function: `getCreateTokenInstructions()`
  84. </Callout>
  85. ```ts
  86. import { createTransaction } from "gill";
  87. import { getMintSize } from "gill/programs";
  88. const space = getMintSize();
  89. const transaction = createTransaction({
  90. feePayer: signer,
  91. version: "legacy",
  92. instructions: [
  93. getCreateAccountInstruction({
  94. space,
  95. lamports: getMinimumBalanceForRentExemption(space),
  96. newAccount: mint,
  97. payer: signer,
  98. programAddress: tokenProgram,
  99. }),
  100. getInitializeMintInstruction(
  101. {
  102. mint: mint.address,
  103. mintAuthority: signer.address,
  104. freezeAuthority: signer.address,
  105. decimals: 9,
  106. },
  107. {
  108. programAddress: tokenProgram,
  109. },
  110. ),
  111. getCreateMetadataAccountV3Instruction({
  112. collectionDetails: null,
  113. isMutable: true,
  114. updateAuthority: signer,
  115. mint: mint.address,
  116. metadata: metadataAddress,
  117. mintAuthority: signer,
  118. payer: signer,
  119. data: {
  120. sellerFeeBasisPoints: 0,
  121. collection: null,
  122. creators: null,
  123. uses: null,
  124. name: "super sweet token",
  125. symbol: "SST",
  126. uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/Climate/metadata.json",
  127. },
  128. }),
  129. ],
  130. latestBlockhash,
  131. });
  132. ```
  133. ## Sign and send the transaction
  134. With your transaction fully created, you can now sign the transaction to
  135. ```ts
  136. import { signTransactionMessageWithSigners } from "gill";
  137. const signedTransaction = await signTransactionMessageWithSigners(transaction);
  138. console.log(
  139. "Explorer:",
  140. getExplorerLink({
  141. cluster: "devnet",
  142. transaction: getSignatureFromTransaction(signedTransaction),
  143. }),
  144. );
  145. ```
  146. If your transaction is already fully signed or has all signer's available, you can send and confirm
  147. it on the blockchain.
  148. ```ts
  149. await sendAndConfirmTransaction(signedTransaction);
  150. ```
  151. <Callout title="Pro Tip">
  152. If you do not need to know the transaction signature prior to sending the transaction AND you all
  153. signers are attached to the transaction, you can pass a fully signable transaction to the
  154. `sendAndConfirmTransaction()` function initialized from `createSolanaClient()`. It will then
  155. perform the signing operations prior to sending and confirming.
  156. </Callout>