From 80fb05c6c0718e0a235e8f02eaab77477827da5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?=
<42959314+SwenSchaeferjohann@users.noreply.github.com>
Date: Wed, 20 Nov 2024 23:17:42 +0000
Subject: [PATCH] feat: bump to 0.50.0, add getCompressedTokenBalancesByOwnerV2
(#1353)
* bump to 0.50.0, add getCompressedTokenBalancesByOwnerV2, extend rem. endpoints with opt. cursors
* upd name paginatedoptions
* released js
* add --no-reset flag to install.sh
* clean readme
* upd readme
* upd readme for ctoken
* capitalization
* bump js release, readme updates
---------
Co-authored-by: Swenschaeferjohann
---
cli/README.md | 6 +-
cli/package.json | 6 +-
cli/src/utils/constants.ts | 2 +-
js/compressed-token/README.md | 26 ++++--
js/compressed-token/package.json | 2 +-
.../tests/e2e/rpc-token-interop.test.ts | 38 ++++++++
js/stateless.js/README.md | 26 +-----
js/stateless.js/package.json | 2 +-
js/stateless.js/src/rpc-interface.ts | 26 +++++-
js/stateless.js/src/rpc.ts | 93 +++++++++++++++++--
.../src/test-helpers/test-rpc/test-rpc.ts | 44 +++++++--
scripts/install.sh | 15 ++-
12 files changed, 227 insertions(+), 59 deletions(-)
diff --git a/cli/README.md b/cli/README.md
index a2af2adfe..0c5f9fbe1 100644
--- a/cli/README.md
+++ b/cli/README.md
@@ -1,6 +1,6 @@
# ZK Compression CLI
-CLI to interact with ZK compression.
+CLI to interact with compressed accounts and compressed tokens on Solana.
## Requirements
@@ -179,9 +179,7 @@ FLAGS
```
-#### Compress native SOL
-
-> **Note:** Ensure the SOL omnibus account of the Light system program is already initialized by running: `light init-sol-pool`
+#### Assign native SOL to a compressed account
```bash
light compress-sol --amount 1000 --to "YOUR_WALLET_ADDRESS_BASE58"
diff --git a/cli/package.json b/cli/package.json
index 9bffdb80a..bd4e74b70 100644
--- a/cli/package.json
+++ b/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@lightprotocol/zk-compression-cli",
- "version": "0.19.3",
+ "version": "0.20.1",
"description": "ZK Compression: Secure Scaling on Solana",
"maintainers": [
{
@@ -21,6 +21,10 @@
"./config.json",
"/npm-shrinkwrap.json",
"/oclif.manifest.json",
+ "!bin/proving-keys/address-append_26_1.key",
+ "!bin/proving-keys/address-append_26_1.vkey",
+ "!bin/proving-keys/address-append_26_10.key",
+ "!bin/proving-keys/address-append_26_10.vkey",
"!bin/proving-keys/append-with-proofs_26_10.key",
"!bin/proving-keys/append-with-proofs_26_10.vkey",
"!bin/proving-keys/append-with-subtrees_26_10.key",
diff --git a/cli/src/utils/constants.ts b/cli/src/utils/constants.ts
index 34366e4f1..05c4bcc67 100644
--- a/cli/src/utils/constants.ts
+++ b/cli/src/utils/constants.ts
@@ -19,7 +19,7 @@ export const SOLANA_VALIDATOR_PROCESS_NAME = "solana-test-validator";
export const LIGHT_PROVER_PROCESS_NAME = "light-prover";
export const INDEXER_PROCESS_NAME = "photon";
-export const PHOTON_VERSION = "0.48.0";
+export const PHOTON_VERSION = "0.50.0";
export const LIGHT_PROTOCOL_PROGRAMS_DIR_ENV = "LIGHT_PROTOCOL_PROGRAMS_DIR";
export const BASE_PATH = "../../bin/";
diff --git a/js/compressed-token/README.md b/js/compressed-token/README.md
index 755c1600c..3e59da4ee 100644
--- a/js/compressed-token/README.md
+++ b/js/compressed-token/README.md
@@ -1,24 +1,36 @@
-# TS client for Interacting with the Compressed-Token Program
+
+
+
+
+@lightprotocol/compressed-token
+
+
+ This is the JavaScript SDK for interacting with the Compressed Token program on Solana.
+
+
+
+
+
+
+
+
+
-Use this to interact with the compressed-token program on Solana via the
-Compression RPC API.
### Installation
-**For use in Node.js or a web application**
+**For use in Node.js or web**
```bash
npm install --save \
@lightprotocol/compressed-token \
@lightprotocol/stateless.js \
- @solana/web3.js \
- @coral-xyz/anchor@0.29
```
### Documentation and examples
- [Latest Source code](https://github.com/lightprotocol/lightprotocol/tree/main/js/compressed-token)
-- Documentation and examples will be linked here soon!
+- [Creating and sending compressed tokens](https://www.zkcompression.com/developers/typescript-client#creating-minting-and-transferring-a-compressed-token)
### Getting help
diff --git a/js/compressed-token/package.json b/js/compressed-token/package.json
index 31b89abd1..abebc852b 100644
--- a/js/compressed-token/package.json
+++ b/js/compressed-token/package.json
@@ -1,6 +1,6 @@
{
"name": "@lightprotocol/compressed-token",
- "version": "0.14.3",
+ "version": "0.15.1",
"description": "JS client to interact with the compressed-token program",
"sideEffects": false,
"main": "dist/cjs/node/index.cjs",
diff --git a/js/compressed-token/tests/e2e/rpc-token-interop.test.ts b/js/compressed-token/tests/e2e/rpc-token-interop.test.ts
index 761fc00a6..8512cc6a5 100644
--- a/js/compressed-token/tests/e2e/rpc-token-interop.test.ts
+++ b/js/compressed-token/tests/e2e/rpc-token-interop.test.ts
@@ -152,6 +152,44 @@ describe('rpc-interop token', () => {
});
});
+
+ it('getCompressedTokenBalancesByOwnerV2 should match', async () => {
+ const balances = (
+ await rpc.getCompressedTokenBalancesByOwnerV2(bob.publicKey, {
+ mint,
+ })
+ ).value.items;
+ const balancesTest = (
+ await testRpc.getCompressedTokenBalancesByOwnerV2(bob.publicKey, {
+ mint,
+ })
+ ).value.items;
+
+ assert.equal(balances.length, balancesTest.length);
+
+ balances.forEach((balance, index) => {
+ assert.isTrue(balance.balance.eq(balancesTest[index].balance));
+ });
+
+ const balancesReceiver = (
+ await rpc.getCompressedTokenBalancesByOwnerV2(charlie.publicKey, {
+ mint,
+ })
+ ).value.items;
+ const balancesReceiverTest = (
+ await testRpc.getCompressedTokenBalancesByOwnerV2(charlie.publicKey, {
+ mint,
+ })
+ ).value.items;
+
+ assert.equal(balancesReceiver.length, balancesReceiverTest.length);
+ balancesReceiver.forEach((balance, index) => {
+ assert.isTrue(
+ balance.balance.eq(balancesReceiverTest[index].balance),
+ );
+ });
+ });
+
it('[test-rpc missing] getSignaturesForTokenOwner should match', async () => {
const signatures = (
await rpc.getCompressionSignaturesForTokenOwner(bob.publicKey)
diff --git a/js/stateless.js/README.md b/js/stateless.js/README.md
index 5f75ed491..a0a65b7bf 100644
--- a/js/stateless.js/README.md
+++ b/js/stateless.js/README.md
@@ -2,10 +2,10 @@
-Stateless.js
+@lightprotocol/stateless.js
- Integrate server and web applications with ZK Compression on Solana.
+ This is the JavaScript SDK for building Solana applications with ZK Compression for Node and web.
@@ -16,14 +16,6 @@
-## Overview
-
-This package provides server and web applications with clients, utilities, and types to leverage the power of [ZK Compression](https://www.zkcompression.com/) on Solana via the Compression RPC API.
-
-> The core ZK Compression Solana programs and clients are maintained by
-> [Light](https://github.com/lightprotocol) as a part of the Light Protocol. The RPC API and indexer are maintained by
-> [Helius Labs](https://github.com/helius-labs).
-
## Usage
### Installation
@@ -31,22 +23,14 @@ This package provides server and web applications with clients, utilities, and t
Install this package in your project by running the following terminal command:
```bin
-npm install --save \
- @lightprotocol/stateless.js \
- @solana/web3.js \
- @coral-xyz/anchor@0.29
+npm install --save @lightprotocol/stateless.js
```
-### Dependencies
-
-- [`@solana/web3.js`](https://www.npmjs.com/package/@solana/web3.js) — provides access to the Solana network via RPC.
-- [`@coral-xyz/anchor`](https://www.npmjs.com/package/@coral-xyz/anchor) — a client for [Anchor](https://www.anchor-lang.com/) Solana programs.
-
## Documentation and Examples
For a more detailed documentation on usage, please check [the respective section at the ZK Compression documentation.](https://www.zkcompression.com/developers/typescript-client)
-For example implementations, including web and server, refer to the respective repositories:
+For example implementations, including web and Node, refer to the respective repositories:
- [Web application example implementation](https://github.com/Lightprotocol/example-web-client)
@@ -55,7 +39,7 @@ For example implementations, including web and server, refer to the respective r
## Troubleshooting
Have a question or a problem?
-Feel free to ask in the [Light](https://discord.gg/CYvjBgzRFP) and [Helius](https://discord.gg/Uzzf6a7zKr) developer Discord servers. Please, include the following information to better be able to respond:
+Feel free to ask in the [Light](https://discord.gg/CYvjBgzRFP) and [Helius](https://discord.gg/Uzzf6a7zKr) developer Discord servers. Please, include the following information:
- A detailed description or context of the issue or what you are trying to achieve.
- A code example that we can use to test and debug (if possible). Use [CodeSandbox](https://codesandbox.io/p/sandbox/vanilla-ts) or any other live environment provider.
diff --git a/js/stateless.js/package.json b/js/stateless.js/package.json
index 8064da679..6dab22af3 100644
--- a/js/stateless.js/package.json
+++ b/js/stateless.js/package.json
@@ -1,6 +1,6 @@
{
"name": "@lightprotocol/stateless.js",
- "version": "0.14.4",
+ "version": "0.15.1",
"description": "JavaScript API for Light and ZK Compression",
"sideEffects": false,
"main": "dist/cjs/node/index.cjs",
diff --git a/js/stateless.js/src/rpc-interface.ts b/js/stateless.js/src/rpc-interface.ts
index 1cccfa565..ebdc1fade 100644
--- a/js/stateless.js/src/rpc-interface.ts
+++ b/js/stateless.js/src/rpc-interface.ts
@@ -130,8 +130,14 @@ export interface GetCompressedTokenAccountsByOwnerOrDelegateOptions {
cursor?: string;
limit?: BN;
}
+export type TokenBalance = { balance: BN; mint: PublicKey };
-export interface GetCompressedMintTokenHoldersOptions {
+/**
+ * **Cursor** is a unique identifier for a page of results by which the next page can be fetched.
+ *
+ * **Limit** is the maximum number of results to return per page.
+ */
+export interface PaginatedOptions {
cursor?: string;
limit?: BN;
}
@@ -441,6 +447,11 @@ export const TokenBalanceListResult = pick({
cursor: nullable(string()),
});
+export const TokenBalanceListResultV2 = pick({
+ items: array(TokenBalanceResult),
+ cursor: nullable(string()),
+});
+
export const CompressedMintTokenHoldersResult = pick({
cursor: nullable(string()),
items: array(
@@ -546,7 +557,7 @@ export interface CompressionApiInterface {
getCompressedMintTokenHolders(
mint: PublicKey,
- options?: GetCompressedMintTokenHoldersOptions,
+ options?: PaginatedOptions,
): Promise>>;
getCompressedTokenAccountsByOwner(
@@ -564,7 +575,12 @@ export interface CompressionApiInterface {
getCompressedTokenBalancesByOwner(
publicKey: PublicKey,
options: GetCompressedTokenAccountsByOwnerOrDelegateOptions,
- ): Promise>;
+ ): Promise>;
+
+ getCompressedTokenBalancesByOwnerV2(
+ publicKey: PublicKey,
+ options: GetCompressedTokenAccountsByOwnerOrDelegateOptions,
+ ): Promise>>;
getTransactionWithCompressionInfo(
signature: string,
@@ -576,18 +592,22 @@ export interface CompressionApiInterface {
getCompressionSignaturesForAddress(
address: PublicKey,
+ options?: PaginatedOptions,
): Promise>;
getCompressionSignaturesForOwner(
owner: PublicKey,
+ options?: PaginatedOptions,
): Promise>;
getCompressionSignaturesForTokenOwner(
owner: PublicKey,
+ options?: PaginatedOptions,
): Promise>;
getLatestNonVotingSignatures(
limit?: number,
+ cursor?: string,
): Promise;
getLatestCompressionSignatures(
diff --git a/js/stateless.js/src/rpc.ts b/js/stateless.js/src/rpc.ts
index c86319305..0370dc9f4 100644
--- a/js/stateless.js/src/rpc.ts
+++ b/js/stateless.js/src/rpc.ts
@@ -41,7 +41,9 @@ import {
HashWithTree,
CompressedMintTokenHoldersResult,
CompressedMintTokenHolders,
- GetCompressedMintTokenHoldersOptions,
+ TokenBalance,
+ TokenBalanceListResultV2,
+ PaginatedOptions,
} from './rpc-interface';
import {
MerkleContextWithMerkleProof,
@@ -806,13 +808,15 @@ export class Rpc extends Connection implements CompressionApiInterface {
}
/**
+ * @deprecated use {@link getCompressedTokenBalancesByOwnerV2} instead.
+ *
* Fetch all the compressed token balances owned by the specified public
- * key. Can filter by mint
+ * key. Can filter by mint. Returns without context.
*/
async getCompressedTokenBalancesByOwner(
owner: PublicKey,
options?: GetCompressedTokenAccountsByOwnerOrDelegateOptions,
- ): Promise> {
+ ): Promise> {
if (!options) options = {};
const unsafeRes = await rpcRequest(
@@ -855,6 +859,59 @@ export class Rpc extends Connection implements CompressionApiInterface {
};
}
+ /**
+ * Fetch the compressed token balances owned by the specified public
+ * key. Paginated. Can filter by mint. Returns with context.
+ */
+ async getCompressedTokenBalancesByOwnerV2(
+ owner: PublicKey,
+ options?: GetCompressedTokenAccountsByOwnerOrDelegateOptions,
+ ): Promise>> {
+ if (!options) options = {};
+
+ const unsafeRes = await rpcRequest(
+ this.compressionApiEndpoint,
+ 'getCompressedTokenBalancesByOwnerV2',
+ {
+ owner: owner.toBase58(),
+ mint: options.mint?.toBase58(),
+ limit: options.limit?.toNumber(),
+ cursor: options.cursor,
+ },
+ );
+
+ const res = create(
+ unsafeRes,
+ jsonRpcResultAndContext(TokenBalanceListResultV2),
+ );
+ if ('error' in res) {
+ throw new SolanaJSONRPCError(
+ res.error,
+ `failed to get compressed token balances for owner ${owner.toBase58()}`,
+ );
+ }
+ if (res.result.value === null) {
+ throw new Error(
+ `failed to get compressed token balances for owner ${owner.toBase58()}`,
+ );
+ }
+
+ const maybeFiltered = options.mint
+ ? res.result.value.items.filter(
+ tokenBalance =>
+ tokenBalance.mint.toBase58() === options.mint!.toBase58(),
+ )
+ : res.result.value.items;
+
+ return {
+ context: res.result.context,
+ value: {
+ items: maybeFiltered,
+ cursor: res.result.value.cursor,
+ },
+ };
+ }
+
/**
* Returns confirmed compression signatures for transactions involving the specified
* account hash forward in time from genesis to the most recent confirmed
@@ -985,11 +1042,16 @@ export class Rpc extends Connection implements CompressionApiInterface {
*/
async getCompressionSignaturesForAddress(
address: PublicKey,
+ options?: PaginatedOptions,
): Promise> {
const unsafeRes = await rpcRequest(
this.compressionApiEndpoint,
'getCompressionSignaturesForAddress',
- { address: address.toBase58() },
+ {
+ address: address.toBase58(),
+ cursor: options?.cursor,
+ limit: options?.limit?.toNumber(),
+ },
);
const res = create(
@@ -1020,11 +1082,16 @@ export class Rpc extends Connection implements CompressionApiInterface {
*/
async getCompressionSignaturesForOwner(
owner: PublicKey,
+ options?: PaginatedOptions,
): Promise> {
const unsafeRes = await rpcRequest(
this.compressionApiEndpoint,
'getCompressionSignaturesForOwner',
- { owner: owner.toBase58() },
+ {
+ owner: owner.toBase58(),
+ cursor: options?.cursor,
+ limit: options?.limit?.toNumber(),
+ },
);
const res = create(
@@ -1046,7 +1113,6 @@ export class Rpc extends Connection implements CompressionApiInterface {
return res.result.value;
}
- /// TODO(photon): needs mint
/**
* Returns confirmed signatures for compression transactions involving the
* specified token account owner forward in time from genesis to the most
@@ -1054,11 +1120,16 @@ export class Rpc extends Connection implements CompressionApiInterface {
*/
async getCompressionSignaturesForTokenOwner(
owner: PublicKey,
+ options?: PaginatedOptions,
): Promise> {
const unsafeRes = await rpcRequest(
this.compressionApiEndpoint,
'getCompressionSignaturesForTokenOwner',
- { owner: owner.toBase58() },
+ {
+ owner: owner.toBase58(),
+ cursor: options?.cursor,
+ limit: options?.limit?.toNumber(),
+ },
);
const res = create(
@@ -1132,9 +1203,12 @@ export class Rpc extends Connection implements CompressionApiInterface {
return res.result;
}
+ /**
+ * Fetch all the compressed token holders for a given mint. Paginated.
+ */
async getCompressedMintTokenHolders(
mint: PublicKey,
- options?: GetCompressedMintTokenHoldersOptions,
+ options?: PaginatedOptions,
): Promise>> {
const unsafeRes = await rpcRequest(
this.compressionApiEndpoint,
@@ -1189,11 +1263,12 @@ export class Rpc extends Connection implements CompressionApiInterface {
*/
async getLatestNonVotingSignatures(
limit?: number,
+ cursor?: string,
): Promise {
const unsafeRes = await rpcRequest(
this.compressionApiEndpoint,
'getLatestNonVotingSignatures',
- { limit },
+ { limit, cursor },
);
const res = create(
unsafeRes,
diff --git a/js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts b/js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts
index adc1ea5e9..cdba8c2dc 100644
--- a/js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts
+++ b/js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts
@@ -19,7 +19,7 @@ import {
CompressedMintTokenHolders,
CompressedTransaction,
GetCompressedAccountsByOwnerConfig,
- GetCompressedMintTokenHoldersOptions,
+ PaginatedOptions,
HashWithTree,
LatestNonVotingSignatures,
LatestNonVotingSignaturesPaginated,
@@ -32,6 +32,7 @@ import {
CompressionApiInterface,
GetCompressedTokenAccountsByOwnerOrDelegateOptions,
ParsedTokenAccount,
+ TokenBalance,
} from '../../rpc-interface';
import {
BN254,
@@ -418,8 +419,9 @@ export class TestRpc extends Connection implements CompressionApiInterface {
}
/**
+ * @deprecated use {@link getCompressedTokenBalancesByOwnerV2}.
* Fetch all the compressed token balances owned by the specified public
- * key. Can filter by mint
+ * key. Can filter by mint.
*/
async getCompressedTokenBalancesByOwner(
publicKey: PublicKey,
@@ -439,6 +441,31 @@ export class TestRpc extends Connection implements CompressionApiInterface {
};
}
+ /**
+ * Fetch all the compressed token balances owned by the specified public
+ * key. Can filter by mint. Uses context.
+ */
+ async getCompressedTokenBalancesByOwnerV2(
+ publicKey: PublicKey,
+ options: GetCompressedTokenAccountsByOwnerOrDelegateOptions,
+ ): Promise>> {
+ const accounts = await getCompressedTokenAccountsByOwnerTest(
+ this,
+ publicKey,
+ options.mint!,
+ );
+ return {
+ context: { slot: 1 },
+ value: {
+ items: accounts.items.map(account => ({
+ balance: bn(account.parsed.amount),
+ mint: account.parsed.mint,
+ })),
+ cursor: null,
+ },
+ };
+ }
+
/**
* Returns confirmed signatures for transactions involving the specified
* account hash forward in time from genesis to the most recent confirmed
@@ -447,7 +474,7 @@ export class TestRpc extends Connection implements CompressionApiInterface {
* @param hash queried account hash
*/
async getCompressionSignaturesForAccount(
- hash: BN254,
+ _hash: BN254,
): Promise {
throw new Error(
'getCompressionSignaturesForAccount not implemented in test-rpc',
@@ -459,7 +486,7 @@ export class TestRpc extends Connection implements CompressionApiInterface {
* CompressionInfo
*/
async getTransactionWithCompressionInfo(
- signature: string,
+ _signature: string,
): Promise {
throw new Error('getCompressedTransaction not implemented in test-rpc');
}
@@ -473,6 +500,7 @@ export class TestRpc extends Connection implements CompressionApiInterface {
*/
async getCompressionSignaturesForAddress(
_address: PublicKey,
+ _options?: PaginatedOptions,
): Promise> {
throw new Error('getSignaturesForAddress3 not implemented');
}
@@ -485,7 +513,8 @@ export class TestRpc extends Connection implements CompressionApiInterface {
* @param owner queried owner public key
*/
async getCompressionSignaturesForOwner(
- owner: PublicKey,
+ _owner: PublicKey,
+ _options?: PaginatedOptions,
): Promise> {
throw new Error('getSignaturesForOwner not implemented');
}
@@ -496,7 +525,8 @@ export class TestRpc extends Connection implements CompressionApiInterface {
* recent confirmed block
*/
async getCompressionSignaturesForTokenOwner(
- owner: PublicKey,
+ _owner: PublicKey,
+ _options?: PaginatedOptions,
): Promise> {
throw new Error('getSignaturesForTokenOwner not implemented');
}
@@ -581,7 +611,7 @@ export class TestRpc extends Connection implements CompressionApiInterface {
async getCompressedMintTokenHolders(
_mint: PublicKey,
- _options?: GetCompressedMintTokenHoldersOptions,
+ _options?: PaginatedOptions,
): Promise>> {
throw new Error(
'getCompressedMintTokenHolders not implemented in test-rpc',
diff --git a/scripts/install.sh b/scripts/install.sh
index b3df6d3d3..6b09fadb5 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -13,7 +13,7 @@ VERSIONS=(
"solana:1.18.22"
"anchor:anchor-v0.29.0"
"jq:jq-1.7.1"
- "photon:0.48.0"
+ "photon:0.50.0"
)
# Architecture-specific suffixes
@@ -187,14 +187,19 @@ install_dependencies() {
main() {
mkdir -p "${PREFIX}/bin"
- # Parse command line arguments
+ # Parse command line arguments
local key_type="light"
+ local reset_log=true
while [[ $# -gt 0 ]]; do
case $1 in
--full-keys)
key_type="full"
shift
;;
+ --no-reset)
+ reset_log=false
+ shift
+ ;;
*)
echo "Unknown option: $1"
exit 1
@@ -202,6 +207,10 @@ main() {
esac
done
+ if $reset_log; then
+ rm -f "$INSTALL_LOG"
+ fi
+
install_go
install_rust
install_node
@@ -212,8 +221,6 @@ main() {
download_gnark_keys "$key_type"
install_dependencies
- rm -f "$INSTALL_LOG"
-
echo "✨ Light Protocol development dependencies installed"
}