# 在Solana发行元数据代币（纯JS完成）

By [木白鹿粦](https://paragraph.com/@0x513dd2b49363c8506b037afd487e3a7d18bbfec0) · 2024-03-09

---

**教学视频链接：**

*   Bilibili [**https://www.bilibili.com/video/BV1Wv421i7GM/?share\_source=copy\_web&vd\_source=c147db41bce0140aa28781d353032bab**](https://www.bilibili.com/video/BV1LF4m1c7Xk/?spm_id_from=333.999.0.0&vd_source=2979dcefbf505a6422797470b6fbbfad)
    
*   Youtube [**https://youtu.be/bfw\_uhrvqjc?si=vuY1likrBvZ5ftPa**](https://www.youtube.com/watch?v=ORFes1Xebug)
    

**欢迎添加我的联系方式：Rico\_ruilabs**

### **一、安装 Node.js**

是Javascript的运行环境，到官网下载安装即可 [https://nodejs.org/](https://nodejs.org/)

### **二、项目初始化，安装需要的库**

新建文件夹，初始化项目

    npm init -y
    

然后使用 npm install 指令安装以下各库

*   @metaplex-foundation/umi
    
*   @metaplex-foundation/mpl-token-metadata
    
*   @metaplex-foundation/umi-bundle-defaults
    
*   @solana/web3.js
    

看该文档体会Solana Token、NFT是怎么构建的

[https://developers.metaplex.com/token-metadata](https://developers.metaplex.com/token-metadata)

### **三、新建index.js文件，导入库和模块**

    import { percentAmount, generateSigner, signerIdentity, createSignerFromKeypair } from '@metaplex-foundation/umi'import { TokenStandard, createAndMint ,mplTokenMetadata} from '@metaplex-foundation/mpl-token-metadata'import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'import { Keypair } from "@solana/web3.js"import { readFileSync } from 'fs'
    

**四、实例化umi，连接到Solana devnet网络**

    const umi = createUmi('your_devnet_rpc');
    

这里的节点推荐使白嫖 QiuckNode，用过都说好，访问 quicknode.com，一步步注册即可，免费套餐跑测试代码都用

![](https://storage.googleapis.com/papyrus_images/9bd823b9b2193b129d5150ea33939db652c2ae344c2b7e5d708dcf3c70489c93.png)

### **五、实例化钱包、获取签名者**

使用上一节在本机创建的 id.json 私钥文件，实例化用户钱包

    const userKeypair = Keypair.fromSecretKey(    Buffer.from(JSON.parse(readFileSync('./id.json', "utf-8"))))​
    

此时获取的 \_keypair 有两个成员，publicKey 与 secretKey

使用其 secretKey ，生成 UMI 签名者（Signer）

    const userWallet = umi.eddsa.createKeypairFromSecretKey(userKeypair.secretKey);​const userWalletSigner = createSignerFromKeypair(umi, userWallet);
    

### **六、定义元数据**

将您的令牌信息在线化，我推荐使用 pinata

[https://www.pinata.cloud/](https://www.pinata.cloud/)

注册登录，来到仪表盘

![](https://storage.googleapis.com/papyrus_images/f2f94d0d1219b1946f5bb9001d017c35ef35b1ef06d82e71469e833dad6214e5.png)

![](https://storage.googleapis.com/papyrus_images/84d750881046d65153db647b0e42eae917de04648ffc08e0af5a65987a2a12cc.png)

TokenInfo.json

    {    "name": "Per aspera ad astra",    "symbol": "PAA",    "description": "「循此苦旅，以達星辰」",    "image": "https://white-historical-basilisk-887.mypinata.cloud/ipfs/QmS7kMQG1gHptsd4NAEVYDhMJ7SGa23hpJ63RYh69FqPGk"}
    

各字段分别为 名称、简称、介绍、头像的在线链接

    const metadata = {    name: "Per aspera ad astra",    symbol: "PAA",    uri: "https://white-historical-basilisk-887.mypinata.cloud/ipfs/QmVd6xVRqg9sJQP1zkUVizZ7jah6zD7j6fSPn9F7MRjZMo",}
    

### **七、杂项配置**

    // 生成 Mint 签名者const mint = generateSigner(umi);​// 使用 use 方法配置 UMI 的签名者和元数据模块umi.use(signerIdentity(userWalletSigner))   .use(mplTokenMetadata())
    

### **八、成功**

    createAndMint(umi, {    mint,    authority: umi.identity,    name: metadata.name,    symbol: metadata.symbol,    uri: metadata.uri,    sellerFeeBasisPoints: percentAmount(0),    decimals: 9,    amount: 666_000000000,    tokenOwner: userWallet.publicKey,    tokenStandard: TokenStandard.Fungible,    }).sendAndConfirm(umi).then(() => {    console.log("Successfully minted tokens (", mint.publicKey, ")");})
    

重要字段的含义为：

*   sellerFeeBasisPoints: percentAmount(0) 卖方费用为0
    
*   amount: 666\_000000000,最终数量为666，后面的0对应小数精度
    
*   tokenStandard: TokenStandard.Fungible,令牌标准，此处为可替代令牌
    

执行 index.js 代码

    node .\index.js
    

得到带有元数据的新令牌

![](https://storage.googleapis.com/papyrus_images/8b832b725888f2717cc37611a921cd40cb40ba33bd6464b82cda64e4705e97f3.png)

EpnTRJksPN5GicrhpLDHhW67dArQuYPnf8B1rWx7u96k

区块浏览器验证

![](https://storage.googleapis.com/papyrus_images/2cf2a8cecb9500bf862dd41b63c6ee6abcd82ae615174288e2c8a4782aa02622.png)

### **九、全部代码**

    // 引入各模块
    import { percentAmount, generateSigner, signerIdentity, createSignerFromKeypair } from '@metaplex-foundation/umi'
    import { TokenStandard, createAndMint ,mplTokenMetadata} from '@metaplex-foundation/mpl-token-metadata'
    import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
    import { Keypair } from "@solana/web3.js"
    import { readFileSync } from 'fs'
    
    // 连接到 Solana devnet
    const umi = createUmi('https://hidden-purple-arrow.solana-devnet.quiknode.pro/206956a59552f9a87a253f7172eb7f58c9246801/')
    
    
    // 使用 id.json 本地的私钥文件，实例化钱包
    const userKeypair = Keypair.fromSecretKey(
        Buffer.from(JSON.parse(readFileSync('./id.json', "utf-8")))
    )
    // 获取签名者
    const userWallet = umi.eddsa.createKeypairFromSecretKey(userKeypair.secretKey);
    const userWalletSigner = createSignerFromKeypair(umi, userWallet);
    
    // 构建元数据
    const metadata = {
        name: "Per aspera ad astra",
        symbol: "PAA",
        uri: "https://white-historical-basilisk-887.mypinata.cloud/ipfs/QmVd6xVRqg9sJQP1zkUVizZ7jah6zD7j6fSPn9F7MRjZMo",
    }
    
    // 生成 Mint 签名者
    const mint = generateSigner(umi);
    
    // 使用 use 方法配置 UMI 的签名者和元数据模块
    umi.use(signerIdentity(userWalletSigner))
       .use(mplTokenMetadata())
    
    
    // 打包发送 令牌铸造的交易
    createAndMint(umi, {
        mint,
        authority: umi.identity,
        name: metadata.name,
        symbol: metadata.symbol,
        uri: metadata.uri,
        sellerFeeBasisPoints: percentAmount(0),
        decimals: 9,
        amount: 666_000000000,
        tokenOwner: userWallet.publicKey,
        tokenStandard: TokenStandard.Fungible,
        }).sendAndConfirm(umi).then(() => {
        console.log("Successfully minted tokens (", mint.publicKey, ")");
    })

---

*Originally published on [木白鹿粦](https://paragraph.com/@0x513dd2b49363c8506b037afd487e3a7d18bbfec0/solana-js)*
