Solana Anchor+React调用合约报reading '_bn'属性undefined错误
问题根因
控制台抛出的Cannot read properties of undefined (reading '_bn')是Solana Web3.js库解析公钥时的典型错误:当传入PublicKey构造函数的值为undefined时,内部校验逻辑尝试读取值的_bn属性就会触发这个类型错误。结合调用栈落点在greetingAccount.fetch()行,核心问题有3个:
- 你调用Anchor的
program.account.greetingAccount.fetch()方法时没有传入必填参数:要查询的链上账户公钥。Anchor的账户fetch方法不会自动匹配目标查询地址,空参调用时内部会把undefined传入PublicKey构造函数,直接触发报错。 - Rust合约里给
GreetingAccount分配的空间错误。Anchor中String类型存储需要占4字节长度前缀 + 实际字符串字节数,你当前写的8 + 32是按公钥长度计算的,根本存不下字符串内容,交易上链时会报空间不足错误。 - IDL里配置的合约地址前后带多余空格,初始化
programId时如果没处理空格,也会触发公钥解析错误。
修复步骤
1. 修正合约账户空间配置
修改合约中Execute结构体的账户空间分配,根据你要存储的字符串最大长度调整空间值,改完重新编译部署,生成新的IDL文件替换前端旧文件:
#[derive(Accounts)] pub struct Execute<'info> { // 8字节是Anchor固定的账户鉴别器长度,4字节是字符串长度前缀,后面100是给字符串内容留的容量,可按需调整 #[account(init, payer = user, space = 8 + 4 + 100)] pub gm_account: Account<'info, GreetingAccount>, #[account(mut)] pub user: Signer<'info>, pub system_program: Program<'info, System>, }
2. 修正前端调用逻辑
首先要确保greetingAccount密钥对的初始化时机正确,不会拿到undefined值,其次调用fetch时必须传入对应账户的公钥,同时处理IDL地址的多余空格:
// 注意trim掉IDL地址前后的多余空格,避免公钥解析失败 const programId = new PublicKey(idl.metadata.address.trim()); const getMsg = async () => { try { const provider = getProvider(); const program = new Program(idl, programId, provider); // 生成新的Greeting账户密钥对 const greetingAccount = Keypair.generate(); // 发送execute交易 await program.rpc.execute("a test message", { accounts: { gmAccount: greetingAccount.publicKey, user: provider.wallet.publicKey, systemProgram: SystemProgram.programId }, signers: [greetingAccount] }); // 必须传入要查询的账户公钥,不能空参调用 const onChainAccount = await program.account.greetingAccount.fetch(greetingAccount.publicKey); console.log("链上存储的消息:", onChainAccount.name); } catch (e) { console.error(e); } };
3. IDL配置校验
确保重新生成的IDL中,gmAccount的isSigner属性为true(因为是客户端生成的新账户,不属于PDA,交易签名时必须传入),账户字段定义和合约完全一致即可。
内容的提问来源于stack exchange,提问作者KylianMbappe
相关产品推荐
相关产品推荐

