【问题标题】:How to create account/signer using Phantom Wallet provider?如何使用 Phantom Wallet 提供商创建帐户/签名者?
【发布时间】:2022-07-19 04:27:05
【问题描述】:

我正在遵循 Solana NFT 的内部说明来创建上架 NFT 待售的流程。 根据这个 NFT,https://solscan.io/tx/25g9L7rDCn8ZbZAZoCvyVNe5woZUoK2PVU3VEXftqySa2EYsLUJB2GA42qDwxsezUBRH2A9eJX1iUUD2LCK9Fua9,第一条指令是创建一个帐户。

指令显示

NewAccount - E61SDPzHP61C4KwwiSqG4FAHXof852wsaSjh3F4kLbwmicon

Source - H2eud1RCJu8u8vEQ8jJLQ32jM5oKfARGxz5LwEKKfTLuicon

TransferAmount(SOL) - 0.00223416

ProgramOwner - M2mx93ekt1fmXSVkTrUL9xVFHkmME8HTUi5Cyc5aF7Kicon

New Account 似乎是新生成的帐户,Source 是用户将钱包连接到客户端时使用的钱包。

我正在使用 Solana Cookbook 中的此代码作为参考

import { clusterApiUrl, Connection, PublicKey, Keypair, Transaction, SystemProgram } from "@solana/web3.js";
import { Token, TOKEN_PROGRAM_ID, AccountLayout } from "@solana/spl-token";
import * as bs58 from "bs58";

(async () => {
  // connection
  const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

  // 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
  const feePayer = Keypair.fromSecretKey(
    bs58.decode("588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2")
  );

  // G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
  const alice = Keypair.fromSecretKey(
    bs58.decode("4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp")
  );

  const mintPubkey = new PublicKey("54dQ8cfHsW1YfKYpmdVZhWpb9iSi6Pac82Nf7sg3bVb");

  // generate a new keypair for token account
  const tokenAccount = Keypair.generate();
  console.log(`token account: ${tokenAccount.publicKey.toBase58()}`);

  let tx = new Transaction().add(
    // create token account
    SystemProgram.createAccount({
      fromPubkey: feePayer.publicKey,
      newAccountPubkey: tokenAccount.publicKey,
      space: AccountLayout.span,
      lamports: await Token.getMinBalanceRentForExemptAccount(connection),
      programId: TOKEN_PROGRAM_ID,
    }),
    /**... some other instruction*/
  );
  console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer, tokenAccount])}`);
})();

据我了解,在这种情况下,feePayer 是连接钱包的用户。 (Source 来自说明),tokenAccount 是我们要将 SOL 转移到的帐户(NewAccount 来自说明),programID 是说明中的 ProgramOwner

当我从 Solana Cookbook 运行这个确切的代码时,它可以工作。 当我尝试将provider 用作feePayer(在客户端连接的钱包)时,它不起作用。

我有一个函数来获取我的提供者

getProvider = ()  => {
    if ("solana" in window) {
        const anyWindow = window;
        const provider = anyWindow.solana;
        if (provider.isPhantom) {
            return provider;
        }
    }
    window.open("https://phantom.app/", "_blank");
};

然后我抓住我的提供者

const provider = this.getProvider();

我将使用Keypair.fromSecretKey 创建的原始feePayer 替换为provider

关于为什么提供者不能作为await connection.sendTransaction(tx, [provider, tokenAccount]) 中的签名者之一,我的假设是因为签名者需要密钥。

所以我尝试做的是使用我在网上找到的一些关于如何签署交易的代码自己签署交易。

const blockHash = await connection.getRecentBlockhash()
tx.feePayer = provider.publicKey
tx.recentBlockhash = await blockHash.blockhash
const signed = await provider.signTransaction(tx);

这运行良好,我可以在执行console.log(signed); 时看到结果 我遇到的问题是有 2 个签名,其中一个为空。一个是provider 的签名,另一个是tokenAccount 的签名。 当我使用console.log() 显示provider 的公钥和tokenAccount 的公钥并尝试将其与签名中的公钥匹配时,我发现tokenAccount 的签名是一个返回 null。

所以当运行const signature = await connection.sendRawTransaction(signed.serialize()); 时,我收到来自signed.serialize() 的错误消息,说签名验证失败

我在这里做错了什么? 我可以从连接虚拟钱包的用户创建签名者吗?如果没有,我该如何签署交易,以使两个签名都不为空?

【问题讨论】:

  • 那些是真正的钥匙吗?
  • 加倍 @0stone0 所说的 - 您需要立即重新颁发这些密钥。
  • 不,这些键来自 solana 食谱参考 solanacookbook.com/references/…

标签: javascript solana solana-web3js


【解决方案1】:

所以我建议使用wallet-adapter 连接并从钱包发送交易。

这将使上面的代码看起来像这样:

const { publicKey, sendTransaction } = useWallet();

// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
    bs58.decode("4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp")
);

const mintPubkey = new PublicKey("54dQ8cfHsW1YfKYpmdVZhWpb9iSi6Pac82Nf7sg3bVb");

// generate a new keypair for token account
const tokenAccount = Keypair.generate();
console.log(`token account: ${tokenAccount.publicKey.toBase58()}`);

let tx = new Transaction().add(
    // create token account
    SystemProgram.createAccount({
      fromPubkey: publicKey,
      newAccountPubkey: tokenAccount.publicKey,
      space: AccountLayout.span,
      lamports: await Token.getMinBalanceRentForExemptAccount(connection),
      programId: TOKEN_PROGRAM_ID,
    }),
    /**... some other instruction*/
);
const signature = await sendTransaction(transaction, connection);

await connection.confirmTransaction(signature, 'processed');

【讨论】:

【解决方案2】:

您好,我有类似的问题, 有两个签名者管理员和用户, admin 正在从节点签署 tx 并序列化 tx。 这是我发送到前端 和用户签名。 但最初签名为空,所以 wallet.signTransaction(tx); 给出签名验证失败

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
【解决方案3】:

您必须在发送交易之前使用 tokenAccount 进行部分签名。

const blockHash = await connection.getRecentBlockhash()
tx.feePayer = provider.publicKey
tx.recentBlockhash = await blockHash.blockhash
const signed = await provider.signTransaction(tx);
// now sign with the tokenAccount
signed.partialSign(tokenAccount);

【讨论】:

    猜你喜欢
    • 2022-10-16
    • 2011-11-22
    • 2021-07-30
    • 2017-11-24
    • 2020-07-29
    • 1970-01-01
    • 2019-03-30
    • 2013-06-29
    • 2019-05-18
    相关资源
    最近更新 更多