小试牛刀-SOL链创建Token代币

news2024/12/27 9:59:36

目录

1.编写目的

2.账户结构

3.环境及使用依赖

4.步骤分解

4.1.导入相关依赖

4.2. 初始化变量

4.3.  创建并初始化Mint Account

4.4. 创建并初始化Metadata Account

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

4.6 铸造代币

5.源码分享


Welcome to Code Block's blog

本篇文章主要介绍了

[小试牛刀-SOL链创建Token代币]
❤博主广交技术好友,喜欢文章的可以关注一下❤

1.编写目的

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

2.账户结构

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

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

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

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

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,
    //代币名称
    name: "BOGGY",
    //代币符号
    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

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

>createInitializeMint2Instruction

mintKeypair.publicKey:指定作为mint Account的账户.
tokenConfig.decimals:设置小数位数为2位,
payer.publicKey:分别指定铸造权限拥有者和冻结权限拥有者,当设置为null时代币将不能继续被铸造.
注:这两个命令其实就可以创建代币,但代币没有名称和头像.

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)账户初始化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的创建和初始化:

metadata:metadata Account(即PDA账户)
mint:关联MINT账户,
mintAuthority: mint的权限用户,
payer: 费用支付者和拥有者,
updateAuthority: metadata的更新操作权限拥有者,

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

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

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

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

测试截图:

 

4.6 铸造代币

  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代币:"+mintSig);

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

测试截图:

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

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("创建代币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代币:"+mintSig);
})();

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

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

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

相关文章

视频孪生智慧监所平台,实现监管数据的统一管理和立体直观呈现

针对监所传统方式难以有效管控;监所视频监控相似度极高,难以辨识,工作人员劳动强度大;监所行业涉及的系统众多,缺少统一高效的管理;监所行业对系统应急响应能力、智慧化程度要求高等痛点问题。在智慧监所建…

24数学建模国赛及提供助力(12——存贮论)!!!!

需要资料和助攻的小伙伴们可以文章末尾获取链接!!!! 点击链接加入群聊获取资料以及助攻https://qm.qq.com/q/NGl6WD0Bky

免费作图软件推荐,六款工具助你提升设计效率

在现代设计工作中,合适的作图工具能极大地提高工作效率。对于设计师、学生或是爱好者来说,免费的作图软件无疑是一个经济实惠的选择。本文将为大家介绍 6 款免费且功能强大的作图软件,其中包括国内备受欢迎的免费作图软件以及 5 款优秀的国外…

多态,匿名内部类(lambda表达式),集合

多态(polymorphism) 一个演员扮演多个不同角色。可以减少if语句的使用。 概念 具有接口或者继承关系 A extends B A implement C 类型一致(IEat) 民间说法:父类的引用指向不同的子类对象(不同时刻) 产生不同结果 调用相同方法&#x…

学历不会改变命运但知识一定可以改变命运

一、知识与学历的区别 首先,我们需要区分“知识”与“学历”。学历通常是指一个人通过正规教育体系获得的证书或学位,而知识则是更为宽泛的概念,它包括了一个人通过各种途径获得的信息、技能和理解。学历可能只是知识的一部分,而…

自然语言处理系列五十二》文本分类算法》BERT模型算法原理及文本分类

注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】 文章目录 自然语言处理系列五十二文本分类算法》BERT模型算法原理及文本分…

day7 测试知识积累

1.有一个班级表,里面有学号,姓名,学科,分数。找到语文学科分数最高的前10位的姓名(SQL) select 姓名 from 班级表 where 学科=语文 order by 分数 DESC limit 10; 2.有一张年级表,有班级,年级,学生姓名,找到这10名同学所在的班级(SQL) select class from 年级表 wher…

《python语言程序设计》第8章第12题生物信息:找出基因,生物学家使用字母A C T和G构成字符2串建模一个基因组(上)

草稿一、用单一方法遍历文本 9.1代码 genome_text TTATGTTTTAAGGATGGGGCGTTAGTTdef div_word(word_to_judge):len_num len(word_to_judge)save_word ""if len_num % 3 0:print("This word is valid")if save_word.find("ATG") "ATG&qu…

SpringBoot链路追踪②:如何集成?

首先下载Zipkin的jar包&#xff1a;Central Repository: io/zipkin/zipkin-server (maven.org) 根据自己的项目版本。我的版本分别是&#xff1a; <spring-boot.version>2.7.18</spring-boot.version> <spring-cloud.version>2021.0.8</spring-cloud.ve…

Spring理论知识(Ⅳ)——Spring Instrumentation模块

Spring的组成 Spring由20个核心依赖组成&#xff0c;这20个核心依赖可以分为6个核心模块 Spring Instrumentation模块介绍 总的来说&#xff0c;Spring Instrumentation提供了类植入&#xff08;Instrumentation&#xff09;支持和类加载器的实现&#xff0c;可以在特定…

解决报错【ERROR: Could not install packages due to an OSError: [WinError 5] 拒绝访问。】

1、问题发生 用pip安装时出现报错【ERROR: Could not install packages due to an OSError: [WinError 5] 拒绝访问。: c:\\programdata\\anaconda3\\lib\\site-packages\\__pycache__\\typing_extensions.cpython-39.pyc Consider using the --user option or check the perm…

多媒体信息共享|基于SprinBoot+vue的多媒体信息共享平台(源码+数据库+文档)

多媒体信息共享平台 目录 基于SprinBootvue的多媒体信息共享平台 一、前言 二、系统设计 三、系统功能设计 系统前台功能模块 后台模块实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌…

软考计算机软件基础知识总结

目录 前言 计算机软件概述 操作系统 数据库 文件系统 网络协议 中间件 软件构件 应用软件 最后 前言 早期的计算机软件和计算机程序 (Computer Program) 的概念几乎不加区别&#xff0c;后来计算机 软件的概念在计算机程序的基础上得到了延伸。计算机软件是指计算机系…

基于HybridCLR做的一个FlyBird Demo

周末学习了下HybridCLR的原理和用法做了个FlyBrid小demo。记录一下 官网里写的原理&#xff1a; 对于这个我的理解是&#xff1a; Unity引擎的代码使用还是AOT方式。对于项目业务这块打成多个程序集。运行时使用了解释器&#xff0c;解释执行。从而完成热更新。 一。环境安装…

MySQL5.6迁移到DM8

注意&#xff1a; MySQL 5.7 与 MySQL 8.0 的语法有所区别&#xff0c;本文档是将MySQL5.6迁移到DM8。 迁移前准备 源库 数据库信息 统计源端业务库要迁移的数据量、字符编码、归档保留等信息。 内容 说明 备注 数据库架构 单机 节点数 1 数据库版本 MySQL 5.6…

OpenGL/GLUT实践:实现反弹运动的三角形动画与键盘控制(电子科技大学信软图形与动画Ⅱ实验)

源码见GitHub&#xff1a;A-UESTCer-s-Code 文章目录 1 运行效果2 实验过程2.1 环境配置2.2 绘制三角形2.2.1 渲染函数2.2.2 主函数2.2.3 运行结果 2.3 调整窗口大小2.4 简单动画与按键控制2.4.1 简单旋转2.4.2 键盘控制 2.5 窗口反弹动画2.5.1 处理窗口大小变化2.5.2 渲染函数…

【Redis】缓存(下)

经过缓存这篇文章的概述&#xff0c;已经对缓存有了初步的了解和认知。在本篇文章中&#xff0c;主要是通过代码来实现缓存的应用&#xff0c;以及在使用缓存过程中出现的经典问题。 简单应用 需求&#xff1a;根据菜品id来查询缓存 流程&#xff1a;① 从缓存中查询&#x…

『功能项目』怪物的信息显示【15】

本章项目成果展示 我们打开上一篇14怪物反击主角复活的项目&#xff0c; 本章要做的事情是当主角进入怪物的攻击范围之内时显示怪物的血量信息 在Canvas创建一个空物体 将空物体GameObject钉到视角上方 重命名为KingInfoUI 在子级创建一个Image 在资源文件夹下创建一个空文件命…

【数据结构 | 每日一题】图的概念辨析

图的概念辨析 考点分析&#xff1a;我们学习数据结构图的第一小节就是&#xff1a;图的基本概念&#xff0c;我们会发现图的概念非常多且有些概念之间又很像&#xff0c;而对于初学者来说&#xff0c;相比树的概念是不好理解的&#xff0c;很容易搞混&#xff0c;因此做了这么…

Tapd敏捷开发平台的使用心得

Tapd敏捷开发平台的使用心得 一、Tapd 简介 TAPD(Tencent Agile Product Development),腾讯敏捷产品研发平台行业领先的敏捷协作方案,贯穿敏捷产品研发生命周期的一站式服务,了解敏捷如下图 二、几个核心模块概念 需求迭代缺陷故事墙前期项目需求的管理,可以按类别建…