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)