小试牛刀-SOL链创建Token

news2024/11/15 12:11:10

目录

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,结构图如下:

60670c95ade44a6aa49d00fd2de3364e.png

 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-metadata2.1.1
@solana/spl-token0.4.8
@solana/web3.js1.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"
  }
}

        这里使用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'

这里的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",
  };

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

4.3.  创建并初始化Mint Account

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

这里创建一个密钥对,并打印,其公钥作为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,
  );

这里进行了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());

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

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

曲线方程为:eq?-x%5E%7B2%7D+y%5E%7B2%7D%3D1-%5Cleft%20%28%20%5Cfrac%7B121665%7D%7B121666%7D%5Cright%20%29*x%5E%7B2%7D*y%5E%7B2%7D

1f9fe6a4ae554edeb133bdcff453e6a2.png

注:根据官方要求必须使用派生(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,
      },
    },
  );

 使用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);

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

测试截图:
ae5bcd5e9aa947048942f344a11e38fb.png
 031a74ea092c4b9dbbad6e72b444a56c.png

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);

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

测试截图:

0739dcd8f1fd416282a63637ffef6c50.png

因为小数位数设置为两位所以铸造了 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);
})();

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

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

感谢您的关注和收藏!!!!!!
17a5b84bdcbb4896bda2b8481c3a53ce.jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2108219.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

震惊,从仿真走向现实,3D Map最大提升超12,Cube R-CNN使用合成数据集迁移到真实数据集

震惊,从仿真走向现实,3D Map最大提升超12,Cube R-CNN使用合成数据集迁移到真实数据集 Abstract 由于摄像机视角多变和场景条件不可预测,在动态路边场景中从单目图像中准确检测三维物体仍然是一个具有挑战性的问题。本文介绍了一…

基于飞桨paddle2.6.1+cuda11.7+paddleRS开发版的目标提取-道路数据集训练和预测代码

基于飞桨paddle2.6.1cuda11.7paddleRS开发版的目标提取-道路数据集训练和预测代码 预测结果: 预测影像: (一)准备道路数据集 下载数据集地址: https://aistudio.baidu.com/datasetdetail/56961 mass_road.zip …

国际标准图像分辨率测试ISO12233 - 2017中文翻译

参考:https://blog.csdn.net/jgw2008/article/details/116519404?spm1035.2023.3001.6557&utm_mediumdistribute.pc_relevant_bbs_down_v2.none-task-blog-2~default~OPENSEARCH~Rate-2-116519404-bbs-392397517.264^v3^pc_relevant_bbs_down_v2_default&d…

SpringBoot与Minio的极速之旅:解锁文件切片上传新境界

目录 一、前言 二、对象存储(Object Storage)介绍 (1)对象存储的特点 (2)Minio 与对象存储 (3)对象存储其他存储方式的区别 (4)对象存储的应用场景 三、…

万龙觉醒辅助:VMOS云手机助力资源采集!挂机升级!

《万龙觉醒》是一款策略型游戏,玩家需要合理规划资源采集、建筑升级、科技研发等来提升实力。在本文中,我们将为您提供一篇详细的游戏辅助攻略,并介绍如何使用VMOS云手机来提升您的游戏体验,实现24小时的自动化管理。 使用VMOS云…

R3M: A Universal Visual Representation for Robot Manipulation

R3M [25] explores how visual representations obtained by training on diverse human video data using time-contrastive learning and video-language can enable data-efficient learning(实际上就是小样本学习) of downstream robotic manipulati…

【FreeRTOS】事件组实验-改进姿态控制

目录 0 前言1 事件组实验_改进姿态控制2 改进思路2.1 创建事件2.2 等待事件2.3 设置事件2.4 Debug2.5 设置MPU6050寄存器 3 总结 0 前言 学习视频: 【FreeRTOS 入门与工程实践 --由浅入深带你学习 FreeRTOS(FreeRTOS 教程 基于 STM32,以实际项…

pdf文件怎么编辑?6个pdf编辑方法学起来(图文教程)

pdf文件怎么编辑?现今的互联网时代,我们的办公也趋向于数字化办公。PDF文件已经成为我们日常工作和学习中不可或缺的格式文件。然而,编辑PDF文档不是一件容易的事。很多人会因为编辑pdf文档感到非常苦恼,尤其是当需要对PDF进行内容…

Linux内核编程(十五)网络设备驱动

本文目录 一、常见的网络协议二、传输介质三、RJ-45接口 对于网络知识不太熟悉的同学可以查看这篇文章:计算机网络知识点详情总结。 一、常见的网络协议 TCP、UDP协议:详情查看-TCP、UDP系统编程。DNS协议:是互联网中用于将域名&#xff08…

【刷题笔记】删除并获取最大点数粉刷房子

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 题目一 题目链接&#xff1a;删除并获取最大点数 思路&#xff1a; 预处理状态表示 状态转移方程 代码如下&#xff1a; class Solution { public:int deleteAndEarn(vector<int>& nums) {int N1…

八股(7)——Redis

八股&#xff08;7&#xff09;——Redis 4.3 RedisRedis 基础简单介绍一下 Redis!分布式缓存常见的技术选型方案有哪些&#xff1f;说一下 Redis 和 Memcached 的区别和共同点缓存数据的处理流程是怎样的&#xff1f;为什么要用 Redis/为什么要用缓存&#xff1f;Redis 除了做…

2024 年全国大学生数学建模竞赛(国赛)浅析

需要完整资料&#xff0c;请关注WX&#xff1a;“小何数模”&#xff01; &#xff08;需要完整B、C和E题资料请关注WX&#xff1a;“小何数模”&#xff0c;获取资料链接&#xff01;&#xff09; 本次万众瞩目的全国大学生数学建模赛题已正式出炉&#xff0c;无论是赛题难度…

Floorp Browser:开源自由,打造更个性化的浏览环境!

前言 "技术引领未来&#xff0c;创新改变世界。" 在这个日新月异的数字化时代&#xff0c;网络浏览器作为我们探索互联网世界的窗口&#xff0c;其重要性不言而喻。正是在这样的背景下&#xff0c;Floorp浏览器应运而生&#xff0c;它不仅继承了Mozilla Firefox的强…

基于SpringBoot的外卖点餐系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootJSP 工具&#xff1a;IDEA/Eclipse、Navicat、Maven、Tomcat 系统展示 首页 用户管理界…

超强台风“摩羯”来临:EasyCVR平台如何汇聚城市视频资源,构建应急监测网

一、背景概述 2024年第11号台风“摩羯”自生成以来&#xff0c;迅速加强为超强台风级别&#xff0c;预计将在海南琼海到广东电白一带沿海登陆&#xff0c;带来16-17级的强风和巨浪。我国作为自然灾害多发的国家&#xff0c;每年夏季都面临着山洪、泥石流、洪涝、飓风、地震等多…

摸鱼 | 图片转Excel单元格脚本

依赖安装 pip install Pillow tqdm源码&#xff1a; import argparse from PIL import Image import openpyxl from openpyxl.styles import PatternFill from tqdm import tqdmdef image_to_excel(image_path, excel_path, cell_size20, sample_ratio1, output_widthNone, o…

C++(十五)继承 part1

一、继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许我们在保持原有类特性的基础上进行扩展&#xff0c;增加方法(成员函数)和属性(成员变量)&#xff0c;这样产生新的类&#xff0c;称子类。继承呈现了面向对象程序设计的…

Restful风格接口开发

一、项目搭建 安装nestjs脚手架 // 安装nestjs脚手架 npm i nestjs/cli// 新建 nest new [名字]//选择要用的工具 npm / yarn / pnpm 文件信息&#xff1a; 【main.ts】&#xff1a; 入口文件&#xff0c;通过NestFactory&#xff08;由nestjs/core库抛出的对象&#x…

【深度学习】softmax 回归的从零开始实现与简洁实现

前言 小时候听过一个小孩练琴的故事&#xff0c;老师让他先弹最简单的第一小节&#xff0c;小孩练了两天后弹不出。接着&#xff0c;老师让他直接去练更难的第二小节&#xff0c;小孩练习了几天后还是弹不出&#xff0c;开始感觉到挫败和烦躁了。 小孩以为老师之后会让他从简…

数据链路层认识以太网

我们前面学习到的传输层&#xff0c;网络层&#xff0c;传输层是保证数据可靠传输。而网络层是实现在复杂的网络环境中确定一个合适的路径。我们接下来所说的数据链路层其实就是用于两个设备(同一种数据链路节点)之间进行传递。其实也就是如数次的局域网中设备之间的转发过程。…