Skip to content

Commit

Permalink
Account Compression: JS SDK release 0.1.1 (#3680)
Browse files Browse the repository at this point in the history
* ac: beet* as deps, not peerDeps

* ac: expose depth size pairs, add canopyDepth to CMTAccount getters

* ac: add tests for CMT Account

* ac: update README.md

* ac: update lockfile
  • Loading branch information
ngundotra authored Oct 13, 2022
1 parent 39935ba commit 6e81794
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 52 deletions.
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 <[email protected]>",
"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

0 comments on commit 6e81794

Please sign in to comment.