前端基于Phantom钱包创建SPL Token的安全方案需求
前端基于Phantom钱包创建SPL Token的可行方案
核心思路
所有操作依赖Phantom钱包完成签名,前端仅负责构建交易、发起请求,全程不触碰用户私钥,也无需生成额外密钥对,完全利用钱包自身的密钥对作为交易发起方和Token权限控制方。
方案一:不使用Anchor框架实现
1. 安装依赖
npm install @solana/web3.js @solana/spl-token @solana/wallet-adapter-phantom
2. 连接Phantom钱包
先实现钱包连接逻辑,获取已授权的钱包实例:
import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom'; import { Connection } from '@solana/web3.js'; // 初始化连接和钱包适配器 const connection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed'); // 可切换测试网 const phantomWallet = new PhantomWalletAdapter(); // 连接钱包函数 async function connectWallet() { try { await phantomWallet.connect(); console.log('钱包已连接,地址:', phantomWallet.publicKey.toString()); } catch (err) { console.error('连接失败:', err); } }
3. 创建SPL Token核心逻辑
利用spl-token库构建创建Token的交易,交由Phantom签名并发送:
import { createMint, getOrCreateAssociatedTokenAccount, mintTo } from '@solana/spl-token'; async function createSPLToken() { if (!phantomWallet.connected) { alert('请先连接钱包'); return; } const payer = phantomWallet.publicKey; const mintAuthority = payer; const freezeAuthority = payer; const decimals = 9; // Token精度,通常设为9 const initialSupply = 1000000; // 初始发行量 try { // 1. 创建Mint账户 const mint = await createMint( connection, phantomWallet, // 传入钱包适配器,由Phantom处理签名 mintAuthority, freezeAuthority, decimals ); console.log('Mint账户地址:', mint.toString()); // 2. 为创建者创建关联Token账户(可选,若需要直接 mint 到自己账户) const associatedTokenAccount = await getOrCreateAssociatedTokenAccount( connection, phantomWallet, mint, payer ); console.log('关联Token账户地址:', associatedTokenAccount.address.toString()); // 3. mint初始代币到关联账户 await mintTo( connection, phantomWallet, mint, associatedTokenAccount.address, mintAuthority, initialSupply * Math.pow(10, decimals) // 转换为最小单位 ); alert('SPL Token创建成功!'); } catch (err) { console.error('创建失败:', err); alert('创建失败,请检查钱包余额或重试'); } }
方案二:使用Anchor框架实现
1. 安装依赖
npm install @solana/web3.js @solana/spl-token @solana/wallet-adapter-phantom @project-serum/anchor
2. 编写Anchor合约(后端侧)
合约中实现创建Token的核心逻辑,以下是关键代码片段:
use anchor_lang::prelude::*; use spl_token::instruction::{create_mint, mint_to}; declare_id!("YOUR_PROGRAM_ID"); #[program] pub mod spl_token_creator { use super::*; pub fn create_mint(ctx: Context<CreateMint>, decimals: u8, initial_supply: u64) -> Result<()> { // 构建创建Mint的指令 let create_mint_ix = create_mint( &spl_token::id(), &ctx.accounts.mint.key(), &ctx.accounts.authority.key(), Some(&ctx.accounts.authority.key()), decimals, )?; invoke(&create_mint_ix, &[ ctx.accounts.mint.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.rent.to_account_info(), ])?; // 构建Mint代币的指令(可选) let mint_to_ix = mint_to( &spl_token::id(), &ctx.accounts.mint.key(), &ctx.accounts.associated_token_account.key(), &ctx.accounts.authority.key(), &[], initial_supply * 10u64.pow(decimals as u32), )?; invoke(&mint_to_ix, &[ ctx.accounts.mint.to_account_info(), ctx.accounts.associated_token_account.to_account_info(), ctx.accounts.authority.to_account_info(), ])?; Ok(()) } } #[derive(Accounts)] pub struct CreateMint<'info> { #[account(mut)] pub authority: Signer<'info>, #[account( init, payer = authority, mint::decimals = decimals, mint::authority = authority, mint::freeze_authority = authority, )] pub mint: Account<'info, spl_token::state::Mint>, #[account( init_if_needed, payer = authority, associated_token::mint = mint, associated_token::authority = authority, )] pub associated_token_account: Account<'info, spl_token::state::Account>, pub rent: Sysvar<'info, Rent>, pub system_program: Program<'info, System>, pub token_program: Program<'info, spl_token::program::SplToken>, pub associated_token_program: Program<'info, spl_associated_token_account::program::SplAssociatedTokenAccount>, }
3. 前端调用Anchor合约
通过Anchor Provider连接Phantom钱包,调用合约方法:
import { AnchorProvider, Program, web3 } from '@project-serum/anchor'; import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom'; import idl from './idl.json'; // 合约IDL文件 import * as splToken from '@solana/spl-token'; const connection = new web3.Connection('https://api.mainnet-beta.solana.com', 'confirmed'); const phantomWallet = new PhantomWalletAdapter(); const programId = new web3.PublicKey('YOUR_PROGRAM_ID'); async function connectAndCreateToken() { if (!phantomWallet.connected) { await phantomWallet.connect(); } // 初始化Anchor Provider const provider = new AnchorProvider( connection, phantomWallet, AnchorProvider.defaultOptions() ); const program = new Program(idl, programId, provider); try { // 生成Mint账户地址(由Anchor自动处理) const mintKeypair = web3.Keypair.generate(); await program.methods .createMint(9, 1000000) // 传入精度和初始发行量 .accounts({ authority: phantomWallet.publicKey, mint: mintKeypair.publicKey, systemProgram: web3.SystemProgram.programId, tokenProgram: splToken.TOKEN_PROGRAM_ID, associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID, }) .signers([mintKeypair]) // Mint账户需要签名创建,但仅需生成公钥,签名由Phantom处理 .rpc(); alert('Token创建成功!Mint地址:' + mintKeypair.publicKey.toString()); } catch (err) { console.error('创建失败:', err); alert('创建失败,请检查钱包余额或重试'); } }
关键注意事项
- 确保用户钱包有足够的SOL支付交易手续费和账户创建费用
- 交易发起前需检查钱包是否已连接,避免无权限操作
- 可根据需求调整Token的精度、初始发行量、权限设置(如冻结权限可设为null)
内容的提问来源于stack exchange,提问作者Prashant Sriharsh ATR634
相关产品推荐
相关产品推荐

