anchor测试中常用typescript代码
1- 获取provider,初始化链接:
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const connection = provider.connection;
2- 获取程序
const program = anchor.workspace.Marketplace as Program<Marketplace>; //Marketplace用idl文件中的合约名称替代
const programId = program.programId;
3- 获取PDA账号
const [newGameDataAccount] = anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("level1", "utf8"), mintAccount], // seeds根据合约中的要求配置,必须是Buffer数据
program.programId
);
4- 调用合约方法
4.1- 使用rpc(),用于一个指令的处理
const txHash = await program.methods
.initialize() // 方法名称,如果有参数的话在()加入参数值
.accounts({ // 对应的Accounts指令结构
newGameDataAccount: newGameDataAccount,
signer: provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
})
.signer([签名keypairs]) // 如果是自己签名,不需要
.rpc(); // 运行该指令
// 等待交易确认
await provider.connection.confirmTransaction(txHash, "confirmed");
4.2- 使用instruction()
,可以在前端处理多个指令
const tx = new anchor.web3.Transaction();
const ix = await program.methods
.initialize() // 方法名称,如果有参数的话在()加入参数值
.accounts({ // 对应的Accounts指令结构
newGameDataAccount: newGameDataAccount,
signer: provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
})
.instruction();
tx.add(ix);
await provider.sendAndConfirm(tx);
5- 根据keypair获取默认账号
const secretKey = Uint8Array.from(...) // 用solana-keygen new生成,keypair保存在本地~/.config/solana/id.json中,是一个数组。这个地址应该和solana address一致。
const myAccount = anchor.web3.Keypair.fromSecretKey(secretKey);
如果只需要获取当前钱包账号的Pubkey,使用:
const pubkey = provider.wallet.publicKey;
也可以不需要secretKey获取:
const wallet = provider.wallet as anchor.Wallet;
const myAccount = wallet.payer;
如果私钥保存在env中,可以使用
import { getKeypairFromEnvironment } from "@solana-developers/helpers";
const keypair = getKeypairFromEnvironment("SECRET_KEY"); // 不需要process.env
6- 生成新账号(keypair)
import {Keypair} from "@solana/web3.js";
const tokenAccount = Keypair.generate();
7- 读取账号中的数据
await program.account.<Account Struct name>.fetch(<account address>);
注意Account struct name对应#[account]中的定义,但是转成驼峰格式,如ConfigInfo转成configInfo
8- 获取SystemProgram
const systemProgram = anchor.web3.SystemProgram.programId;
9- 获取交易事件
注意:solana本身不具备event功能,使用anchor实现
9.1- 在合约端定义Event结构,如:
use anchor_lang::prelude::*;
#[event]
pub struct ListEvent {
pub lister: Pubkey,
pub order_id: String,
pub tick: String,
pub amount: u64,
pub price: u64,
pub expired_at: i64,
}
9.2- 在合约的方法中使用emit!宏发送Event:
emit!(ListEvent{
lister: ctx.accounts.lister.key(),
order_id: order.order_id.clone(),
tick: order.tick.clone(),
amount: amount,
price: price,
expired_at: expired_at,
});
9.3- 在前端使用idl文件解析Event:
await sleep(1000); // waiting for tx confirmed,only for testing,otherwise txData will be null
const txData = await anchor.getProvider().connection.getTransaction(tx, {
commitment: "confirmed",
maxSupportedTransactionVersion: 1,
});
const eventParser = new anchor.EventParser(program.programId, new anchor.BorshCoder(program.idl));
const events = eventParser.parseLogs(txData.meta?.logMessages);
for(let event of events) {
console.log(event.data);
}
也可以直接使用getEvents方法:
const getEvents = async (tx: string) => {
await sleep(1000); // waiting for tx confirmed
const txData = await anchor.getProvider().connection.getTransaction(tx, {
commitment: "confirmed",
maxSupportedTransactionVersion: 1,
});
const eventParser = new anchor.EventParser(program.programId, new anchor.BorshCoder(program.idl));
const events = eventParser.parseLogs(txData.meta?.logMessages);
return events;
}
10- 获取账户余额
const balance = await anchor.getProvider().connection.getBalance(accountPublicKey);
console.log('Balance:', balance);
11- 给账户空投
const airdropSignature = await anchor.getProvider().connection.requestAirdrop(account.publicKey, amount);
await provider.connection.confirmTransaction(airdropSignature);
12- 定位ATA地址
方法1: 用anchor库
const [mintAccount] = web3.PublicKey.findProgramAddressSync([Buffer.from(MINT_SEED)], program.programId);
const destination = anchor.utils.token.associatedAddress({
mint: mintAccount,
owner: myAccount.publicKey,
});
// 获取ATA中的代币数量
const balance = await provider.connection.getTokenAccountBalance(destination);
方法2: 用@solana/spl-token库:
const ataAddress = await getAssociatedTokenAddress(programPubkey, ownerPubkey);
方法3: 不确定是否已经创建ata账户时(可能要发送交易)
const tokenAccount = await token.getOrCreateAssociatedTokenAccount(
connection,
payer,
tokenMintAccount,
owner.publicKey,
);
13- 将Uint8Array私钥转为bs58格式的私钥
import {bs58} from "@coral-xyz/anchor/dist/cjs/utils/bytes";
const privateKey58 = [8,43,141,...,21,217,144];
const strPrivateKey = bs58.encode(privateKey58);
const owner = "AUVyevF2Wv...tWj6iS6s";
// decode
bs58.decode(strPrivateKey);