npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@solana/spl-account-compression

v0.4.1

Published

SPL Account Compression Program JS API

Downloads

90,648

Readme

@solana/spl-account-compression

A TypeScript library for interacting with SPL Account Compression and SPL NoOp. For more information, see the full Solana account compression SDK documentation.

Install

npm install --save @solana/spl-account-compression @solana/web3.js

OR

yarn add @solana/spl-account-compression @solana/web3.js

Information

This on-chain program provides an interface for composing smart contracts to create and use SPL ConcurrentMerkleTrees. The primary application of using SPL ConcurrentMerkleTrees is to synchronize off-chain databases with on-chain updates.

SPL ConcurrentMerkleTrees are Merkle Trees that have their roots on-chain with support for fast-forwarding proofs. Fast forwarding allows multiple updates to the tree in a single block and reduces the latency burden on indexers.

In order to execute transactions that modify an SPL ConcurrentMerkleTree, an indexer will need to parse through transactions that touch the tree in order to provide up-to-date merkle proofs. For more information regarding merkle proofs, see this great explainer.

This program is targeted towards supporting Metaplex Compressed NFTs and may be subject to change.

A rough draft of the whitepaper for SPL ConcurrentMerkleTrees can be found here.

High Level Overview

Instructions

Code to interact with the on-chain instructions is auto-generated by @metaplex-foundation/solita. Exported functions to create instructions have pattern create<instructionName>Instruction.

  • For example, account compression's append_leaf instruction has a Solita-generated factory function called createAppendLeafInstruction.

Solita provides very low-level functions to create instructions. Thus, helper functions are provided for each instruction, denoted with the suffix ix.

  • For example: createReplaceLeafInstruction has a helper function createReplaceLeafIx

Modules

A merkle tree reference implementation is provided to index the on-chain trees. The MerkleTree class and its helpers are provided under src/merkle-tree.

The MerkleTree class is meant to follow a similar interface as MerkleTree from merkletreejs.

| Feature | Our Tree | merkletreejs | Notes | | ---------- | -------- | -------------- | ------------------------------------------------------------ | | updateLeaf | ✅ | ❌ | This is the unique feature of ConcurrentMerkleTree's | | multiProof | ❌ | ✅ | Possible to support in future version of Account Compression | | addLeaf | ✅ | ✅ | Our version does this via updateLeaf() |

If you'd like to see more features added, please create an issue with the title Account Compression and your feature request.

Examples

  1. Create a tree
// Assume: known `payer` Keypair

// Generate a keypair for the ConcurrentMerkleTree
const cmtKeypair = Keypair.generate();

// Create a system instruction to allocate enough 
// space for the tree
const allocAccountIx = await createAllocTreeIx(
    connection,
    cmtKeypair.publicKey,
    payer.publicKey,
    { maxDepth, maxBufferSize },
    canopyDepth,
);

// Create an SPL compression instruction to initialize
// the newly created ConcurrentMerkleTree
const initTreeIx = createInitEmptyMerkleTreeIx(
    cmtKeypair.publicKey, 
    payer.publicKey, 
    { maxDepth, maxBufferSize }
);

const tx = new Transaction().add(allocAccountIx).add(initTreeIx);

await sendAndConfirmTransaction(connection, tx, [cmtKeypair, payer]);
  1. Add a leaf to the tree
// Create a new leaf
const newLeaf: Buffer = crypto.randomBytes(32);

// Add the new leaf to the existing tree
const appendIx = createAppendIx(cmtKeypair.publicKey, payer.publicKey, newLeaf);

const tx = new Transaction().add(appendIx);

await sendAndConfirmTransaction(connection, tx, [payer]);
  1. Replace a leaf in the tree, using the provided MerkleTree as an indexer

This example assumes that offChainTree has been indexing all previous modifying transactions involving this tree. It is okay for the indexer to be behind by a maximum of maxBufferSize transactions.

// Assume: `offChainTree` is a MerkleTree instance
// that has been indexing the `cmtKeypair.publicKey` transactions

// Get a new leaf
const newLeaf: Buffer = crypto.randomBytes(32);

// Query off-chain records for information about the leaf
// you wish to replace by its index in the tree
const leafIndex = 314;

// Replace the leaf at `leafIndex` with `newLeaf`
const replaceIx = createReplaceIx(
    cmtKeypair.publicKey,          
    payer.publicKey,
    newLeaf,
    offChainTree.getProof(leafIndex) 
);

const tx = new Transaction().add(replaceIx);

await sendAndConfirmTransaction(connection, tx, [payer]);
  1. Replace a leaf in the tree, using a 3rd party indexer

This example assumes that some 3rd party service is indexing the tree at cmtKeypair.publicKey for you, and providing MerkleProofs via some REST endpoint. The getProofFromAnIndexer function is a placeholder to exemplify this relationship.

// Get a new leaf
const newLeaf: Buffer = crypto.randomBytes(32);

// Query off-chain indexer for a MerkleProof
// possibly by executing GET request against a REST api
const proof = await getProofFromAnIndexer(myOldLeaf);

// Replace `myOldLeaf` with `newLeaf` at the same index in the tree
const replaceIx = createReplaceIx(
    cmtKeypair.publicKey,          
    payer.publicKey,
    newLeaf,
    proof
);

const tx = new Transaction().add(replaceIx);

await sendAndConfirmTransaction(connection, tx, [payer]);

Reference examples

Here are some examples using account compression in the wild:

  • Solana Program Library tests

  • Metaplex Program Library Compressed NFT tests

Build from Source

  1. Install dependencies with pnpm i.

  2. Generate the Solita SDK with pnpm solita.

  3. Then build the SDK with pnpm build.

  4. Run tests with pnpm test. (Expect jest to detect an open handle that prevents it from exiting naturally)