Fragmetric SDK is the official TypeScript/JavaScript client for interacting with Fragmetric Solana programs. It supports both browser apps and Node.js environments, and includes a CLI for operational workflows and hardware wallet support.

Installation

Use your package manager to install the @fragmetric-labs/sdk package. It is available in both ESM (for browsers) and CJS (for Node.js), with all type definitions included.

npm i @fragmetric-labs/sdk@latest

@fragmetric-labs/sdk@dev is intended to test early features on devnet and may not work with programs deployed on mainnet.

Restaking Program

The RestakingProgram is the main entry point for interacting with the Fragmetric Liquid Restaking Program. It manages RPC configuration, global transaction settings, and more.

It also serves as the root of a hierarchical structure called the context graph, where each node—called a context—represents a specific part of the program and provides structured access to accounts and transaction templates. The entire SDK interface is exposed through this context graph.

import { RestakingProgram } from '@fragmetric-labs/sdk';

1. Query fragSOL data

import { RestakingProgram } from '@fragmetric-labs/sdk';

const restaking = RestakingProgram.devnet();

restaking.fragSOL
    .resolve()
    .then(console.log);

restaking.fragSOL can resolve() on-chain and off-chain aggregated data, as shown above, which includes:

  • Token metadata such as APY, price, and more.
  • A list of supported assets for deposit and withdrawal.

2. Query fragSOL user data

import { RestakingProgram } from '@fragmetric-labs/sdk';

const restaking = RestakingProgram.devnet();

restaking.fragSOL
    .user('91zBeWL8kHBaMtaVrHwWsck1UacDKvje82QQ3HE2k8mJ')
    .resolve()
    .then(console.log);

restaking.fragSOL.user(...) instantiates a new user instance using a public key. The user can then call resolve() to fetch its on-chain account data, including:

  • fragSOL and wrapped fragSOL amounts.
  • SOL balance and token balances for supported assets.
  • Ongoing withdrawal requests.
  • It will return null if the user is new.

3. Deposit

import { RestakingProgram } from '@fragmetric-labs/sdk';
import { createKeyPairSignerFromBytes } from '@solana/kit';
import fs from 'fs';

const userKeypair = Uint8Array.from(JSON.parse(fs.readFileSync('my_wallet.json').toString()));
const signerResolver = () => createKeyPairSignerFromBytes(userKeypair);

const restaking = RestakingProgram.devnet();

// user constructor accepts: null | string | Address | TransactionSigner | () => Promise<null | string | Address | TransactionSigner>
// so we can resolve user address in lazy way.
const user = restaking.fragSOL.user(signerResolver);

// deposits 1_000_000 lamports
user.deposit
    .execute({
        assetMint: null, // null means SOL
        assetAmount: 1_000_000n,
        metadata: null,
        applyPresetComputeUnitLimit: true,
    }, {
        signers: [
            // signers config accepts: TransactionSigner | () => Promise<TransactionSigner>
            signerResolver,
        ],
    })
        .then(result => console.log(result.toJSON()));

This SDK uses @solana/kit (aka. @solana/web3.js@2), so transaction-related interfaces are compatible with @solana/kit.

Transaction templates like user.deposit provide the following pipeline:

1

assemble

Assembles the full transaction message using instructions, fee payer, and lifetime strategy. This method does not perform signing, but returns a fully prepared transaction blueprint.

2

serialize

Serializes the message of the transaction blueprint into raw bytes (Uint8Array). Applies configured signers.

3

serializeToBase64

Serializes the entire transaction blueprint into a base64-encoded string. Applies signing before serialization.

For compatibility with @solana/web3.js@1, you can use it like this:

const serializedTx = await txTemplate.serializeToBase64(...);
const versionedTx = web3.VersionedTransaction.deserialize(Buffer.from(serializedTx, 'base64'));
4

simulate

Simulates the transaction. Returns the simulation result including logs, compute units, errors, etc.

5

send

Sends the serialized transaction to the network. Does not wait for confirmation or fetch any results. If any TransactionSendingSigner is configured, this method is only way to invoke the transaction.

6

sendAndConfirm

Sends the transaction and waits for confirmation. Does not parse logs or results. This method will return a signature instead of throwing an error when a skip-preflight request fails.

7

parse

Parses transaction result and events. Use this after confirming a transaction manually, if needed.

8

execute

Executes the full pipeline: assemble transaction, send and confirm, then fetch and parse the result including events.

9

executeChained

Executes the full pipeline for the initial transaction, then automatically executes any chained transactions in sequence. Execution stops if any transaction in the chain fails. This method is designed for operational workflows that require multiple successive transactions.

4. Request Withdrawal

import { RestakingProgram, createLedgerSignerResolver } from '@fragmetric-labs/sdk';

const signerResolver = createLedgerSignerResolver();

const restaking = RestakingProgram.devnet(null, { // null gives default RPC URL
    transaction: {
        // can set signers to program instance for all transactions
        signers: [
            signerResolver
        ],
        executionHooks: {
            // onSignature: console.log,
            // onError: console.error,
            // onResult: console.log,
        }
    }
});

restaking.fragSOL
    .user(signerResolver)
    .requestWithdrawal
    .execute({
        // transaction template arguments
        assetMint: null, // null means withdrawal of fragSOL to SOL
        receiptTokenAmount: 100_000n,
    }, {
        // transaction config overrides like:
        // feePayer
        // signers
        // prependedInstructions
        // appendedInstructions
        // recentBlockhash
        // durableNonce
        // addressLookupTables
        // executionHooks
    }, {
        // sending options overrides like:
        // minContextSlot
        // maxRetries
        // commitment
        skipPreflight: true,
    })
    .then(result => console.log(result.toJSON());

Withdrawal requests can have one of the following states:

  • cancellable: can be canceled by the user
  • processing: being processed by the protocol
  • claimable: ready for final withdrawal

There is a MAX limit (4) for the number of ongoing withdrawal requests per user. Trying to create more than max active withdrawal requests will result in a program error or simulation failure.

5. Cancel Request Withdrawal

import { RestakingProgram, createLedgerSignerResolver } from '@fragmetric-labs/sdk';

const signerResolver = createLedgerSignerResolver()

const restaking = RestakingProgram.devnet('https://api.devnet.solana.com', {
    rpc: {
        // configure or disable underlying RPC optimization.
        accountDeduplicationIntervalSeconds: 0,
        accountCacheTTLSeconds: 0,
        accountBatchIntervalMilliseconds: 0,
        accountBatchMaxSize: 0,
        blockhashCacheTTLMilliseconds: 0,
        blockhashBatchIntervalMilliseconds: 0,
        blockhashBatchMaxSize: 0,
    },
});

restaking.fragSOL
    .user(signerResolver)
    .cancelWithdrawalRequest
    .execute({
        // transaction template arguments
        assetMint: null,
        requestId: 148n, // get or verify request ids from resolving user data
    }, {
        signers: [signerResolver],
        // feePayer: ...
        // if `feePayer` is not explicitly provided in the method call, the program determines the feePayer in the following order:
        // (1) method-level override passed to the template call
        // (2) global program-level feePayer configuration
        // (3) template’s preset feePayer configuration
        // (4) account of parent context (e.g., the user account in this example)
    })
        .then(result => console.log(result.toJSON()));

Users can cancel cancellable withdrawal requests like above.

6. Withdraw

import { RestakingProgram, createLedgerSignerResolver } from '@fragmetric-labs/sdk';
import {createSolanaRpc, createSolanaRpcSubscriptions} from "@solana/kit";

const signerResolver = createLedgerSignerResolver();

// below is the way to create a fully customized program instance
const restaking = RestakingProgram.connect({
    type: 'solana',
    cluster: 'mainnet',
    rpc: createSolanaRpc('https://api.mainnet-beta.solana.com'),
    rpcSubscriptions: createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com'),
}, {
    rpc: {
        accountDeduplicationIntervalSeconds: 0,
        accountCacheTTLSeconds: 0,
        accountBatchIntervalMilliseconds: 0,
        accountBatchMaxSize: 0,
        blockhashCacheTTLMilliseconds: 0,
        blockhashBatchIntervalMilliseconds: 0,
        blockhashBatchMaxSize: 0
    },
    transaction: {
        signers: [
            signerResolver,
        ],
        feePayer: signerResolver,
        executionHooks: {
            onSignature: console.log,
            onError: console.error,
            onResult: console.log,
        },
        confirmationCommitment: 'confirmed'
    },
    debug: false,
});

// fragJTO has the same interface
restaking.fragJTO
    .user(signerResolver)
    .withdraw
    .execute({
        assetMint: 'jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL',
        requestId: 232n,
    })
    .then(result => console.log(result.toJSON()));

Users can withdraw claimable withdrawal requests like above.

7. Others

In addition, users can wrap, unwrap and transfer.