如何无需自建铸造账户,通过Phantom钱包在Solana链上铸造NFT
解决方案
完全可以直接使用Phantom钱包完成铸造,不需要先通过随机生成的密钥对中转,核心逻辑是把原来由本地生成Keypair完成的签名操作,替换为调用Phantom钱包的签名能力即可,Phantom不会向网页暴露私钥,所有签名操作都在钱包内部完成,安全性有保障。
核心修改点
- 补充Phantom钱包连接逻辑,获取用户授权的钱包公钥作为付款方、铸币权限方
- 移除本地随机生成
Keypair的相关逻辑,不再需要中转账户 - 所有交易构造完成后调用Phantom的
signAndSendTransaction方法完成签名上链,不需要传入本地私钥 - 直接将代币铸造到Phantom钱包的关联代币账户,省略额外转账步骤,降低gas消耗
适配后的完整代码
import * as web3 from '@solana/web3.js'; import * as splToken from '@solana/spl-token'; const getProvider = async () => { if ("solana" in window) { const provider = window.solana; if (provider.isPhantom) { // 新增连接逻辑,请求用户授权连接钱包 await provider.connect(); console.log("Phantom已连接"); return provider; } } else { alert("请先安装Phantom钱包"); } }; const mintingTest = async () => { const phantomProvider = await getProvider(); // 直接使用Phantom钱包的公钥作为所有操作的权限方 const walletPublicKey = phantomProvider.publicKey; console.log("钱包公钥: ", walletPublicKey.toString()); const connection = new web3.Connection( web3.clusterApiUrl('devnet'), 'confirmed', ); // 1. 新建mint账户 const mint = web3.Keypair.generate(); // 计算mint账户所需租金 const lamports = await splToken.getMinimumBalanceForRentExemptMint(connection); // 构造创建mint账户的交易 const transaction = new web3.Transaction().add( // 创建账户指令 web3.SystemProgram.createAccount({ fromPubkey: walletPublicKey, newAccountPubkey: mint.publicKey, space: splToken.MINT_SIZE, lamports, programId: splToken.TOKEN_PROGRAM_ID, }), // 初始化mint指令 splToken.createInitializeMintInstruction( mint.publicKey, 0, // 铸NFT的话小数位设为0,FT可自定义 walletPublicKey, // 铸币权限 null, // 冻结权限,不需要可以设为null splToken.TOKEN_PROGRAM_ID ) ); // 让Phantom签名并发送交易 transaction.feePayer = walletPublicKey; transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash; // 这里要签名mint账户的私钥,因为是新建的账户,本地生成的所以可以直接加 transaction.partialSign(mint); // 剩余部分让Phantom签名 const signedTx = await phantomProvider.signTransaction(transaction); const txId = await connection.sendRawTransaction(signedTx.serialize()); await connection.confirmTransaction(txId, 'confirmed'); console.log("Mint账户创建成功,地址:", mint.publicKey.toString()); // 2. 获取/创建钱包的关联代币账户 const tokenAccount = await splToken.getOrCreateAssociatedTokenAccount( connection, // 这里传phantomProvider作为signer,会自动调用钱包签名创建账户(如果不存在的话) phantomProvider, mint.publicKey, walletPublicKey ); console.log("关联代币账户地址:", tokenAccount.address.toString()); // 3. 铸造代币到自己的关联账户 const mintTx = new web3.Transaction().add( splToken.createMintToInstruction( mint.publicKey, tokenAccount.address, walletPublicKey, 1, // 铸1个,因为小数位是0,就是1个NFT [], splToken.TOKEN_PROGRAM_ID ) ); mintTx.feePayer = walletPublicKey; mintTx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash; const signedMintTx = await phantomProvider.signTransaction(mintTx); const mintTxId = await connection.sendRawTransaction(signedMintTx.serialize()); await connection.confirmTransaction(mintTxId, 'confirmed'); console.log("铸造成功,交易ID:", mintTxId); // 查询余额 const balance = await splToken.getMint(connection, mint.publicKey); console.log("当前铸造总量:", balance.supply.toString()); };
注意事项
- 测试前请确保你的Phantom钱包切换到了Devnet网络,且有足够的Devnet SOL支付交易手续费
- 代码中默认是铸造NFT的配置,如果要铸造可拆分的同质化代币,可自行调整小数位和铸造数量
- 所有需要签名的操作都会触发Phantom钱包的确认弹窗,手动确认后才会执行上链操作
内容的提问来源于stack exchange,提问作者Tabish Shafi
相关产品推荐
相关产品推荐

