Anchor serialization
Clients will send transactions which include instruction data. When these transactions are sent over the wire, their instructions are first compressed into bytes which is then compressed into a compact Base58 representation.
Base58 is a type of binary to text encoding.
While everything on Solana is stored in bytes, transforming them into Base58 for data transfer over-the-wire is done as an optimization.
On the other side, as a receiver, you also must be able to translate that Base58 code into something meaningful, like a Struct, when receiving transactions. Once it has been deserialized, validated, and executed it will again be serialized into byte code to be written to the account's buffer.
Serialization
The client and the program must serialize in an identical way. In order to facilitate this, Anchor uses Borsh serialization as a standard, and is our default serializer when we're using Anchor with Rust.
What the program actually receives is the individually parsed instructions, in this format:
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult
The transaction structure (signatures, blockhash, full message, etc.) is never exposed to your on-chain logic, instead it receives the final parsed instructions.
Given that the Pubkey
and AccountInfo
have already been parsed into formats that the Rust program can understand, the only thing to parse is the u8
instruction data.
This is where the program would use Borsh serialization to transform that transaction data into the specific structs it would need to handle.
Deserializing with javascript
On the client side, we generate a client that will convert the native Rust types into their corresponding Typescript types.
Rust | Typescript | Example |
---|---|---|
bool | boolean | true |
u8/u16/u32/i8/i16/i32 | number | 99 |
u64/u128/i64/i128 | anchor.BN | new anchor.BN(99) |
f32/f64 | number | 1.0 |
String | string | "hello" |
[T; N] | Array<T> | [1, 2, 3] |
Vec<T> | Array<T> | [1, 2, 3] |
Option<T> | T | null | undefined | null or 42 (some) |
- Rust integers (
u8
throughi32
) map to JavaScript number - Larger integers (
u64
and above) use Anchor'sBN
type for precision - Rust's
Option<T>
maps to TypeScript's union type withnull
/undefined
- Structs and enums become JavaScript objects
More complicated objects like structs become types themselves:
// Rust
struct MyStruct {
val: u16
}
// Typescript
type MyStruct = {
val: number;
}