我正试图创建一个以我的程序为权威的铸币厂,我正在努力使我的CPI呼叫正确。
下面是我到目前为止所拥有的一个玩具例子:
use anchor_lang::prelude::*;
use anchor_spl::token::{
self, set_authority, spl_token::instruction::AuthorityType, SetAuthority, Token,
};
use program::MintTest;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod mint_test {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let bump = *ctx.bumps.get("mint").unwrap();
let seeds = vec![bump];
let seeds = vec![b"some-seed".as_ref(), seeds.as_slice()];
let seeds = vec![seeds.as_slice()];
let seeds = seeds.as_slice(); // ❓ slightly unrelated but I'd love to understand why all this nesting is required
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_accounts = SetAuthority {
account_or_mint: ctx.accounts.mint.to_account_info(),
current_authority: ctx.accounts.program.to_account_info(),
};
let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, seeds);
set_authority(cpi_ctx, AuthorityType::MintTokens, None)?; // ❌ This fails
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init,
payer = signer,
mint::decimals = 0,
mint::authority = program,
seeds = [b"some-seed".as_ref()],
bump,
)]
pub mint: Account<'info, token::Mint>,
#[account(mut)]
pub signer: Signer<'info>,
pub token_program: Program<'info, Token>,
pub system_program: Program<'info, System>,
pub rent: Sysvar<'info, Rent>,
pub program: Program<'info, MintTest>,
}
薄荷的创建是正确的,但是任何CPI调用都会在Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account
中失败(set_authority
只是一个例子,我尝试了其他CPI,比如mint_to
,但没有成功)。
如果我把TX的签字人设置为权威的话,它确实有效,所以我认为我对签名者的种子做了一些错误的事情,但我就是搞不明白,我已经被困在这个问题上好几个小时了。
这也是我的TS测试:
import * as anchor from "@project-serum/anchor";
import { Program } from "@project-serum/anchor";
import { MintTest } from "../target/types/mint_test";
describe("mint-test", () => {
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.MintTest as Program<MintTest>;
it("Is initialized!", async () => {
const [mint] = await anchor.web3.PublicKey.findProgramAddress(
[Buffer.from("some-seed")],
program.programId
);
const tx = await program.methods
.initialize()
.accounts({
mint,
program: program.programId,
})
.rpc();
console.log("Your transaction signature", tx);
});
});
预先感谢您的帮助
发布于 2022-10-04 16:02:54
所以,我对这一切的理解似乎有点过激了。一个程序不能签署,所以我们的程序不能成为我们造币厂的权威。
但是,我们可以指定PDA作为我们造币厂的所有者,并使用用于查找PDA地址的种子来“签名”指令。
以下工作:
use anchor_lang::prelude::*;
use anchor_spl::token::{
self, set_authority, spl_token::instruction::AuthorityType, SetAuthority, Token,
};
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod mint_test {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let bump = *ctx.bumps.get("auth").unwrap();
let seeds = vec![bump];
let seeds = vec![b"auth".as_ref(), seeds.as_slice()];
let seeds = vec![seeds.as_slice()];
let seeds = seeds.as_slice();
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_accounts = SetAuthority {
account_or_mint: ctx.accounts.mint.to_account_info(),
current_authority: ctx.accounts.auth.to_account_info(),
};
let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, seeds);
set_authority(cpi_ctx, AuthorityType::MintTokens, None)?;
Ok(())
}
}
#[account]
pub struct Auth {}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init,
space = 8,
payer = signer,
seeds = [b"auth".as_ref()],
bump,
)]
pub auth: Account<'info, Auth>,
#[account(
init,
payer = signer,
mint::decimals = 0,
mint::authority = auth,
seeds = [b"some-seed".as_ref()],
bump,
)]
pub mint: Account<'info, token::Mint>,
#[account(mut)]
pub signer: Signer<'info>,
pub token_program: Program<'info, Token>,
pub system_program: Program<'info, System>,
pub rent: Sysvar<'info, Rent>,
}
而测试:
import * as anchor from "@project-serum/anchor";
import { Program } from "@project-serum/anchor";
import { MintTest } from "../target/types/mint_test";
describe("mint-test", () => {
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.MintTest as Program<MintTest>;
it("Is initialized!", async () => {
const [auth] = await anchor.web3.PublicKey.findProgramAddress(
[Buffer.from("auth")],
program.programId
);
const [mint] = await anchor.web3.PublicKey.findProgramAddress(
[Buffer.from("some-seed")],
program.programId
);
const tx = await program.methods
.initialize()
.accounts({
mint,
auth,
})
.rpc();
console.log("Your transaction signature", tx);
});
});
希望这对某人有帮助。
发布于 2022-11-13 17:03:45
正如在这个答案https://stackoverflow.com/a/73950605/20494156中所述,程序不能单独签名,唯一的方法是使用PDA。有关作为签名者的程序的更多信息可以在这里找到:https://book.anchor-lang.com/anchor_in_depth/PDAs.html#programs-as-signers
只想添加以下关于种子嵌套的内部注释问题,这个答案可能会有帮助:https://solana.stackexchange.com/questions/3002/can-there-be-two-signers-in-an-anchor-cpi。
基本上,您可以发送多个种子数组,以防出现多个PDA签名。
https://stackoverflow.com/questions/73944428
复制相似问题