Solana Anchor改用Instruction与Phantom signAndSendTransaction解决恶意dApp警告
解决Phantom钱包恶意dApp警告:改用signAndSendTransaction实现NFT铸造
我的NFT铸造逻辑原本可以正常运行,但Phantom钱包会弹出“此dApp可能存在恶意,除非确认安全否则请勿执行”的警告。根据要求,需要改用Phantom的signAndSendTransaction方法来消除这个警告。
原始可运行代码
export default async function mintNFT(metadata: MintNFTResponse, wallet) { const provider = new AnchorProvider(connection, wallet, { preflightCommitment: commitmentLevel, }); const signer = provider.wallet as AnchorWallet; if (!provider) { throw new Error("No provider found"); } const program = new Program( solanaNFTprogramInterface, solanaNFTprogramId, provider ) as Program<SolanaNft>; program.addEventListener("MintedEvent", (event, slot) => { eventEmitter.emit("minted", event); }); const umi = createUmi(endpoint) .use(walletAdapterIdentity(signer)) .use(mplTokenMetadata()); const mint = web3.Keypair.generate(); const associatedTokenAccount = await getAssociatedTokenAddress( mint.publicKey, signer.publicKey ); let metadataAccount = findMetadataPda(umi, { mint: publicKey(mint.publicKey), })[0]; let masterEditionAccount = findMasterEditionPda(umi, { mint: publicKey(mint.publicKey), })[0]; const tx = await program.methods .mintNft(metadata.name, metadata.symbol, metadata.uri, mintPrice) .accounts({ metadataAccount, mint: mint.publicKey, masterEditionAccount, associatedTokenAccount, signer: signer.publicKey, rent: web3.SYSVAR_RENT_PUBKEY, tokenProgram: TOKEN_PROGRAM_ID, recipient: config.recipientPubKey, systemProgram: web3.SystemProgram.programId, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, tokenMetadataProgram: MPL_TOKEN_METADATA_PROGRAM_ID, }) .signers([mint]) .rpc(); console.log( `mint nft tx: https://explorer.solana.com/tx/${tx}?cluster=devnet` ); console.log( `minted nft: https://explorer.solana.com/address/${mint.publicKey}?cluster=devnet` ); return tx; }
尝试改用Instruction和signAndSendTransaction的代码(无法正常运行)
export default async function mintNFT(metadata: MintNFTResponse, wallet) { const provider = new AnchorProvider(connection, wallet, { preflightCommitment: commitmentLevel, }); const signer = provider.wallet as AnchorWallet; if (!provider) { throw new Error("No provider found"); } const program = new Program( solanaNFTprogramInterface, solanaNFTprogramId, provider ) as Program<SolanaNft>; program.addEventListener("MintedEvent", (event, slot) => { eventEmitter.emit("minted", event); }); const umi = createUmi(endpoint) .use(walletAdapterIdentity(signer)) .use(mplTokenMetadata()); const mint = web3.Keypair.generate(); const associatedTokenAccount = await getAssociatedTokenAddress( mint.publicKey, signer.publicKey ); let metadataAccount = findMetadataPda(umi, { mint: publicKey(mint.publicKey), })[0]; let masterEditionAccount = findMasterEditionPda(umi, { mint: publicKey(mint.publicKey), })[0]; debugger; const instruction = await program.methods .mintNft(metadata.name, metadata.symbol, metadata.uri, mintPrice) .accounts({ metadataAccount, mint: mint.publicKey, masterEditionAccount, associatedTokenAccount, signer: signer.publicKey, rent: web3.SYSVAR_RENT_PUBKEY, tokenProgram: TOKEN_PROGRAM_ID, recipient: config.recipientPubKey, systemProgram: web3.SystemProgram.programId, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, tokenMetadataProgram: MPL_TOKEN_METADATA_PROGRAM_ID, }) .instruction(); const tx = new web3.Transaction().add(instruction); let blockhash = (await connection.getLatestBlockhash("finalized")) .blockhash; tx.recentBlockhash = blockhash; tx.feePayer = wallet.publicKey; await web3.sendAndConfirmTransaction(provider.connection, tx, [ wallet, mint, ]); return true; }
问题分析与修正方案
尝试的代码核心问题:
- 错误将
wallet(钱包适配器实例)作为签名者传入web3.sendAndConfirmTransaction,该方法仅接受Keypair类型签名者,钱包签名需通过Phantom的signAndSendTransaction处理。 - 未正确处理本地生成的
mintKeypair签名——需先对交易做部分签名,再交给钱包完成最终签名。
修正后的代码
export default async function mintNFT(metadata: MintNFTResponse, wallet) { const provider = new AnchorProvider(connection, wallet, { preflightCommitment: commitmentLevel, }); const signer = provider.wallet as AnchorWallet; if (!provider) { throw new Error("No provider found"); } const program = new Program( solanaNFTprogramInterface, solanaNFTprogramId, provider ) as Program<SolanaNft>; program.addEventListener("MintedEvent", (event, slot) => { eventEmitter.emit("minted", event); }); const umi = createUmi(endpoint) .use(walletAdapterIdentity(signer)) .use(mplTokenMetadata()); const mint = web3.Keypair.generate(); const associatedTokenAccount = await getAssociatedTokenAddress( mint.publicKey, signer.publicKey ); let metadataAccount = findMetadataPda(umi, { mint: publicKey(mint.publicKey), })[0]; let masterEditionAccount = findMasterEditionPda(umi, { mint: publicKey(mint.publicKey), })[0]; // 获取Anchor指令 const instruction = await program.methods .mintNft(metadata.name, metadata.symbol, metadata.uri, mintPrice) .accounts({ metadataAccount, mint: mint.publicKey, masterEditionAccount, associatedTokenAccount, signer: signer.publicKey, rent: web3.SYSVAR_RENT_PUBKEY, tokenProgram: TOKEN_PROGRAM_ID, recipient: config.recipientPubKey, systemProgram: web3.SystemProgram.programId, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, tokenMetadataProgram: MPL_TOKEN_METADATA_PROGRAM_ID, }) .instruction(); // 创建交易并设置必要参数 const latestBlockhash = await connection.getLatestBlockhash("finalized"); const tx = new web3.Transaction({ recentBlockhash: latestBlockhash.blockhash, feePayer: wallet.publicKey, }).add(instruction); // 用本地生成的mint Keypair对交易进行部分签名 tx.partialSign(mint); // 使用Phantom的signAndSendTransaction方法提交交易 const txResult = await wallet.signAndSendTransaction(tx, { preflightCommitment: commitmentLevel, }); console.log(`mint nft tx: ${txResult.signature}`); console.log(`minted nft: ${mint.publicKey.toBase58()}`); // 可选:等待交易确认 await connection.confirmTransaction({ signature: txResult.signature, blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, }, commitmentLevel); return txResult.signature; }
关键修改点
- 移除
web3.sendAndConfirmTransaction,改用钱包实例的signAndSendTransaction方法,这是Phantom推荐的安全方式,可消除恶意dApp警告。 - 对本地生成的
mintKeypair执行tx.partialSign(mint),该账户签名只能由本地Keypair完成,钱包无法代签。 - 交易参数直接在创建时传入,代码更简洁。
- 增加交易确认步骤,确保交易成功上链。
内容的提问来源于stack exchange,提问作者Yasser
相关产品推荐
相关产品推荐

