You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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处理。
  • 未正确处理本地生成的mint Keypair签名——需先对交易做部分签名,再交给钱包完成最终签名。

修正后的代码

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警告。
  • 对本地生成的mint Keypair执行tx.partialSign(mint),该账户签名只能由本地Keypair完成,钱包无法代签。
  • 交易参数直接在创建时传入,代码更简洁。
  • 增加交易确认步骤,确保交易成功上链。

内容的提问来源于stack exchange,提问作者Yasser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:11:02