solana_kit_surfpool 0.2.1
solana_kit_surfpool: ^0.2.1 copied to clipboard
Surfpool SDK helpers for Solana Kit Dart tests.
solana_kit_surfpool #
Surfpool SDK helpers for Solana Kit Dart tests.
This package ports Surfpool's TypeScript/Rust SDK surface to idiomatic Dart by using Surfpool's JSON-RPC cheatcodes. Surfnet.start() is CLI-backed: it starts surfpool start on random ports and then talks to that process over HTTP. This keeps the package pure Dart and avoids native napi or flutter_rust_bridge bindings.
Installation #
Installation #
Install the package directly:
dependencies:
"solana_kit_surfpool": ^0.2.1
If your app uses several Solana Kit packages together, you can also depend on the umbrella package instead:
dart pub add solana_kit
Inside this monorepo, Dart workspace resolution uses the local package automatically.
solana_kit_surfpool is not re-exported by the umbrella solana_kit package; add and import this package directly when you need Surfpool helpers.
The CLI-backed runtime requires the surfpool executable to be available on PATH. In this repository, use the configured devenv shell.
Usage #
import 'package:solana_kit_surfpool/solana_kit_surfpool.dart';
Future<void> main() async {
final surfnet = await Surfnet.start();
final alice = Surfnet.newKeypair();
try {
await surfnet.fundSol(alice.address, 1_000_000_000);
final epoch = await surfnet.timeTravelToSlot(1_000);
print('RPC: ${surfnet.rpcUrl}');
print('Payer: ${surfnet.payer.value}');
print('Slot: ${epoch.absoluteSlot}');
} finally {
await surfnet.stop();
}
}
Connect to an existing Surfpool process when you manage surfpool start yourself:
final surfnet = Surfnet.connect(
rpcUrl: Uri.parse('http://127.0.0.1:8899'),
wsUrl: Uri.parse('ws://127.0.0.1:8900'),
);
Solana Kit client (kit plugin) #
createSurfpoolClient() mirrors the @solana/surfpool/kit plugin for TypeScript: it starts a fresh Surfnet and returns a SurfpoolClient with a Solana Kit RPC client, an RPC subscriptions client, the Surfnet's pre-funded payer signer, and a typed cheatcode RPC — so tests can build, sign, send, and confirm transactions without managing a validator or RPC plumbing by hand.
import 'package:solana_kit/solana_kit.dart';
import 'package:solana_kit_surfpool/solana_kit_surfpool.dart';
Future<void> main() async {
final client = await createSurfpoolClient();
try {
// Pre-funded payer installed by the plugin.
final payer = client.payer;
// Standard Solana RPC and subscriptions clients.
final slot = await client.rpc.getSlot().send();
print('Slot: $slot');
// Surfpool cheatcodes with the `surfnet_` prefix stripped.
await client.cheatcodes.pauseClock();
// Helpers.
await client.airdrop(payer.address, BigInt.from(1_000_000_000));
final rent = await client.getMinimumBalance(BigInt.zero);
print('Rent-exempt minimum: $rent');
} finally {
await client.stop();
}
}
Stopping a freshly created client clears Surfnet's in-memory payer bytes and disposes the client-owned payer signer. A signer supplied to connectSurfpoolClient remains caller-owned and is not disposed.
Attach to an already-running Surfpool with connectSurfpoolClient; the [payer] must be a funded signer you provide:
final client = connectSurfpoolClient(
rpcUrl: Uri.parse('http://127.0.0.1:8899'),
payer: myFundedSigner,
);
Cheatcodes #
import 'package:solana_kit_addresses/solana_kit_addresses.dart';
final owner = Surfnet.newKeypair().address;
final mint = address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
await surfnet.fundToken(owner, mint, 5_000_000);
final ata = surfnet.getAta(owner, mint);
print('ATA: ${ata.value}');
await surfnet.setTokenAccount(
owner,
mint,
const SetTokenAccountUpdate(
state: 'initialized',
delegatedAmount: 500_000,
),
);
For advanced account fields, use the builder API:
import 'dart:typed_data';
await surfnet.execute(
SetAccount(Surfnet.newKeypair().address)
.withLamports(500_000)
.withData(Uint8List.fromList([1, 2, 3]))
.withOwner(surfnet.payer)
.withRentEpoch(0)
.withExecutable(executable: false),
);
Deploy programs #
final programId = await surfnet.deployProgram('my_program');
print('deployed at ${programId.value}');
deployProgram discovers conventional Anchor/Agave artifacts under target/deploy and target/idl. Use deploy with DeployOptions when bytes or paths live elsewhere.
Runtime events #
The upstream Rust and JS SDKs expose an in-process event channel. This Dart package does not embed the Rust runtime, so drainEvents() currently returns best-effort stdoutLog and stderrLog events captured from the CLI-backed process. Use RPC assertions for deterministic tests.
Key APIs #
| API | Purpose |
|---|---|
createSurfpoolClient() / connectSurfpoolClient() |
Kit-plugin style client: RPC + subscriptions + payer + cheatcodes. |
SurfpoolClient.rpc / rpcSubscriptions / payer / cheatcodes |
Wired Solana Kit clients and the pre-funded payer. |
SurfpoolClient.airdrop / getMinimumBalance |
Funding and rent-exemption helpers. |
Surfnet.start() / Surfnet.startWithConfig() |
Start a CLI-backed local Surfnet. |
Surfnet.connect() |
Attach to an existing Surfpool RPC endpoint. |
fundSol, fundToken, setAccount, setTokenAccount |
Mutate local account state through Surfpool cheatcodes. |
resetAccount, streamAccount |
Re-fetch or stream accounts from an upstream RPC. |
timeTravelToSlot, timeTravelToEpoch, timeTravelToTimestamp |
Move the local Surfnet clock forward. |
deployProgram, deploy |
Write program bytes and optionally register an Anchor IDL. |