| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- ---
- title: Create a Token with Metadata
- description:
- Learn how to create a new Solana token, with metadata, using the gill JavaScript library.
- ---
- Tokens are digital assets that represent ownership over diverse categories of assets. Tokenization
- enables the digitalization of property rights. Tokens on Solana are referred to as SPL
- ([Solana Program Library](https://github.com/solana-program)) Tokens.
- This article will demonstrate [how to create a new SPL token](./create-token) using the
- [`gill` package](https://www.npmjs.com/package/gill), including attaching metadata to the token for
- users to see and applications to display.
- ## Install gill
- Install gill using the core `gill` library:
- ```package-install
- gill
- ```
- import { PackageBadges } from "@/components/package-badges";
- <PackageBadges packageName="gill" />
- ## Create an RPC connection
- In order to send transactions and/or fetch data from the Solana blockchain, you will need an client
- connection. You can easily create a Solana client connection using the `createSolanaClient()`
- function.
- The `urlOrMoniker` can be either a Solana network moniker (e.g. `devnet`, `mainnet`, `localnet`) or
- a full URL of your RPC provider.
- ```ts twoslash
- import { createSolanaClient } from "gill";
- const { rpc, sendAndConfirmTransaction } = createSolanaClient({
- urlOrMoniker: "devnet", // `mainnet`, `localnet`, etc
- });
- ```
- <Callout title="Public RPC endpoints are subject to rate limits">
- Using a Solana moniker will connect to the public RPC endpoints. These are subject to rate limits
- and should not be used in production applications. Applications should find their own RPC provider
- and the URL provided from them.
- </Callout>
- ## Prepare a Signer
- Every Solana transaction requires at least one "signer" to be the fee payer for the transaction. The
- following are common practices:
- - load a signer from a local keypair file (like `~/.config/solana/id.json`, the one used by the
- Solana CLI)
- - loading the signer from an ENV variable (e.g. `process.env.SERVER_SIGNER`)
- - having a user's wallet be the signer via a front end application
- ### Load a signer from a local keypair file
- For backend scripts and some server environments, you can load a signer from your local filesystem:
- ```ts twoslash
- import { type KeyPairSigner } from "gill";
- import { loadKeypairSignerFromFile } from "gill/node";
- // This defaults to the file path used by the Solana CLI: `~/.config/solana/id.json`
- const signer: KeyPairSigner = await loadKeypairSignerFromFile();
- console.log("signer:", signer.address);
- ```
- ## Decide which Token Program to use
- To use the legacy Token Program:
- ```ts twoslash
- import { TOKEN_PROGRAM_ADDRESS } from "gill/programs";
- const tokenProgram = TOKEN_PROGRAM_ADDRESS;
- ```
- To use the Token Extensions Program (aka Token22):
- ```ts twoslash
- import { TOKEN_2022_PROGRAM_ADDRESS } from "gill/programs";
- const tokenProgram = TOKEN_2022_PROGRAM_ADDRESS;
- ```
- ## Generate a Mint and metadata address
- ```ts twoslash
- import { generateKeyPairSigner } from "gill";
- const mint = await generateKeyPairSigner();
- ```
- If you are using the legacy Token Program, you will need to derive the "metadata address" from
- Metaplex's Token Metadata program.
- ```ts twoslash
- import { generateKeyPairSigner } from "gill";
- import { getTokenMetadataAddress } from "gill/programs";
- const mint = await generateKeyPairSigner();
- const metadataAddress = await getTokenMetadataAddress(mint);
- ```
- ## Get the latest blockhash
- ```ts
- const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
- ```
- ## Create a transaction that creates a token
- <Callout>
- Instead of manually crafting all of these instructions, you can also use gill's instruction
- builder function: `getCreateTokenInstructions()`
- </Callout>
- ```ts
- import { createTransaction } from "gill";
- import { getMintSize } from "gill/programs";
- const space = getMintSize();
- const transaction = createTransaction({
- feePayer: signer,
- version: "legacy",
- instructions: [
- getCreateAccountInstruction({
- space,
- lamports: getMinimumBalanceForRentExemption(space),
- newAccount: mint,
- payer: signer,
- programAddress: tokenProgram,
- }),
- getInitializeMintInstruction(
- {
- mint: mint.address,
- mintAuthority: signer.address,
- freezeAuthority: signer.address,
- decimals: 9,
- },
- {
- programAddress: tokenProgram,
- },
- ),
- getCreateMetadataAccountV3Instruction({
- collectionDetails: null,
- isMutable: true,
- updateAuthority: signer,
- mint: mint.address,
- metadata: metadataAddress,
- mintAuthority: signer,
- payer: signer,
- data: {
- sellerFeeBasisPoints: 0,
- collection: null,
- creators: null,
- uses: null,
- name: "super sweet token",
- symbol: "SST",
- uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/Climate/metadata.json",
- },
- }),
- ],
- latestBlockhash,
- });
- ```
- ## Sign and send the transaction
- With your transaction fully created, you can now sign the transaction to
- ```ts
- import { signTransactionMessageWithSigners } from "gill";
- const signedTransaction = await signTransactionMessageWithSigners(transaction);
- console.log(
- "Explorer:",
- getExplorerLink({
- cluster: "devnet",
- transaction: getSignatureFromTransaction(signedTransaction),
- }),
- );
- ```
- If your transaction is already fully signed or has all signer's available, you can send and confirm
- it on the blockchain.
- ```ts
- await sendAndConfirmTransaction(signedTransaction);
- ```
- <Callout title="Pro Tip">
- If you do not need to know the transaction signature prior to sending the transaction AND you all
- signers are attached to the transaction, you can pass a fully signable transaction to the
- `sendAndConfirmTransaction()` function initialized from `createSolanaClient()`. It will then
- perform the signing operations prior to sending and confirming.
- </Callout>
|