Skip to main content
A reservation gives you a Swig wallet address before you send a transaction. Supply the owner’s public key, then let a funded payer activate the wallet when you need it. Reservation runs locally: it needs no RPC, signature, or on-chain account. Activation requires a Swig deployment that supports CreateReservedV1. Verify support on your target cluster before funding a reserved address.

Set up the SDK

The examples use the reservation APIs in swig-protocol-sdk. The TypeScript reservation APIs in this guide require a source build containing ReservationV1 and getCreateReservedSwigInstruction. Follow the Solana source setup.
  • TypeScript: ReservationV1 is exported by @swig-wallet/lib, @swig-wallet/classic, and @swig-wallet/kit.
  • Rust: use swig_sdk::reservation::ReservationV1. The underlying swig-interface crate owns the package format and instruction builder.

Choose the owner and address

Provide a direct Ed25519, secp256k1, or secp256r1 (P-256) public key. For secp256k1, provide the public key, not a 20-byte Ethereum address. Choose either an account index or your own 32-byte salt:
  • Omitting the option uses index 0.
  • A different index gives the same owner another wallet. Indices range from 0 to 4,294,967,295.
  • A custom salt must be exactly 32 bytes. The SDK does not generate one.
The same program ID, owner type, canonical public key, and salt produce the same addresses in TypeScript and Rust. Compressed and uncompressed SEC1 input keys normalize to the same reservation.

Reserve and activate

TypeScript

This Classic example reserves an Ed25519 wallet and prepares its activation instructions using the same reservation object.
Use walletAddress as the SOL deposit address and as the owner when deriving token accounts. Use configAddress to fetch roles and build wallet operations. Classic returns Web3.js PublicKey values, so configAddress can be passed directly to fetchSwig. Add the returned instructions to a transaction, sign with the payer, submit through your Solana client, and confirm the transaction. The builder performs no RPC or submission. The 600,000-unit compute budget accommodates P-256 validation; the activation builder itself does not add a compute-budget instruction. For Solana Kit, import ReservationV1 and getCreateReservedSwigInstruction from @swig-wallet/kit. Pass the payer as a Kit Address; the builder returns a Kit instruction. await reservation.addresses() returns Kit Address values for both swigAddress and walletAddress, ready to use with Kit helpers. Include a 600,000-unit compute limit for P-256 owners. Only the external payer signs activation. It pays the required account top-ups and transaction fee. The program fixes role 0 to the committed owner with All permissions; the payer cannot substitute an owner or permission set. Activation preserves SOL deposited before account creation.

Rust

The Rust flow uses the same package bytes and addresses. Pass the reservation returned by reserve_wallet to prepare_activation to build instructions for the payer. This example uses solana-sdk 4.x and solana-compute-budget-interface 3.x alongside the source swig-sdk crate.
Add swig-interface at the same version/revision used by swig-sdk for program_id(). Call reservation.addresses()? to get swig_address for the config and wallet_address for deposits. For a wallet API that handles RPC and activation, use SwigWallet::from_reservation. It activates a missing or prefunded uninitialized config, then opens it. For an active config, it opens the wallet with the current authority without sending an activation transaction. RPC failures and invalid existing accounts remain errors.

Continue using the wallet

  • After confirmation, fetch the wallet by its config address and use the current on-chain roles for signing and authority management.
  • Retrying activation for the same valid active reservation preserves its authorities, counters, and permissions, including owner rotations.
  • If you saved the package, keep it after a rotation: it identifies the wallet’s creation address, while current on-chain roles determine who can act.
  • A closed config retains a tombstone. Activation cannot recreate it.
  • Reserved wallets use address-bound V2 subaccounts. The TypeScript legacy V1 subaccount helpers are incompatible; use the Rust V2 subaccount APIs when you need that flow.

Optional: load a saved reservation

Use the existing reservation object while it is available. If you save a reservation for a later session, store its exact package bytes and keep the wallet address in a trusted record. The package contains public data, but changing it can change the destination. Encode the bytes as base64 or hex if your storage requires text. When loading, check the expected program ID and compare the derived wallet address with your trusted record. The loaded reservation can be passed to the same activation builder used above.

TypeScript

Save reservation.toBytes() and walletAddress.toBase58() from the Classic example. Kit addresses are already base58 strings.

Rust

Save reservation.package_bytes and reservation.addresses()?.wallet_address.

Package compatibility

Imports accept exactly one canonical V1 package: 99 bytes for Ed25519 or 100 bytes for secp256k1/P-256. They reject unsupported owner types, malformed keys, wrong program IDs, unsupported versions, and trailing bytes. Ed25519 owners must be canonical, non-small-order curve points. Constructors accept compressed (33-byte) or uncompressed (65-byte) SEC1 keys for both secp curves, and raw 64-byte keys for secp256k1. Serialized packages always contain the compressed form. The config uses ["rsv", SHA256("rsv" || package)] as PDA seeds. The wallet uses ["swig-wallet-address", config_address]. An account index is encoded little-endian in the last four bytes of an otherwise zero 32-byte salt. Use the returned config address directly: passing its commitment to legacy findSwigPda derives a different wallet.