Solana 使用 anchor调用合约

2,006 阅读2分钟

Solana 调用合约需要手动编译二进制数据,我们可以用borsh来简化这个过程,但是borsh我们也需要去写schma,然后手动deserializeUnchecked和serialize,很麻烦。我们希望有一个类似abi的东西,导入进来,然后把参数传进去就好了。

anchor工程就很好的解决这个问题。

复习

我们先复习下没使用anchor的情况,调用需要做什么。下面展示createMasterEdition的instructions的组合核心代码。

// 设置data
  const value = new CreateMasterEditionArgs({ maxSupply: maxSupply || null });
  const data = Buffer.from(serialize(METADATA_SCHEMA, value));
// keys
  const keys = [
    {
      pubkey: toPublicKey(editionAccount),
      isSigner: false,
      isWritable: true,
    },
    {
      pubkey: toPublicKey(mintKey),
      isSigner: false,
      isWritable: true,
    },
    {
      pubkey: toPublicKey(updateAuthorityKey),
      isSigner: true,
      isWritable: false,
    },
    {
      pubkey: toPublicKey(mintAuthorityKey),
      isSigner: true,
      isWritable: false,
    },
    {
      pubkey: toPublicKey(payer),
      isSigner: true,
      isWritable: false,
    },
    {
      pubkey: toPublicKey(metadataAccount),
      isSigner: false,
      isWritable: false,
    },

    {
      pubkey: programIds().token,
      isSigner: false,
      isWritable: false,
    },
    {
      pubkey: SystemProgram.programId,
      isSigner: false,
      isWritable: false,
    },
    {
      pubkey: SYSVAR_RENT_PUBKEY,
      isSigner: false,
      isWritable: false,
    },
  ];
// 组合指令
instructions.push(
    new TransactionInstruction({
      keys,
      programId: toPublicKey(metadataProgramId),
      data,
    }),
  );
  
// 上面的data需要进行一个结构函数和一个scheme分别对应如下

class CreateMasterEditionArgs {
  instruction: number = 10;
  maxSupply: BN | null;
  constructor(args: { maxSupply: BN | null }) {
    this.maxSupply = args.maxSupply;
  }
}

export const METADATA_SCHEMA = new Map<any, any>([
  // other code
  [
    CreateMasterEditionArgs,
    {
      kind: 'struct',
      fields: [
        ['instruction', 'u8'],
        ['maxSupply', { kind: 'option', type: 'u64' }],
      ],
    },
  ]
  // other code
])

然后就可以组合成一个trisection了,加入需要签名的账户对即可。但是代码很长很麻烦。

开饭

先安装依赖 @project-serum/anchor

import * as anchor from "@project-serum/anchor"

获取program环境

const provider = useMemo(() => {
    return new anchor.AnchorProvider(connection, wallet, {
        commitment: "processed",
    })
}, [connection, wallet]) 
const program = useMemo(() => {
    return  new anchor.Program(idl, programId, provider)
}, [provider]) 

执行合约

methods.<你需要调用的方法名>(<你的参数>) .accounts(accounts)

  • 参数 参数对应的是合约的参数,ts类型可能会报错,忽略即可。
  • accounts 你的keys,和上面的keys一样,跟传统没区别,但是不需要设置isSigner,只需要pubkey

例子

const tx = await program.methods.
  userClaim(Data).
  accounts({
      systemProgram,
      rent,
      // ... more Publick,
  }).
  rpc();

fetch方法

如果需要链上信息,我们去请求并且解析数据,会很累,用anchor就会很方便,如下使用

const res = await program.fetch(Pubkey)

更多可参考下面文章

上一次写的原生转账和代币转账文章

anchor官方例子

anchor ts文档

anchor initialize