小试牛刀-SOL链创建Token

简介: 最近需要编写SOL合约进行SPL Token的转移,因为在测试网上需要自己部署测试Token,同时为了更加美观,Token需携带metadata数据(对名称、头像等)进行定义.在此对创建过程进行记录,希望帮助到有需要实现相关功能的朋友.

 目录

1.编写目的

2.账户结构

3.环境及使用依赖

4.步骤分解

4.1.导入相关依赖

4.2. 初始化变量

4.3.  创建并初始化Mint Account

4.4. 创建并初始化Metadata Account

4.5. 发送创建和初始化mint Account

4.6 铸造Token

5.源码分享


Welcome to Code Block's blog

本篇文章主要介绍了

[小试牛刀-SOL链创建Token]

❤博主广交技术好友,喜欢文章的可以关注一下❤

文章为在测试网络进行,不涉及任何其他建议!!

1.编写目的

       最近需要编写SOL合约进行SPL Token的转移,因为在测试网上需要自己部署测试Token,同时为了更加美观,Token需携带metadata数据(对名称、头像等)进行定义.在此对创建过程进行记录,希望帮助到有需要实现相关功能的朋友.

2.账户结构

       SOL链内的所有数据都存储在账户中,创建Token需要使用不同的程序(合约)创建三个Account,结构图如下:

image.gif 编辑

Mint Account:使用TOKEN_PROGRAM(Token相关操作)程序,创建一个Mint Account,这个账户的作用是用来铸造Token.


MetaData Account:使用METADATA_PROGRAM(metadata数据相关操作)程序,创建一个MetaData账户,用来存储Token基础信息(名称、图标/头像).


ACT Account: 铸造出的Token需要ACT Account进行接收,这需要使用用户和mint Account进行计算然后进行创建,用于接收铸造完成的Token.

3.环境及使用依赖

依赖名 版本号
@metaplex-foundation/mpl-token-metadata 2.1.1
@solana/spl-token 0.4.8
@solana/web3.js 1.95.3
{
  "scripts": {
    "test": "ts-node ./test/createmint.test.ts"
  },
  "dependencies": {
    "@metaplex-foundation/mpl-token-metadata": "^2.1.1",
    "@solana/spl-token": "^0.4.8",
    "@solana/web3.js": "^1.95.3",
  },
  "devDependencies": {
    "@types/node": "^22.5.0",
    "ts-node": "^10.9.2",
    "typescript": "^5.5.4"
  }
}

image.gif

       这里使用TypeScript和node环境进行代码编写,主要需要用到@metaplex-foundation/mpl-token-metadata(用于metadata Account初始化),@solana/spl-token(mint Account初始化和ACT Account创建),@solana/web3.js(用于基础Account创建和一些工具类).

注:这里尽量保持引入版本一致,因为不同版本的方法名称可能不同.

4.步骤分解

4.1.导入相关依赖

import { Keypair, PublicKey, SystemProgram,Connection,sendAndConfirmTransaction, Transaction } from "@solana/web3.js";
import { MINT_SIZE, TOKEN_PROGRAM_ID, createInitializeMint2Instruction, getOrCreateAssociatedTokenAccount,mintTo } from "@solana/spl-token";
import {
  PROGRAM_ID as METADATA_PROGRAM_ID,
  createCreateMetadataAccountV3Instruction,
} from "@metaplex-foundation/mpl-token-metadata";
import * as fs from 'fs'

image.gif

这里的fs用于读取本地密钥文件,用于生成payer.

4.2. 初始化变量

const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
const secretKeyPath='./wallet/id.json';
const secretKeyJSON = fs.readFileSync(secretKeyPath, 'utf-8');
// 创建测试密钥对
const secretKeyArray = JSON.parse(secretKeyJSON);
const secretKey = new Uint8Array(secretKeyArray);
const payer = Keypair.fromSecretKey(secretKey);
// 打印payer地址
console.log("Payer address:", payer.publicKey.toBase58());
// 定义token名称等
const tokenConfig = {
    //小数位数
    decimals: 2,
    //Token名称
    name: "BOGGY",
    //Token符号
    symbol: "Boggy Coin",
    //metadata json地址
    uri: "https://bafkreibyxbbl2jba2ry6ds2wgc6phdlhm2u6sox3neltfrdth7ocgkbqfm.ipfs.nftstorage.link",
  };

image.gif

这里connection定义了使用SOL测试网进行连接,同时通过读取本地的id.json文件创建一个交易费用支付者并进行打印。

4.3.  创建并初始化Mint Account

//创建一个密钥对,将其公钥作为Mint地址
  const mintKeypair = Keypair.generate();
  //输出Mint Account地址
  console.log("Mint address:", mintKeypair.publicKey.toBase58());

image.gif

这里创建一个密钥对,并打印,其公钥作为Mint Account地址在后面进行初始化.

//创建基础Account 
 const createMintAccountInstruction = SystemProgram.createAccount({
    fromPubkey: payer.publicKey,
    newAccountPubkey: mintKeypair.publicKey,
    space: MINT_SIZE,
    lamports: await connection.getMinimumBalanceForRentExemption(MINT_SIZE),
    programId: TOKEN_PROGRAM_ID,
  });
  //将Account初始化为一个mint Account
  const initializeMintInstruction = createInitializeMint2Instruction(
    mintKeypair.publicKey,
    tokenConfig.decimals,
    payer.publicKey,
    payer.publicKey,
  );

image.gif

这里进行了mint Account的创建和初始化两条命令:

>SystemProgram.createAccount

  1. fromPubkey:将作为该Wallet的拥有者和交易费用支付者.
  2. newAccountPubkey:即为创建mint地址,
  3. space:为组件内提供的MINT_SIZE(MINT Account必须使用的空间大小),
  4. lamports:作为免租费用.使用提供的方法根据空间进行计算.
  5. TOKEN_PROGRAM_ID: TOKEN_PROGRAM(Token相关操作)程序

>createInitializeMint2Instruction

  1. mintKeypair.publicKey:指定作为mint Account的Wallet.
  2. tokenConfig.decimals:设置小数位数为2位,
  3. payer.publicKey:分别指定铸造权限拥有者和冻结权限拥有者,当设置为null时Token将不能继续被铸造.

注:这两个命令其实就可以创建Token,但Token没有名称和头像.

4.4. 创建并初始化Metadata Account

const metadataAccount = PublicKey.findProgramAddressSync(
    [Buffer.from("metadata"), METADATA_PROGRAM_ID.toBuffer(), mintKeypair.publicKey.toBuffer()],
    METADATA_PROGRAM_ID,
  )[0];
  console.log("Metadata address:", metadataAccount.toBase58());

image.gif

这里先创建了一个PDA账户(即METADATA_PROGRAM作为操作执行者),并进行打印.

PDA的生成是[seeds]种子和持续的变动bump查看生成的地址是否在Ed25519椭圆曲线上,直到找到一个未在曲线上的值,则结束,并返回地址,以保持Pda地址的唯一性.

曲线方程为:

image.gif 编辑

注:根据官方要求必须使用派生(PDA)账户初始化MetaData Account.

const createMetadataInstruction = createCreateMetadataAccountV3Instruction(
    {
      metadata: metadataAccount,
      mint: mintKeypair.publicKey,
      mintAuthority: payer.publicKey,
      payer: payer.publicKey,
      updateAuthority: payer.publicKey,
    },
    {
      createMetadataAccountArgsV3: {
        data: {
          creators: null,
          name: tokenConfig.name,
          symbol: tokenConfig.symbol,
          uri: tokenConfig.uri,
          //费用
          sellerFeeBasisPoints: 0,
          collection: null,
          uses: null,
        },
        collectionDetails: null,
        isMutable: true,
      },
    },
  );

image.gif

使用createCreateMetadataAccountV3Instruction进行metadata Account的创建和初始化:

  1. metadata:metadata Account(即PDA Account)
  2. mint:关联MINT Address,
  3. mintAuthority: mint的权限用户,
  4. payer: 费用支付者和拥有者,
  5. updateAuthority: metadata的更新操作权限拥有者,

在createMetadataAccountArgsV3中分别设置了Token名称、图像、简称地址等参数。

 

4.5. 发送创建和初始化mint Account

const transaction=new Transaction().add(createMintAccountInstruction,initializeMintInstruction,createMetadataInstruction);
  const tx=await sendAndConfirmTransaction(connection,transaction,[payer,mintKeypair]);
  console.log("创建Token mint地址,交易tx:"+tx);

image.gif

       这里将上面的 createMintAccountInstructioninitializeMintInstructioncreateMetadataInstruction添加到一个transaction中并使用sendAndConfirmTransaction发送到链上,即可完成带有metadata的SPL Token创建.

测试截图:

image.gif 编辑

image.gif 编辑

4.6 铸造Token

const actAccount=await getOrCreateAssociatedTokenAccount(connection,payer,mintKeypair.publicKey,payer.publicKey);
  const mintSig=await mintTo(connection,payer,mintKeypair.publicKey,actAccount.address,payer,1000_000_000_000);
  console.log("向我的账户mint Token:"+mintSig);

image.gif

这里使用 getOrCreateAssociatedTokenAccount方法创建一个actAccount,同时通过mintTo方法向actAccount铸造Token.

测试截图:

image.gif 编辑

因为小数位数设置为两位所以铸造了 1000_000_000_000将会铸造10_000_000_000个Token.

5.源码分享

import { Keypair, PublicKey, SystemProgram,Connection,sendAndConfirmTransaction, Transaction } from "@solana/web3.js";
import { MINT_SIZE, TOKEN_PROGRAM_ID, createInitializeMint2Instruction, getOrCreateAssociatedTokenAccount,mintTo } from "@solana/spl-token";
import {
  PROGRAM_ID as METADATA_PROGRAM_ID,
  createCreateMetadataAccountV3Instruction,
} from "@metaplex-foundation/mpl-token-metadata";
import * as fs from 'fs'
const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
const secretKeyPath='./wallet/id.json';
const secretKeyJSON = fs.readFileSync(secretKeyPath, 'utf-8');
// 创建测试账户
const secretKeyArray = JSON.parse(secretKeyJSON);
const secretKey = new Uint8Array(secretKeyArray);
const payer = Keypair.fromSecretKey(secretKey);
(async () => {
  console.log("Payer address:", payer.publicKey.toBase58());
  const mintKeypair = Keypair.generate();
  console.log("Mint address:", mintKeypair.publicKey.toBase58());
  const tokenConfig = {
    decimals: 2,
    name: "BOGGY",
    symbol: "Boggy Coin",
    uri: "https://bafkreibyxbbl2jba2ry6ds2wgc6phdlhm2u6sox3neltfrdth7ocgkbqfm.ipfs.nftstorage.link",
  };
  const createMintAccountInstruction = SystemProgram.createAccount({
    fromPubkey: payer.publicKey,
    newAccountPubkey: mintKeypair.publicKey,
    space: MINT_SIZE,
    lamports: await connection.getMinimumBalanceForRentExemption(MINT_SIZE),
    programId: TOKEN_PROGRAM_ID,
  });
  const initializeMintInstruction = createInitializeMint2Instruction(
    mintKeypair.publicKey,
    tokenConfig.decimals,
    payer.publicKey,
    payer.publicKey,
  );
  const metadataAccount = PublicKey.findProgramAddressSync(
    [Buffer.from("metadata"), METADATA_PROGRAM_ID.toBuffer(), mintKeypair.publicKey.toBuffer()],
    METADATA_PROGRAM_ID,
  )[0];
  console.log("Metadata address:", metadataAccount.toBase58());
  const createMetadataInstruction = createCreateMetadataAccountV3Instruction(
    {
      metadata: metadataAccount,
      mint: mintKeypair.publicKey,
      mintAuthority: payer.publicKey,
      payer: payer.publicKey,
      updateAuthority: payer.publicKey,
    },
    {
      createMetadataAccountArgsV3: {
        data: {
          creators: null,
          name: tokenConfig.name,
          symbol: tokenConfig.symbol,
          uri: tokenConfig.uri,
          sellerFeeBasisPoints: 0,
          collection: null,
          uses: null,
        },
        collectionDetails: null,
        isMutable: true,
      },
    },
  );
  const transaction=new Transaction().add(createMintAccountInstruction,initializeMintInstruction,createMetadataInstruction);
  const tx=await sendAndConfirmTransaction(connection,transaction,[payer,mintKeypair]);
  console.log("创建Token mint地址,交易tx:"+tx);
  const actAccount=await getOrCreateAssociatedTokenAccount(connection,payer,mintKeypair.publicKey,payer.publicKey);
  const mintSig=await mintTo(connection,payer,mintKeypair.publicKey,actAccount.address,payer,1000_000_000_000);
  console.log("向我的账户mint Token:"+mintSig);
})();

image.gif

本代码均在测试网络进行,不涉及任何如投资等方面的建议!

如果你对区块链感兴趣,可以浏览我的专栏:区块链

感谢您的关注和收藏!!!!!!

image.gif 编辑


目录
相关文章
|
7月前
|
存储 Rust IDE
小试牛刀-Solana合约账户详解
开发语言上,Solana合约使用Rust为主要开发语言,其次是Solana合约并不像其它链那样将数据直接存到合约里,而是使用了更加独立的账户来代币转移和存储数据。按功能可以分为以下账户
251 0
|
3天前
|
存储 弹性计算 数据库
阿里云2026年第一波活动有哪些?云服务器抢购、满减券、免费试用都有
2026年阿里云推出多项优惠活动:轻量应用服务器2核2G峰值200M带宽38元抢购,云服务器“99计划”99元与199元新购续费同价;学生享300元无门槛券,教师享5折优惠;初创企业最高得100万上云抵扣金,企业迁云/出海可申5亿算力补贴;140+款云产品免费试用最长12个月,配合165元满减券包(满50减15、满180减50、满350减100),满足个人、企业全场景上云需求,助力个人、企业和学生用户优惠上云。
|
10月前
2025年阿里云域名备案流程(图文详细教程)
本文详细介绍了2025年阿里云域名备案的全流程,包括注册阿里云账号、企业实名认证、购买服务器、创建域名信息模板、购买域名、域名备案及查询备案号等步骤。通过图文结合的方式,清晰展示了每个环节的操作方法和注意事项,帮助用户顺利完成域名备案。文章强调了域名备案的前提是国内需有一台服务器,并提供了具体配置建议,同时提醒用户注意邮箱验证和短信核验等关键步骤,确保备案顺利通过。
11624 15
|
7月前
|
人工智能 数据挖掘 Linux
Centos安装Python3.7(亲测可用)
本指南详细介绍了在基于Linux(以CentOS系统为例,使用yum包管理器)的系统上安装Python 3.7版本的完整流程。Python是一种广泛使用的高级编程语言,在各种领域如软件开发、数据分析、人工智能和区块链开发等都有着重要的应用。
654 2
|
7月前
|
存储 前端开发 测试技术
小试牛刀-区块链代币锁仓合约实战
记录一下自己在开发代币合约中的过程,加深自己对合约功能的理解,在后续的学习过程中可以进行资料查阅,以及帮助有这方面开发要求或想学习的朋友进行更方便的入门。
205 0
|
7月前
|
jenkins Java 持续交付
使用Jenkins完成springboot项目快速更新
本文介绍了使用Jenkins和WinSW实现SpringBoot项目自动化部署的完整流程。首先讲解了Jenkins作为持续集成工具的作用,然后详细说明了环境准备步骤:包括JDK版本管理、WinSW服务配置(含XML文件修改)以及bat启动脚本编写。重点演示了Jenkins的项目配置方法,包括源码管理设置和构建步骤中的Windows批处理命令调用。通过这套方案,开发者只需推送代码到Git仓库,即可触发Jenkins自动完成项目构建、服务重启等全流程,显著提升部署效率。文章还提到IDEA的Jenkins插件可进
308 1
|
7月前
|
安全 算法 区块链
openssl生成证书
本文章是记录openssl命令生成私钥、证书签名请求、CA证书的命令和相关参数的解释。其中包含了各参数的名称、作用、技术细节和安全建议。
178 1
|
7月前
|
存储 算法 fastjson
火点监测:Nasa高分卫星接入
NASA(美国国家航空航天局)是美国联邦政府的一个独立机构,负责国家的航空航天研究和探索任务。NASA成立于1958年,其使命是探索太空并推动科学技术的发展。NASA的主要任务包括研究地球和太空的物理特性、开发和测试航空航天技术、进行太空探索和科学研究,以及促进航空航天技术的应用和技术转移。这里使用其开发的系统firms(火灾资源管理系统),通过Http请求获取数据来实现火点的监测,帮助需要实现相关功能,有类似开发任务的朋友。
218 6
|
7月前
|
算法 关系型数据库 Java
Springboot集成PostGIS完成路径规划
因为公司里需要做关于林区防火方面的项目,需要完成着火后山区路径的导航,但.....某德的功能似乎只能到达山区的边上,后边的路就需要自己完成导航了。搞了一个周终于有所效果了,也遇见了很多的坑,在此记录一下,希望以后不要踩坑。需要上述的环境才能进行路径导航,环境的搭建可以参阅
248 5
|
7月前
|
存储 索引
rbpf虚拟机-opcode码
该篇文章是rbpf虚拟机opcode码作用和使用的整理。(学习该虚拟机的目的是为了搞懂solana合约的执行方式,solana使用的rbpf是在该虚拟机上进行扩展。)
188 1