首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Solana Anchor:带有PDA的CPI

Solana Anchor:带有PDA的CPI
EN

Stack Overflow用户
提问于 2022-10-04 07:31:37
回答 2查看 202关注 0票数 0

我正试图创建一个以我的程序为权威的铸币厂,我正在努力使我的CPI呼叫正确。

下面是我到目前为止所拥有的一个玩具例子:

代码语言:javascript
运行
复制
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测试:

代码语言:javascript
运行
复制
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);
  });
});

预先感谢您的帮助

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-10-04 16:02:54

所以,我对这一切的理解似乎有点过激了。一个程序不能签署,所以我们的程序不能成为我们造币厂的权威。

但是,我们可以指定PDA作为我们造币厂的所有者,并使用用于查找PDA地址的种子来“签名”指令。

以下工作:

代码语言:javascript
运行
复制
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>,
}

而测试:

代码语言:javascript
运行
复制
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);
  });
});

希望这对某人有帮助。

票数 0
EN

Stack Overflow用户

发布于 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签名。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73944428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档