Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Account Compression: JS SDK release 0.1.1 #3680

Merged
merged 5 commits into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions account-compression/sdk/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,42 @@
# Account Compression SDK
# `@solana/spl-account-compression`

Currently contains a typescript SDK to interact with on-chain SPL ConcurrentMerkleTrees.
A TypeScript library for interacting with SPL Account Compression and SPL NoOp.

Used to test Account Compression program.
## Install

# Setting up the Solita-based Typescript SDK
```shell
npm install --save @solana/spl-account-compression @solana/web3.js
```

__OR__

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


## Examples

* Solana Program Library [tests](https://github.com/solana-labs/solana-program-library/tree/master/account-compression/sdk/tests)

* Metaplex Program Library Compressed NFT [tests](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/bubblegum/js/tests)

## 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 make edits to off-chain data with on-chain verification.

This program is targeted towards supporting [Metaplex Compressed NFTs](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/bubblegum) and may be subject to change.

Note: Using this program requires an indexer to parse transaction information and write relevant information to an off-chain database.

A **rough draft** of the whitepaper for SPL ConcurrentMerkleTree's can be found [here](https://drive.google.com/file/d/1BOpa5OFmara50fTvL0VIVYjtg-qzHCVc/view).

## Build from Source

0. Install dependencies with `yarn`.

1. Generate the Solita SDK with `yarn solita`.

2. Then build the SDK with `yarn build`.

# Testing the SDK

Run `yarn test`. Expect `jest` to detect an open handle that prevents it from exiting tests naturally.
3. Run tests with `yarn test`. (Expect `jest` to detect an open handle that prevents it from exiting naturally)
10 changes: 6 additions & 4 deletions account-compression/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@solana/spl-account-compression",
"description": "SPL Account Compression Program JS API",
"version": "0.1.0",
"version": "0.1.1",
"author": "Solana Maintainers <maintainers@solana.foundation>",
"repository": {
"url": "https://github.com/solana-labs/solana-program-library",
Expand Down Expand Up @@ -37,7 +37,9 @@
"start-validator": "solana-test-validator --reset --quiet --bpf-program cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK ../target/deploy/spl_account_compression.so --bpf-program noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV ../target/deploy/spl_noop.so",
"run-tests": "jest tests --detectOpenHandles",
"run-tests:events": "jest tests/events --detectOpenHandles",
"run-tests:accounts": "jest tests/accounts --detectOpenHandles",
"test:events": "start-server-and-test start-validator http://localhost:8899/health run-tests:events",
"test:accounts": "start-server-and-test start-validator http://localhost:8899/health run-tests:accounts",
"test": "start-server-and-test start-validator http://localhost:8899/health run-tests"
},
"dependencies": {
Expand All @@ -46,11 +48,11 @@
"borsh": "^0.7.0"
},
"peerDependencies": {
"@metaplex-foundation/beet": "^0.6.1",
"@metaplex-foundation/beet-solana": "^0.6.1",
"@solana/web3.js": "^1.50.1"
},
"devDependencies": {
"@metaplex-foundation/beet": "^0.7.1",
"@metaplex-foundation/beet-solana": "^0.4.0",
"@metaplex-foundation/rustbin": "^0.3.1",
"@metaplex-foundation/solita": "0.15.2",
"@project-serum/anchor": "^0.25.0",
Expand All @@ -68,4 +70,4 @@
"typescript": "=4.7.4",
"typescript-collections": "^1.3.3"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { PublicKey, Connection } from "@solana/web3.js";
import type { PublicKey, Connection, Commitment, GetAccountInfoConfig } from "@solana/web3.js";
import * as borsh from "borsh";
import * as BN from 'bn.js';
import * as beet from '@metaplex-foundation/beet';
Expand Down Expand Up @@ -35,8 +35,8 @@ export class ConcurrentMerkleTreeAccount {
return deserializeConcurrentMerkleTree(buffer);
}

static async fromAccountAddress(connection: Connection, publicKey: PublicKey): Promise<ConcurrentMerkleTreeAccount> {
const account = await connection.getAccountInfo(publicKey);
static async fromAccountAddress(connection: Connection, publicKey: PublicKey, commitmentOrConfig?: Commitment | GetAccountInfoConfig): Promise<ConcurrentMerkleTreeAccount> {
const account = await connection.getAccountInfo(publicKey, commitmentOrConfig);
if (!account) {
throw new Error("CMT account data unexpectedly null!");
}
Expand Down Expand Up @@ -79,9 +79,13 @@ export class ConcurrentMerkleTreeAccount {
return new BN.BN(this.tree.sequenceNumber).toNumber();
}

getCanopyDepth(): number {
return getCanopyDepth(this.canopy.canopyBytes.length);
}

};

function getCanopyDepth(canopyByteLength: number): number {
export function getCanopyDepth(canopyByteLength: number): number {
if (canopyByteLength === 0) {
return 0;
}
Expand Down
38 changes: 37 additions & 1 deletion account-compression/sdk/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,40 @@ import {
} from "@solana/web3.js";

export const SPL_NOOP_ADDRESS = "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV";
export const SPL_NOOP_PROGRAM_ID = new PublicKey(SPL_NOOP_ADDRESS);
export const SPL_NOOP_PROGRAM_ID = new PublicKey(SPL_NOOP_ADDRESS);

type DepthSizePair = {
maxDepth: number,
maxBufferSize: number
};

const allPairs: number[][] = [
[3, 8],
[5, 8],
[14, 64],
[14, 256],
[14, 1024],
[14, 2048],
[20, 64],
[20, 256],
[20, 1024],
[20, 2048],
[24, 64],
[24, 256],
[24, 512],
[24, 1024],
[24, 2048],
[26, 512],
[26, 1024],
[26, 2048],
[30, 512],
[30, 1024],
[30, 2048],
];

export const ALL_DEPTH_SIZE_PAIRS: DepthSizePair[] = allPairs.map((pair) => {
return {
maxDepth: pair[0],
maxBufferSize: pair[1]
}
})
3 changes: 0 additions & 3 deletions account-compression/sdk/tests/accountCompression.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import { BN } from 'bn.js';
import { AnchorProvider } from "@project-serum/anchor";
import {
Connection,
Signer,
Keypair,
PublicKey,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { assert } from "chai";
Expand Down
64 changes: 31 additions & 33 deletions account-compression/sdk/tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,6 @@ import {
Tree,
} from "./merkleTree";

export async function assertCMTProperties(
connection: Connection,
expectedMaxDepth: number,
expectedMaxBufferSize: number,
expectedAuthority: PublicKey,
expectedRoot: Buffer,
onChainCMTKey: PublicKey
) {
const onChainCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, onChainCMTKey);

assert(
onChainCMT.getMaxDepth() === expectedMaxDepth,
`Max depth does not match ${onChainCMT.getMaxDepth()}, expected ${expectedMaxDepth}`,
);
assert(
onChainCMT.getMaxBufferSize() === expectedMaxBufferSize,
`Max buffer size does not match ${onChainCMT.getMaxBufferSize()}, expected ${expectedMaxBufferSize}`,
);
assert(
onChainCMT.getAuthority().equals(expectedAuthority),
"Failed to write auth pubkey",
);
assert(
onChainCMT.getCurrentRoot().equals(expectedRoot),
"On chain root does not match root passed in instruction",
);
}


/// Wait for a transaction of a certain id to confirm and optionally log its messages
export async function confirmAndLogTx(provider: AnchorProvider, txId: string, verbose: boolean = false) {
const tx = await provider.connection.confirmTransaction(txId, "confirmed");
Expand Down Expand Up @@ -98,6 +69,7 @@ export async function execute(
return txid;
}


export async function createTreeOnChain(
provider: AnchorProvider,
payer: Keypair,
Expand Down Expand Up @@ -152,15 +124,41 @@ export async function createTreeOnChain(
appendIxs = appendIxs.slice(5,);
}
}
return [cmtKeypair, tree];
}

await assertCMTProperties(
export async function createEmptyTreeOnChain(
provider: AnchorProvider,
payer: Keypair,
maxDepth: number,
maxSize: number,
canopyDepth: number = 0,
): Promise<Keypair> {
const cmtKeypair = Keypair.generate();
const allocAccountIx = await createAllocTreeIx(
provider.connection,
maxDepth,
maxSize,
maxDepth,
canopyDepth,
payer.publicKey,
tree.root,
cmtKeypair.publicKey
);

return [cmtKeypair, tree];
let ixs = [
allocAccountIx,
createInitEmptyMerkleTreeIx(
payer,
cmtKeypair.publicKey,
maxDepth,
maxSize,
)
];

let txId = await execute(provider, ixs, [
payer,
cmtKeypair,
]);
await confirmAndLogTx(provider, txId as string);

return cmtKeypair;
}
19 changes: 19 additions & 0 deletions account-compression/sdk/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,16 @@
bs58 "^5.0.0"
debug "^4.3.4"

"@metaplex-foundation/beet-solana@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet-solana/-/beet-solana-0.4.0.tgz#52891e78674aaa54e0031f1bca5bfbc40de12e8d"
integrity sha512-B1L94N3ZGMo53b0uOSoznbuM5GBNJ8LwSeznxBxJ+OThvfHQ4B5oMUqb+0zdLRfkKGS7Q6tpHK9P+QK0j3w2cQ==
dependencies:
"@metaplex-foundation/beet" ">=0.1.0"
"@solana/web3.js" "^1.56.2"
bs58 "^5.0.0"
debug "^4.3.4"

"@metaplex-foundation/beet@>=0.1.0", "@metaplex-foundation/beet@^0.6.1":
version "0.6.1"
resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet/-/beet-0.6.1.tgz#6331bdde0648bf2cae6f9e482f8e3552db05d69f"
Expand All @@ -629,6 +639,15 @@
bn.js "^5.2.0"
debug "^4.3.3"

"@metaplex-foundation/beet@^0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet/-/beet-0.7.1.tgz#0975314211643f87b5f6f3e584fa31abcf4c612c"
integrity sha512-hNCEnS2WyCiYyko82rwuISsBY3KYpe828ubsd2ckeqZr7tl0WVLivGkoyA/qdiaaHEBGdGl71OpfWa2rqL3DiA==
dependencies:
ansicolors "^0.3.2"
bn.js "^5.2.0"
debug "^4.3.3"

"@metaplex-foundation/rustbin@^0.3.0", "@metaplex-foundation/rustbin@^0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@metaplex-foundation/rustbin/-/rustbin-0.3.1.tgz#bbcd61e8699b73c0b062728c6f5e8d52e8145042"
Expand Down