【发布时间】: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