Anchor实现双签名者交易 指定公司方支付员工注册手续费
Anchor 双签名者员工注册交易实现(公司承担手续费)
现有代码问题
#[account(init)]修饰的新建employee_account缺少signer约束,不符合Solana链上强制规则:新创建的普通账户必须作为签名者参与交易才能完成初始化。- 结构体冗余定义了
authority: Signer字段,但测试代码的签名列表中没有传入对应密钥,交易执行时会直接抛出缺少签名的错误。 - 前端代码没有显式指定交易手续费支付方,默认会使用provider连接的钱包支付手续费,不符合公司付费的需求。
注意:#[account(init, payer = company_account)]仅指定新员工账户的租金支付方,和交易手续费的支付方没有绑定关系,手续费需要在交易构造时单独指定。
修正后的链上账户结构体
#[derive(Accounts)] pub struct SignupEmployee<'info> { #[account( init, payer = company_account, space = 8 + 32 + 32, signer // 新建账户必须加签名校验 )] pub employee_account: Account<'info, EmployeeState>, #[account(mut)] pub company_account: Signer<'info>, pub system_program: Program<'info, System>, }
这里去掉了冗余的authority字段,当前测试逻辑里新生成的employeeAccount密钥对就是员工持有的签名密钥,员工通过对该交易签名完成注册授权,不需要额外的authority字段。如果后续业务调整为员工使用已有独立钱包签名、员工状态账户为PDA的场景,再单独加员工签名字段即可。
修正后的前端测试代码
核心是显式指定feePayer为公司账户,保证交易手续费从公司账户扣除,签名列表只传入实际需要的两个签名密钥:
const employeeAccount = anchor.web3.Keypair.generate(); // 构造交易 const tx = await program.methods.signupEmployee() .accounts({ companyAccount: companyAccount.publicKey, employeeAccount: employeeAccount.publicKey, systemProgram: anchor.web3.SystemProgram.programId, }) .transaction(); // 明确指定交易手续费由公司账户支付 tx.feePayer = companyAccount.publicKey; // 获取最新区块哈希 tx.recentBlockhash = (await provider.connection.getLatestBlockhash()).blockhash; // 传入两个签名者:员工账户密钥、公司账户密钥,完成签名并上链 await anchor.web3.sendAndConfirmTransaction( provider.connection, tx, [employeeAccount, companyAccount] );
关键校验点
- 所有标记为
Signer类型、以及添加#[account(signer)]约束的账户,必须在交易签名列表中传入对应密钥,否则链上会直接拒绝交易。 - 交易手续费永远从
tx.feePayer指定的账户扣除,和账户结构体里的租金支付方配置无关,你可以根据业务需求将两者设为同一账户,也可以分开设置。 - 新创建的普通账户(非PDA)必须作为签名者参与初始化交易,这是Solana网络的底层规则,没有绕过方式。
内容的提问来源于stack exchange,提问作者alessandro buffoli
相关产品推荐
相关产品推荐

