I Token SPL standard non includono metadati come nome, simbolo o immagine. Il Metaplex Token Metadata Program risolve questo problema creando un account di metadati collegato a ciascun mint di token.
Questa guida tratta il Metaplex Token Metadata Program che può essere utilizzato per Token SPL standard e Token-2022. Per utilizzare l'estensione Metadata di Token-2022, consulta la guida all'estensione Metadata che memorizza i metadati direttamente sull'account mint.
Come Funziona Token Metadata
Il Token Metadata Program crea un Program Derived Address (PDA) per ogni conio di token. Questo account di metadati memorizza informazioni onchain come il nome e il simbolo del token, oltre a un URI che punta ai metadati JSON off-chain (immagini, descrizioni, ecc.).
┌─────────────────┐ ┌─────────────────────┐│ Mint Account │ │ Metadata Account ││ │ │ (PDA) ││ - Supply │◄──────│ - Name ││ - Decimals │ │ - Symbol ││ - Authority │ │ - URI │└─────────────────┘ │ - Seller Fee ││ - Creators │└─────────────────────┘
Il PDA dei metadati è derivato dai seed:
["metadata", program_id, mint_address]
Creare Token con Metadati
L'istruzione createV1 crea sia l'account mint che i suoi metadati in una
singola transazione.
Typescript
import {airdropFactory,appendTransactionMessageInstructions,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,generateKeyPairSigner,lamports,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners} from "@solana/kit";import {getCreateV1InstructionAsync,TokenStandard} from "@metaplex-foundation/mpl-token-metadata-kit";// Create connectionconst rpc = createSolanaRpc("http://127.0.0.1:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://127.0.0.1:8900");// Generate keypairsconst payer = await generateKeyPairSigner();const mint = await generateKeyPairSigner();// Fund payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: payer.address,lamports: lamports(1_000_000_000n),commitment: "confirmed"});// Create fungible token with metadataconst createInstruction = await getCreateV1InstructionAsync({mint,authority: payer,payer,name: "My Token",symbol: "MTK",uri: "https://example.com/token.json",sellerFeeBasisPoints: 0,tokenStandard: TokenStandard.Fungible});// Build and send transactionconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();const transactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(payer, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),(tx) => appendTransactionMessageInstructions([createInstruction], tx));const signedTransaction =await signTransactionMessageWithSigners(transactionMessage);await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });console.log("Mint Address:", mint.address);
Recuperare i Metadati del Token
Per scoprire come recuperare i metadati per i token esistenti, consulta la ricetta del cookbook Recuperare i Metadati del Token.
Aggiornare i Metadati del Token
L'autorità di aggiornamento può modificare i metadati se l'account è mutabile.
import {appendTransactionMessageInstructions,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners} from "@solana/kit";import {getUpdateV1InstructionAsync,findMetadataPda,fetchMetadata} from "@metaplex-foundation/mpl-token-metadata-kit";const rpc = createSolanaRpc("http://127.0.0.1:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://127.0.0.1:8900");// authority must be a KeyPairSigner with update authorityconst mintAddress = "YOUR_MINT_ADDRESS";// Fetch current metadata to preserve existing valuesconst [metadataAddress] = await findMetadataPda({ mint: mintAddress });const currentMetadata = await fetchMetadata(rpc, metadataAddress);// Update metadata (must provide all data fields)const updateInstruction = await getUpdateV1InstructionAsync({mint: mintAddress,authority, // Update authority signerpayer: authority,data: {name: "Updated Token Name",symbol: "UPD",uri: "https://example.com/updated-token.json",sellerFeeBasisPoints: 100, // 1%creators:currentMetadata.data.creators.__option === "Some"? currentMetadata.data.creators.value: null}});// Build and send transactionconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();const transactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),(tx) => appendTransactionMessageInstructions([updateInstruction], tx));const signedTransaction =await signTransactionMessageWithSigners(transactionMessage);await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });console.log("Metadata updated successfully");
Standard dei Token
Il Token Metadata Program supporta diversi standard di token:
| Standard | Descrizione | Caso d'Uso |
|---|---|---|
Fungible | Token fungibile standard con metadati | Valute, punti |
FungibleAsset | Token fungibile che rappresenta un asset unico | Oggetti semi-fungibili |
NonFungible | NFT con Master Edition | Opera d'arte 1/1 |
ProgrammableNonFungible | NFT con royalty obbligatorie | Royalty per creatori |
NonFungibleEdition | Copia stampata di un NFT | Edizioni limitate |
ProgrammableNonFungibleEdition | Copia stampata con royalty obbligatorie | Edizioni limitate |
import { TokenStandard } from "@metaplex-foundation/mpl-token-metadata-kit";// For fungible tokenstokenStandard: TokenStandard.Fungible;// For NFTstokenStandard: TokenStandard.NonFungible;// For programmable NFTs (enforced royalties)tokenStandard: TokenStandard.ProgrammableNonFungible;
Formato dei Metadati Off-Chain
Il campo uri punta a un file JSON contenente metadati estesi. Il formato
standard segue il
Metaplex Token Metadata Standard:
{"name": "My Token","symbol": "MTK","description": "A description of the token","image": "https://example.com/token-image.png","external_url": "https://example.com","attributes": [{"trait_type": "Category","value": "Utility"}],"properties": {"files": [{"uri": "https://example.com/token-image.png","type": "image/png"}]}}
Conserva il tuo JSON di metadati su una soluzione di archiviazione affidabile e permanente come Arweave, IPFS o una CDN dedicata. Se l'URI diventa inaccessibile, i wallet e gli explorer non saranno in grado di visualizzare i metadati del tuo token.
Struttura dell'Account dei Metadati
L'account di metadati onchain contiene:
pub struct Metadata {pub key: Key, // Account type identifierpub update_authority: Pubkey, // Can update metadatapub mint: Pubkey, // Associated mintpub name: String, // Token name (max 32 chars)pub symbol: String, // Token symbol (max 10 chars)pub uri: String, // URI to off-chain JSON (max 200 chars)pub seller_fee_basis_points: u16, // Royalty % (100 = 1%)pub creators: Option<Vec<Creator>>, // Creator list with sharespub primary_sale_happened: bool, // Primary sale flagpub is_mutable: bool, // Can metadata be updatedpub edition_nonce: Option<u8>, // Edition noncepub token_standard: Option<TokenStandard>, // Token typepub collection: Option<Collection>, // Collection infopub uses: Option<Uses>, // Use tracking}
Best Practice
- Imposta la mutabilità appropriata: Usa
isMutable: falseper token che non dovrebbero mai cambiare - Usa hosting URI affidabile: I metadati off-chain dovrebbero essere su archiviazione permanente
- Verifica i creatori: Gli indirizzi dei creatori dovrebbero essere verificati per confermare l'autenticità
- Considera le royalty: Imposta
sellerFeeBasisPointsper le royalty sulle vendite secondarie (i marketplace potrebbero applicarle o meno)
Is this page helpful?