sol-chainsaw

Crates.iosol-chainsaw
lib.rssol-chainsaw
version0.0.2
sourcesrc
created_at2023-01-22 11:07:36.266817
updated_at2023-01-28 16:51:52.746417
descriptionDeserializing Solana accounts using their progam IDL
homepage
repositoryhttps://github.com/ironforge-cloud/chainsaw
max_upload_size
id764915
size218,944
Thorsten Lorenz (thlorenz)

documentation

README

chainsaw Build+Test

Deserializing Solana accounts using their progam IDL.

Table of Contents generated with DocToc

Installation

cargo add sol-chainsaw

Example

let opts = SerializationOpts {
    pubkey_as_base58: true,
    n64_as_string: false,
    n128_as_string: true,
};

let mut chainsaw = ChainsawDeserializer::new(&opts);

// 1. Add IDLS

// Candy Machine IDL
let cndy_program_id = "cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ";
{
    let idl_json = read_idl_json(&cndy_program_id);
    chainsaw
        .add_idl_json(cndy_program_id.to_string(), &idl_json, IdlProvider::Anchor)
        .expect("failed adding IDL JSON");
}
//  Staking Program IDL
let stake_program_id = "StakeSSzfxn391k3LvdKbZP5WVwWd6AsY1DNiXHjQfK";
{
    let idl_json = read_idl_json(&stake_program_id);
    chainsaw
        .add_idl_json(stake_program_id.to_string(), &idl_json, IdlProvider::Anchor)
        .expect("failed adding IDL JSON");
}

// 2. Read Accounts Data

// Stake Account
let stake_acc_data = read_account(
    &stake_program_id,
    "EscrowHistory",
    "5AEHnKRonYWeXWQTCqbfaEY6jHy38ifutWsriVsxsgbL",
);

// Candy Machine Account
let cndy_acc_data = read_account(
    &cndy_program_id,
    "CollectionPDA",
    "4gt6YPtgZp2MYJUP7cAH8E3UiL6mUruYaPprEiyJytQ4",
);

// 3. Deserialize Accounts

// Stake Account
{
    let mut acc_json = String::new();
    chainsaw
        .deserialize_account(
            &stake_program_id,
            &mut stake_acc_data.as_slice(),
            &mut acc_json,
        )
        .expect("failed to deserialize account");
    assert!(acc_json.contains("{\"escrow\":\"4uj6fRJzqoNRPktmYqGX1nBkjAJBsimJ4ug77S3Tzj7y\""));
}

// Candy Machine Account
{
    let mut acc_json = String::new();
    chainsaw
        .deserialize_account(
            &cndy_program_id,
            &mut cndy_acc_data.as_slice(),
            &mut acc_json,
        )
        .expect("failed to deserialize account");
    assert_eq!(acc_json, "{\"mint\":\"BrqNo3sQFTaq9JevoWYhgagJEjE3MmTgYonfaHV5Mf3E\",\"candyMachine\":\"DpBwktkJsEPTtsRpD8kCFGwEUjwTkXARSGSTQ7MJr4kE\"}");
}

See ./examples/multiple_idls_and_accounts.rs for the full example.

Run it via: cargo run --example multiple_idls_and_accounts

Network Feature

To make retrieving IDLs from chain easier an idl client implementation is included which is only enabled when the network feature is enabled.

let idl_client = IdlClient::for_anchor_on_mainnet();
let program_idl = idl_client.fetch(program_id)?;

_more detailed example inside tests/task_update_idls.rs.

Development

Test Tasks

Various tasks related to tests were included via the ./Makefile. They are part of the tests folder but gated behind features. Thus to activate them specific features need to be enabled.

In order to use a custom RPC cluster when running those tasks please provide it via the RPC_URL env var, i.e.:

export RPC_URL="https://solana-mainnet.g.alchemy.com/v2/<mykey>"

Updating IDLs

Inside ./tests/data/programs_with_idl.json are program ids which have IDLs uploaded on chain.

Those IDLs are stored inside ./fixtures/idls to be used by integration tests.

  • idl_update: update IDLs to what's currently on chain

Fetching Test Data from Chain

  • fetch_account: fetches a specific account from chain (requires ADDRESS env var) and stores it in a tmp file
  • fetch_accounts_for_program: Updates accounts for specific program from chain (requires PROGRAM_ID env var)
  • fetch_accounts_for_all_programs: Updates accounts for all known program from chain (requires COUNT env var to indicate how many accounts per account type to fetch)

Triaging Account Deserialization

In order to isolate deserialization issues for specific accounts use on of the following tasks and provide the required env vars.

  • deserialize_account_type_address_for_program: deserializes an account of program PROGRAM_ID of account type ACCOUNT_TYPE at address ADDRESS
  • deserialize_account_type_for_program: deserializes all accounts of program PROGRAM_ID and account type ACCOUNT_TYPE
  • deserialize_accounts_for_program: deserializes all accounts of program PROGRAM_ID

Examples:

export PROGRAM_ID=1USDCmv8QmvZ9JaL7bmevGsNHn7ez8TNahJzCN551sb 
export ACCOUNT_TYPE=DepositReceipt
make deserialize_account_type_address_for_program ADDRESS=AyMxDEJPvJv6XQaFK9ZZ9XxDxHuVB8d7NUxP8TfLX45K
export PROGRAM_ID=1USDCmv8QmvZ9JaL7bmevGsNHn7ez8TNahJzCN551sb 
make deserialize_account_type_for_program ACCOUNT_TYPE=Realm
export PROGRAM_ID=1USDCmv8QmvZ9JaL7bmevGsNHn7ez8TNahJzCN551sb 
make deserialize_accounts_for_program

LICENSE

MIT

Commit count: 0

cargo fmt