Typescript
Token2022 di Web3.js

Token2022 di Web3.js

Ekstensi Metadata

Ekstensi Metadata adalah ekstensi akun Mint yang memperkenalkan kemampuan untuk menyematkan metadata langsung ke dalam akun mint secara native dan tanpa harus menggunakan program lain.

Initializing the Mint Account

Ekstensi Metadata sedikit berbeda dari yang biasa kita lakukan karena terdiri dari 2 ekstensi berbeda yang keduanya ada pada akun Mint:

  • Ekstensi Metadata yang berisi semua informasi metadata seperti nama, simbol, uri, dan akun tambahan.
  • Ekstensi MetadataPointer yang mereferensikan akun Mint tempat ekstensi Metadata berada.

Biasanya, ketika digunakan, kedua ekstensi ini berada pada akun Mint yang sama; dan kita akan melakukan hal yang sama untuk contoh ini.

Mari mulai dengan beberapa dasar sebelum mendalami kodenya:

Sementara ekstensi MetadataPointer berada dalam paket @solana/spl-token, untuk menginisialisasi Metadata kita perlu menggunakan paket @solana/spl-token-metadata.

Jadi mari kita instal paket yang diperlukan:

 
npm i @solana/spl-token-metadata

Selain itu, ekstensi Metadata adalah salah satu ekstensi "satu-satunya" yang mengharuskan Anda menginisialisasi ekstensi setelah menginisialisasi akun Mint.

Ini karena instruksi inisialisasi metadata secara dinamis mengalokasikan ruang yang diperlukan untuk konten metadata dengan panjang variabel.

Pada saat yang sama, ini berarti kita akan perlu menginisialisasi akun Mint dengan cukup lamport agar bebas sewa dengan ekstensi Metadata yang disertakan, tetapi mengalokasikan ruang yang cukup hanya untuk ekstensi MetadataPointer karena instruksi token_metadata_initialize() sebenarnya meningkatkan ruang dengan benar.

Dalam kode, ini terlihat seperti ini:

ts
import {
    Keypair,
    SystemProgram,
    Transaction,
    sendAndConfirmTransaction,
} from '@solana/web3.js';
import {
    createInitializeMintInstruction,
    TYPE_SIZE,
    LENGTH_SIZE,
    createInitializeMetadataPointerInstruction,
    getMintLen,
    ExtensionType,
    TOKEN_2022_PROGRAM_ID,
} from '@solana/spl-token';
 
import { 
    createInitializeInstruction, 
    pack, 
    TokenMetadata 
} from "@solana/spl-token-metadata";
 
const mint = Keypair.generate();
 
const metadata: TokenMetadata = {
    mint: mint.publicKey,
    name: "Test Token",
    symbol: "TST",
    uri: "https://example.com/metadata.json",
    additionalMetadata: [["customField", "customValue"]],
};
 
// Size of Mint Account with extensions
const mintLen = getMintLen([ExtensionType.MetadataPointer]);
 
// Size of the Metadata Extension
const metadataLen = TYPE_SIZE + LENGTH_SIZE + pack(metadata).length;
 
// Minimum lamports required for Mint Account
const lamports = await connection.getMinimumBalanceForRentExemption(mintLen + metadataLen);
 
const createAccountInstruction = SystemProgram.createAccount({
    fromPubkey: keypair.publicKey,
    newAccountPubkey: mint.publicKey,
    space: mintLen,
    lamports,
    programId: TOKEN_2022_PROGRAM_ID,
});
 
const initializeMetadataPointer = createInitializeMetadataPointerInstruction(
    mint.publicKey,
    keypair.publicKey,
    mint.publicKey,
    TOKEN_2022_PROGRAM_ID,
);
 
const initializeMintInstruction = createInitializeMintInstruction(
    mint.publicKey,
    6,
    keypair.publicKey,
    null,
    TOKEN_2022_PROGRAM_ID,
);
 
const initializeMetadataInstruction = createInitializeInstruction(
    {
        programId: TOKEN_2022_PROGRAM_ID,
        mint: mint.publicKey,
        metadata: mint.publicKey,
        name: metadata.name,
        symbol: metadata.symbol,
        uri: metadata.uri,
        mintAuthority: keypair.publicKey,
        updateAuthority: keypair.publicKey,
    }
);
 
const updateMetadataFieldInstructions = createUpdateFieldInstruction({
    metadata: mint.publicKey,
    updateAuthority: keypair.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    field: metadata.additionalMetadata[0][0],
    value: metadata.additionalMetadata[0][1],
    });
 
const transaction = new Transaction().add(
    createAccountInstruction,
    initializeMetadataPointer,
    initializeMintInstruction,
    initializeMetadataInstruction,
    updateMetadataFieldInstructions,
);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair, mint]);
 
console.log(`Mint created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);

Instruksi initialize untuk metadata-interface tidak mengizinkan additionalMetadata. Karena alasan ini, jika kita ingin membuat aset yang memilikinya, kita perlu menggunakan instruksi token_metadata_update_field() yang akan kita lihat di bagian berikutnya.

Memperbarui Metadata

Dimungkinkan untuk memperbarui semua bidang metadata menggunakan instruksi yang sama token_metadata_update_field().

Untuk additionalMetadata ini bekerja sedikit berbeda karena kita dapat memperbarui bidang yang ada dengan hanya meneruskan Field yang sama dengan nilai baru atau hanya menambahkan bidang baru ke Metadata.

Di balik layar, program menggunakan instruksi yang sama dengan flag berbeda berdasarkan apa yang kita coba ubah, ini berarti kita dapat mengubah semua bidang seperti ini:

ts
const newMetadata: TokenMetadata = {
    mint: mint.publicKey,
    name: "New Name",
    symbol: "TST2",
    uri: "https://example.com/metadata2.json",
    additionalMetadata: [
        ["customField1", "customValue1"],
        ["customField2", "customValue2"],
    ],
};
 
// Size of Mint Account with extensions
const mintLen = getMintLen([ExtensionType.MetadataPointer]);
 
// Size of the Metadata Extension
const metadataLen = TYPE_SIZE + LENGTH_SIZE + pack(newMetadata).length;
 
// Minimum lamports required for Mint Account
const lamports = await connection.getMinimumBalanceForRentExemption(mintLen + metadataLen);
 
// Get the old balance of the keypair
const oldBalance = await connection.getBalance(mint.publicKey)
 
console.log(`Old balance: ${oldBalance}`);
console.log(`Lamports: ${lamports}`);
 
// Add lamports to the Mint if needed to cover the new metadata rent exemption
if (oldBalance < lamports) {
    const transferInstruction = SystemProgram.transfer({
        fromPubkey: keypair.publicKey,
        toPubkey: mint.publicKey,
        lamports: lamports - oldBalance,
    });
 
    const transaction = new Transaction().add(transferInstruction);
 
    const signature = await sendAndConfirmTransaction(connection, transaction, [keypair], {commitment: "finalized"});
 
    console.log(`Lamports added to Mint! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);
}
 
const updateMetadataNameInstructions = createUpdateFieldInstruction({
    metadata: mint.publicKey,
    updateAuthority: keypair.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    field: "Name", // Field | string
    value: "New Name",
});
 
const updateMetadataSymbolInstructions = createUpdateFieldInstruction({
    metadata: mint.publicKey,
    updateAuthority: keypair.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    field: "Symbol", // Field | string
    value: "TST2",
});
 
const updateMetadataUriInstructions = createUpdateFieldInstruction({
    metadata: mint.publicKey,
    updateAuthority: keypair.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    field: "Uri", // Field | string
    value: "https://example.com/metadata2.json",
});
 
const updateMetadataAdditionalMetadataInstructions = createUpdateFieldInstruction({
    metadata: mint.publicKey,
    updateAuthority: keypair.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    field: "customField2", // Field | string
    value: "customValue2",
});
 
const transaction = new Transaction().add(
    updateMetadataNameInstructions,
    updateMetadataSymbolInstructions,
    updateMetadataUriInstructions,
    updateMetadataAdditionalMetadataInstructions,
);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair]);
 
console.log(`Metadata updated! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);

Seperti yang Anda lihat, kita selalu perlu memastikan bahwa akun memiliki rent exempt, inilah mengapa kita melakukan semua perhitungan tentang rent di awal dan mentransfer lamport tambahan jika diperlukan.

Kita juga dapat menghapus Field dalam struktur additionalMetadata menggunakan instruksi RemoveKey seperti ini:

ts
const removeMetadataKeyInstructions = createRemoveKeyInstruction({
    metadata: mint.publicKey,
    updateAuthority: keypair.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    key: "customField", // Field | string
    idempotent: true,
});
Daftar Isi
Lihat Sumber
Blueshift © 2025Commit: 96f50c6