Я пытаюсь создать Mint с моей программой в качестве авторитета, и я изо всех сил пытаюсь правильно настроить вызовы 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>,
}
Монетный двор создается правильно, но вызов any 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.info("Your transaction signature", tx);
});
});
Заранее спасибо за помощь 😇
Так что, похоже, мое понимание всего этого было немного неправильным. Программа просто не может подписывать, поэтому наша программа не может быть авторитетом нашего монетного двора.
Однако мы можем назначить КПК владельцем нашего монетного двора и использовать семена, используемые для нахождения адреса этого КПК, для «подписания» инструкций.
Следующие работы:
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.info("Your transaction signature", tx);
});
});
Надеюсь, это кому-то поможет.
Просто хотел добавить следующее относительно вопроса внутренних комментариев о вложении семян, этот ответ может быть полезен: https://solana.stackexchange.com/questions/3002/can-there-be-two-signers-in- якорь-CPI.
В основном идея состоит в том, что вы можете отправить несколько массивов начальных значений в случае, если имеется несколько подписей КПК.
Ваш ответ может быть улучшен с помощью дополнительной вспомогательной информации. Пожалуйста, отредактируйте , чтобы добавить дополнительные сведения, такие как цитаты или документация, чтобы другие могли подтвердить правильность вашего ответа. Вы можете найти больше информации о том, как писать хорошие ответы в справочном центре.