Rust Types in Javascript - SoproxABI

To convert Rust types and Javascript types to each other, SoproxABI was born to help you hack it.

Installation

SoproxABI is a separate npm package from Soprox framework.

Repo: https://github.com/DescartesNetwork/soprox-abiโ€‹

SoproxABI is usually installed along with all SoproX templates. However, if you would like to install it manually, you can the following to install the latest version.

npm install soprox-abi

Import SoproxABI

const soproxABI = require('soprox-abi');

Quick Tutorial

// Please refer @solana/web3 for fetch account data
// https://solana-labs.github.io/solana-web3.js/class/src/connection.js~Connection.html#instance-method-getAccountInfo
const connection = ...
const { data } = await connection.getAccountInfo(mintPublicKey)
โ€‹
const MINT_SCHEMA = [
{ key: "mint_authority_option", type: "u32" },
{ key: "mint_authority", type: "pub" },
{ key: "supply", type: "u64" },
{ key: "decimals", type: "u8" },
{ key: "is_initialized", type: "bool" },
{ key: "freeze_authority_option", type: "u32" },
{ key: "freeze_authority", type: "pub" },
];
โ€‹
const mintLayout = new soproxABI.struct(schema.MINT_SCHEMA);
const readableData = mintLayout.fromBuffer(data);

More examples are available here.

APIs

Primary types

Rust type

Javascript type

Keyword

Space (bytes)

bool

bool

bool

1

char

string

char

4

i8

number

i8

1

i16

number

i16

2

i32

number

i32

4

i64

bigInt

i64

8

i128

bigInt

i128

16

u8

number

u8

1

u16

number

u16

2

u32

number

u32

4

u64

bigInt

u64

8

u128

bigInt

u128

16

array

array

[<type>;<length>]

depends on length

tuple

object

(<type>;<type>;...)

depends on length

Pubkey

Base58<Buffer>

pub

32

Struct

Struct is a complex type that is a combination of primary types. With this type, we can easily represent inputs of an on-chain function, data forms of on-chain accounts.

The create function won't affect on the struct type.

To define the data schema of a struct, we use an array where each element is an object including key, type, and/or schema for is nested struct.

Simple struct

const schema = [
{ "key": "pet", "type": "(char;u32;bool)" },
{ "key": "owner", "types": "[char;12]" },
{ "key": "male", "types": "bool" },
]
const petStruct = new soproxABI.struct(schema);

Nested struct

const schema = [
{ "key": "productCode", "type": "pub" },
{
"key": "description", "schema": [
{ "key": "colorized", "type": "bool" },
{ "key": "amount", "type": "u64" },
]
}
]
const productStruct = new soproxABI.struct(schema);

Static functions

You can call these functions directly from soproxABI. For example,

const counter = soproxABI.create('[u8;5]', [1,2,3,4,5]);

Function

Description

Interface

create

Create an instance of type

create(type: string, value: (optional) initial value)

span

Compute space in bytes of a variable

span(variable: a SoproxABI variable)

pack

Concatenate all buffers into a single buffer

pack(buffer_1, <buffer_2>, ...)

Class functions

These functions are only called from a class instance. For example,

const toggle = new soproxABI.bool(false);
toggle.toBuffer() // toBuffer is an instance function

Function

Description

Interface

toBuffer

Return a buffer represents the value of a type

toBuffer()

fromBuffer

Assign buffer data to a type

fromBuffer(buf: Buffer)

Examples

Get data length in bytes - For rent account

To rent an account on Solana, you need to compute the data space for the rent-exemption.

const schema = [
{ key: "numGreets", type: "u32" },
{ key: "toggleState", type: "bool" }
]
const layout = new soproxABI.struct(schema);
const space = layout.space; // 5 bytes - the needed space for the account

Parse account data

Parse a dummy account in a hello-world program

// Please refer @solana/web3 for fetch account data
// https://solana-labs.github.io/solana-web3.js/class/src/connection.js~Connection.html#instance-method-getAccountInfo
const { data } = await connection.getAccountInfo(dummyAccount.publicKey);
โ€‹
const schema = [
{ key: "numGreets", type: "u32" },
{ key: "toggleState", type: "bool" }
]
const layout = new soproxABI.struct(schema);
layout.fromBuffer(data);
โ€‹
// Finally
console.log(layout.value);

Calling function

Call sayHello function to a hello-world program

Approach #1

const schema = [
{ key: "numGreets", type: "u32" },
{ key: "toggleState", type: "bool" }
]
const layout = new soproxABI.struct(schema, {
numGreets: 1,
toggleState: true
});
const code = new soproxABI.u8(0); // 0 is corresponding to sayHello
const data = soproxABI.pack(code, layout);
โ€‹
// Finally
console.log(data);

Approach #2

const schema = [
{ key: "code", type: "u8" },
{ key: "numGreets", type: "u32" },
{ key: "toggleState", type: "bool" }
]
const layout = new soproxABI.struct(schema, {
code: 0, // 0 is corresponding to sayHello
numGreets: 1,
toggleState: true
});
const data = soproxABI.pack(code, layout);
โ€‹
// Finally
console.log(data.toBuffer());

Two approaches will end up with the same result.