作弊码

作弊码是绕过正常交易流程的状态变更操作。它们无需消耗 blockhash 或支付费用即可即时执行,非常适合用于测试环境的初始化设置。

在 Rust 中,作弊码位于 Surfnet::cheatcodes() 下。在 JS 中,它们是 Surfnet 实例上的直接方法。

充值 SOL

fundSol / fund_sol 用于设置任意账户的 lamport 余额,若账户不存在则自动创建。

use surfpool_sdk::{Pubkey, Surfnet};
let surfnet = Surfnet::start().await?;
let cheats = surfnet.cheatcodes();
let wallet = Pubkey::new_unique();
cheats.fund_sol(&wallet, 1_000_000_000)?;
// Fund several accounts in one call.
let bob = Pubkey::new_unique();
let carol = Pubkey::new_unique();
cheats.fund_sol_many(&[(&bob, 2_000_000_000), (&carol, 3_000_000_000)])?;

充值代币

fundToken / fund_token 通过计算关联的 token account 向钱包铸造代币,如有需要则自动创建该账户并设置金额。

Token-2022 mints

默认情况下,fundToken 使用经典的 SPL Token program。对于 Token-2022 的铸造,请将 Token-2022 程序 ID (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb) 作为最后一个参数传入。

use surfpool_sdk::{Pubkey, Surfnet};
let surfnet = Surfnet::start().await?;
let cheats = surfnet.cheatcodes();
let wallet = Pubkey::new_unique();
let mint: Pubkey = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
.parse()
.unwrap();
// Classic SPL Token mint.
cheats.fund_token(&wallet, &mint, 5_000_000, None)?;
// Token-2022 mint — pass the program id explicitly.
let token_2022: Pubkey = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
.parse()
.unwrap();
cheats.fund_token(&wallet, &mint, 5_000_000, Some(&token_2022))?;
// Fund many wallets with the same mint.
let mob = vec![Pubkey::new_unique(), Pubkey::new_unique()];
cheats.fund_token_many(&mob.iter().collect::<Vec<_>>(), &mint, 1_000_000, None)?;

若要在不充值的情况下推导 ATA,请使用 getAta / get_ata

let ata = cheats.get_ata(&wallet, &mint, None);

设置任意账户状态

setAccount 方法可在一次调用中为任意账户写入 lamport、所有者及原始数据字节。Rust SDK 还额外提供了 SetAccount 构建器,用于处理 rent_epochexecutable 等更高级的字段。

use surfpool_sdk::cheatcodes::builders::SetAccount;
use surfpool_sdk::{Pubkey, Surfnet};
let surfnet = Surfnet::start().await?;
let cheats = surfnet.cheatcodes();
let address = Pubkey::new_unique();
let owner = Pubkey::new_unique();
// Direct method.
cheats.set_account(&address, 500_000, &[1, 2, 3], &owner)?;
// Builder when you need finer control.
cheats.execute(
SetAccount::new(address)
.lamports(500_000)
.owner(owner)
.data(vec![1, 2, 3])
.rent_epoch(0)
.executable(false),
)?;

修改 Token Account 字段

setTokenAccount 用于更新现有 token account 的高级字段——委托方、状态、关闭权限及委托金额。当单独使用 fundToken 不足以满足需求时,请使用此方法。

use surfpool_sdk::cheatcodes::builders::SetTokenAccount;
use surfpool_sdk::{Pubkey, Surfnet};
let cheats = Surfnet::start().await?.cheatcodes();
let owner = Pubkey::new_unique();
let mint: Pubkey = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".parse()?;
let delegate = Pubkey::new_unique();
cheats.execute(
SetTokenAccount::new(owner, mint)
.amount(2_000_000)
.delegate(delegate)
.delegated_amount(500_000)
.state("initialized"),
)?;
// Later: clear the delegation.
cheats.execute(SetTokenAccount::new(owner, mint).clear_delegate())?;

将账户重置为上游状态

resetAccount 会丢弃所有本地修改,并从上游 RPC 重新获取账户数据。传入 includeOwnedAccounts: true 可同时重置目标所拥有的所有账户——在重置程序及其所有 PDA 时非常实用。

需要 `remoteRpcUrl` 才能重新获取

在离线 Surfnet 环境中,resetAccount 会清除本地副本,但由于没有上游数据源,无法重新获取数据。请在启动时配置 remoteRpcUrl,以使重置操作能够恢复上游状态。

use surfpool_sdk::cheatcodes::builders::ResetAccount;
use surfpool_sdk::{Pubkey, Surfnet};
let cheats = Surfnet::start().await?.cheatcodes();
let token_program: Pubkey = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".parse()?;
cheats.execute(
ResetAccount::new(token_program).include_owned_accounts(true),
)?;

实时账户流

streamAccount 将账户注册为从上游 RPC 进行后台轮询。本地 Surfnet 副本将与主网保持同步,无需测试代码显式轮询。结合 includeOwnedAccounts 可对某个程序所拥有的所有 PDA 进行数据流传输。

需要 `remoteRpcUrl`

streamAccount 仅在以 remoteRpcUrl(或 Rust 中的 remote_rpc_url)启动的 Surfnet 上有效。若没有上游 RPC,则没有可供流式传输的数据源,调用将返回错误。

use surfpool_sdk::cheatcodes::builders::StreamAccount;
use surfpool_sdk::{Pubkey, Surfnet};
let cheats = Surfnet::builder()
.remote_rpc_url("https://api.mainnet-beta.solana.com")
.start()
.await?
.cheatcodes();
let oracle: Pubkey = "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG".parse()?;
cheats.execute(StreamAccount::new(oracle).include_owned_accounts(false))?;

Cheatcode 构建器(Rust)

Rust SDK 在 surfpool_sdk::cheatcodes::builders 下提供了类型化构建器,适用于便捷方法无法满足需求的场景。每个构建器均实现了 CheatcodeBuilder trait,并通过 cheats.execute(builder) 执行。

构建器构造函数常用设置方法
SetAccountnew(address: Pubkey)lamports, data, owner, rent_epoch, executable
SetTokenAccountnew(owner: Pubkey, mint: Pubkey)amount, delegate, clear_delegate, state, delegated_amount, close_authority, clear_close_authority, token_program
ResetAccountnew(address: Pubkey)include_owned_accounts(bool)
StreamAccountnew(address: Pubkey)include_owned_accounts(bool)
DeployProgramnew(program_id: Pubkey), from_keypair_path(path)so_path, so_bytes, idl_path

如需完整的 JS 接口,请参阅 JS 参考文档。如需完整的 Rust 接口,请参阅 Rust 参考文档

Is this page helpful?

Table of Contents

Edit Page
©️ 2026 Solana 基金会版权所有