你的第一个Solana SPL

news/2025/1/15 20:58:33/文章来源:https://www.cnblogs.com/sjie/p/18518801

简介 TFT

你的第一个SPL The first token

技术栈和库

  • Rust
  • Anchor框架
  • Typescript(测试)

开发环境和其它网络地址

  • DevNet: https://api.devnet.solana.com
  • TestNet: https://api.testnet.solana.com
  • MainNet: https://api.mainnet-beta.solana

开发环境设置

1.本教程使用的时 DevNet
2.浏览器打开 https://beta.solpg.io/
3.创建项目
4.请求空头

请求空投

Sol程序开发

// ========= Step 1 引用框架// 1.管理账户的
use anchor_lang::prelude::*;// 2.管理代币的
use anchor_spl::{associated_token::AssociatedToken, // 处理关联代币账户的功能metadata::{create_metadata_accounts_v3,       // 创建元数据账户的功能mpl_token_metadata::types::DataV2, // 元数据的结构体定义CreateMetadataAccountsV3,          // 创建元数据账户的指令结构体Metadata as Metaplex,              // 将 Metadata 重命名为 Metaplex,以便于使用},token::{mint_to,      // 铸币功能Mint,         // 代币铸造的结构体MintTo,       // 铸币指令的结构体Token,        // 代币的基本功能TokenAccount, // 代币账户的结构体},
};// 2.加载程序id(自己获取,或者系统生成)
declare_id!("7CR9ATZRxzEmCSM91UkumMJ6b8h5ompMcxTnUKLc8z4e");// 3.代币主程序
#[program]
mod token_minter {use super::*;// 3.1初始化 SPLpub fn init_token(ctx: Context<InitToken>, metadata: InitTokenParams) -> Result<()> {let seeds = &["mint".as_bytes(), &[ctx.bumps.mint]];let signer = [&seeds[..]];let token_data: DataV2 = DataV2 {name: metadata.name,symbol: metadata.symbol,uri: metadata.uri,seller_fee_basis_points: 0,creators: None,collection: None,uses: None,};let metadata_ctx = CpiContext::new_with_signer(ctx.accounts.token_metadata_program.to_account_info(),CreateMetadataAccountsV3 {payer: ctx.accounts.payer.to_account_info(),update_authority: ctx.accounts.mint.to_account_info(),mint: ctx.accounts.mint.to_account_info(),metadata: ctx.accounts.metadata.to_account_info(),mint_authority: ctx.accounts.mint.to_account_info(),system_program: ctx.accounts.system_program.to_account_info(),rent: ctx.accounts.rent.to_account_info(),},&signer,);create_metadata_accounts_v3(metadata_ctx, token_data, false, true, None)?;msg!("Token mint created successfully.");Ok(())}// 3.2 铸造 SPLpub fn mint_tokens(ctx: Context<MintTokens>, quantity: u64) -> Result<()> {let seeds = &["mint".as_bytes(), &[ctx.bumps.mint]];let signer = [&seeds[..]];mint_to(CpiContext::new_with_signer(ctx.accounts.token_program.to_account_info(),MintTo {authority: ctx.accounts.mint.to_account_info(),to: ctx.accounts.destination.to_account_info(),mint: ctx.accounts.mint.to_account_info(),},&signer,),quantity,)?;Ok(())}
}// 4.主程序需要的账户
#[derive(Accounts)]
#[instruction(params: InitTokenParams)]
pub struct InitToken<'info> {// Metaplex 账户#[account(mut)]pub metadata: UncheckedAccount<'info>,#[account(init,seeds = [b"mint"],bump,payer = payer,mint::decimals = params.decimals,mint::authority = mint,)]pub mint: Account<'info, Mint>,#[account(mut)]pub payer: Signer<'info>,pub rent: Sysvar<'info, Rent>,pub system_program: Program<'info, System>,pub token_program: Program<'info, Token>,pub token_metadata_program: Program<'info, Metaplex>,
}#[derive(Accounts)]
pub struct MintTokens<'info> {#[account(mut,seeds = [b"mint"],bump,mint::authority = mint,)]pub mint: Account<'info, Mint>,#[account(init_if_needed,payer = payer,associated_token::mint = mint,associated_token::authority = payer,)]pub destination: Account<'info, TokenAccount>,#[account(mut)]pub payer: Signer<'info>,pub rent: Sysvar<'info, Rent>,pub system_program: Program<'info, System>,pub token_program: Program<'info, Token>,pub associated_token_program: Program<'info, AssociatedToken>,
}// 5.账户的数据
// 5. 定义init令牌参数
#[derive(AnchorSerialize, AnchorDeserialize, Debug, Clone)]
pub struct InitTokenParams {pub name: String,pub symbol: String,pub uri: String,pub decimals: u8,
}

部署

部署完成


测试

替换anchor.test.ts内容

describe("Test Minter", () => {const METADATA_SEED = "metadata";const TOKEN_METADATA_PROGRAM_ID = new web3.PublicKey("F64uG9fPnEZYZ6G4Nbbuz6D715gYAKw1j71etHLNjHx2"); // 你的程序 ID,和程序相同const MINT_SEED = "mint";// SPL基础信息const payer = pg.wallet.publicKey;const metadata = {name: "My The first token",symbol: "TFT",uri: "https://5vfxc4tr6xoy23qefqbj4qx2adzkzapneebanhcalf7myvn5gzja.arweave.net/7UtxcnH13Y1uBCwCnkL6APKsge0hAgacQFl-zFW9NlI",decimals: 9,};const mintAmount = 1000;const [mint] = web3.PublicKey.findProgramAddressSync([Buffer.from(MINT_SEED)],pg.PROGRAM_ID);const [metadataAddress] = web3.PublicKey.findProgramAddressSync([Buffer.from(METADATA_SEED),TOKEN_METADATA_PROGRAM_ID.toBuffer(),mint.toBuffer(),],TOKEN_METADATA_PROGRAM_ID);// 测试初始化it("initialize", async () => {const info = await pg.connection.getAccountInfo(mint);if (info) {return;}console.log("  Mint not found. Attempting to initialize.");const context = {metadata: metadataAddress,mint,payer,rent: web3.SYSVAR_RENT_PUBKEY,systemProgram: web3.SystemProgram.programId,tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,};const tx = await pg.program.methods.initToken(metadata).accounts(context).transaction();const txHash = await web3.sendAndConfirmTransaction(pg.connection,tx,[pg.wallet.keypair],{ skipPreflight: true });console.log(`  https://explorer.solana.com/tx/${txHash}?cluster=devnet`);const newInfo = await pg.connection.getAccountInfo(mint);assert(newInfo, "  Mint should be initialized.");});// 测试铸造it("mint tokens", async () => {const destination = await anchor.utils.token.associatedAddress({mint: mint,owner: payer,});let initialBalance: number;try {const balance = await pg.connection.getTokenAccountBalance(destination);initialBalance = balance.value.uiAmount;} catch {// Token account not yet initiated has 0 balanceinitialBalance = 0;}const context = {mint,destination,payer,rent: web3.SYSVAR_RENT_PUBKEY,systemProgram: web3.SystemProgram.programId,tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,associatedTokenProgram: anchor.utils.token.ASSOCIATED_PROGRAM_ID,};const txHsh = await pg.program.methods.mintTokens(new BN(mintAmount * 10 ** metadata.decimals)).accounts(context).signers([pg.wallet.keypair]).rpc();// const txHash = await web3.sendAndConfirmTransaction(//   pg.connection,//   tx,//   [pg.wallet.keypair],//   { skipPreflight: true }// );console.log(`mint Hash =>`, txHsh);const postBalance = (await pg.connection.getTokenAccountBalance(destination)).value.uiAmount;assert.equal(initialBalance + mintAmount,postBalance,"Post balance should equal initial plus mint amount");});
});

铸造

运行测试代码,进行SPL铸造, 记得把密钥导入 Phantom(切换网络)

增发

注释初始化代码,增加第二次SPL铸造

总结

Anchor框架总结

// 1.管理账户的
use anchor_lang::prelude::*;// 管理代币的
use anchor_spl::{associated_token::AssociatedToken, // 处理关联代币账户的功能metadata::{create_metadata_accounts_v3,       // 创建元数据账户的功能mpl_token_metadata::types::DataV2, // 元数据的结构体定义CreateMetadataAccountsV3,          // 创建元数据账户的指令结构体Metadata as Metaplex,              // 将 Metadata 重命名为 Metaplex,以便于使用},token::{mint_to,      // 铸币功能Mint,         // 代币铸造的结构体MintTo,       // 铸币指令的结构体Token,        // 代币的基本功能TokenAccount, // 代币账户的结构体},
};

补充

  • Sol游乐场
  • Sol浏览器

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

27 3D图形

3d转2d,用3d投影的数学思想;直线角度,正交投影,投透视投射;一般是三角形,三点可以确定i个平面;从投影角度来绘制多面体结构; 前后采取扫描线渲染 阴暗,通过三角形界面法线方向与光源角度偏移度,平面着色 纹理通过扫面线

项目管理计划都有什么作用

项目管理计划是项目成功的关键导航工具,其主要作用包括确定目标与范围、资源分配、时间管理、风险识别与应对,以及质量保证。该计划帮助团队和利益相关者对项目有全面而明确的认识。特别值得一提的是,通过时间管理,项目管理计划确保了各个阶段和活动在预定时间内完成,从而…

多租户系统的应用架构

大家好,我是汤师爷~ 我们看下多租户系统的应用架构是如何从一层层构建起来的。1、应用层设计 应用层的主要作用是为具体的用户场景提供应用服务,帮助用户在特定场景下完成操作。通过编排领域层的各项能力,实现SaaS产品的核心功能。应用层包含两个关键模块:租户运营平台模块…

环境搭建

一、环境的介绍 (1)测试环境分类; a、开发环境 , 开发 b、测试环境 ,(也叫sit环境 ,uat环境) 测试人员 c、线上环境(也叫生成环境) 运营 (2)测试环境作用: a、用于功能测试 b、寻找bug c、编写测试用例等 (3)环境的结构: lampj=linux+apache+mysql+j…

26 用户图形界面

计算机鼠标+图形界面 桌面,窗口,菜单,图标,指针

Navicat 连接 MySQL 失败:2002-can‘t connect to server on localhost(10061)问题解决

连接不上问题可能有如下原因服务器安全组中没有配置3306端口mysql服务端口只开放本地了如下:修改 /etc/mysql/mysql.conf.d/mysqld.cnf 中 bind-address 和 mysqlx-bind-address 注释掉重启mysql服务systemctl restart mysqlmysql登录用户的host为localhost只允许本地连接查看…

电容屏和电阻屏有哪些本质区别_1

电容屏和电阻屏的区别主要包括:1.工作原理;2.触控灵敏度和精准度;3.多点触控能力;4.对外界影响的抵抗力;5.制造成本;6.兼容性;7.使用寿命。工作原理是两者最根本的区别,电容屏利用人体电流进行操作,而电阻屏依赖于物理压力。电容屏通常触控更灵敏、支持多点触控,但成…

Goby 漏洞发布|Apache Solr /solr/admin/info/properties:/admin/info/key 权限绕过漏洞(CVE-2024-45216)

漏洞名称:Apache Solr /solr/admin/info/properties:/admin/info/key 权限绕过漏洞(CVE-2024-45216) English Name:Apache Solr /solr/admin/info/properties:/admin/info/key Permission Bypass Vulnerability(CVE-2024-45216) CVSS core: 7.3 漏洞描述: Apache Solr是一…

tenda初始密码八位数是什么

Tenda路由器的初始密码通常是一个8位数字,通常位于路由器背面的标签上或是设备的说明书中。此密码用于首次设置和连接WiFi网络。对于不同的Tenda模型,初始密码可能不同。**1、查找标签:**路由器背面通常有带有初始密码的标签。**2、查阅说明书:**设备随附的说明书通常包含初…

信息搜集——原始

!!!在渗透测试过程中,信息收集是非常重要的一个环节,此环节的信息将影响到后续成功几率,掌握信息的多少将决定发现漏洞的机会的大小,换言之决定着是否能完成目标的测试任务。!!! 一.路径(可以通过根据已知的域名反查,分析出此域名的注册人、公司地址、电话、邮箱、…

浅谈对账拓展功能设计

在Saas类产品中,对账功能是一个拓展比较多的设计,不同企业有着不同的要求。这篇文章,我们看看作者的总结。需求场景:不同企业针对对账单的表单字段有不同的要求,如何满足不同企业用户对于对账的个性化字段诉求,包含核对本账期内发生的企业支付明细、本账期可开票结账明细…