Skip to content

Commit

Permalink
get-light-state-tree-info.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
SwenSchaeferjohann committed Jan 18, 2025
1 parent 4d37e98 commit 0a30fb6
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 4 deletions.
2 changes: 1 addition & 1 deletion js/compressed-token/src/actions/create-mint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
* TOKEN_PROGRAM_ID. You can pass in a boolean to
* automatically resolve to TOKEN_2022_PROGRAM_ID if
* true, or TOKEN_PROGRAM_ID if false.
* @param freezeAuthority Account that will control freezing. Defaults to null.
* @param freezeAuthority Account that will control freeze and thaw. Defaults to null.
*
* @return Address of the new mint and the transaction signature
*/
Expand Down
3 changes: 1 addition & 2 deletions js/compressed-token/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ export type CompressedCpiContext = {
firstSetContext: boolean;
cpiContextAccountIndex: number; // u8
};
/// TODO: remove index_mt_account on-chain. passed as part of
/// CompressedTokenInstructionDataInvoke

export type TokenTransferOutputData = {
/**
* The owner of the output token account
Expand Down
1 change: 1 addition & 0 deletions js/stateless.js/src/test-helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './merkle-tree';
export * from './test-rpc';
export * from './test-utils';
File renamed without changes.
211 changes: 211 additions & 0 deletions js/stateless.js/src/utils/get-light-state-tree-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import {
AddressLookupTableProgram,
Connection,
Keypair,
PublicKey,
} from '@solana/web3.js';
import { buildAndSignTx, sendAndConfirmTx } from './send-and-confirm';
import { Rpc } from '../rpc';

/**
* Create two lookup tables storing all public state tree and queue addresses
* returns lookup table addresses and txId
* [stateTreeLookupTable, nullifyTable]
* @internal
* @param connection - Connection to the Solana network
* @param payer - Keypair of the payer
* @param authority - Keypair of the authority
* @param recentSlot - Slot of the recent block
*/
export async function createStateTreeLookupTables(
connection: Rpc,
payer: Keypair,
authority: Keypair,
recentSlot: number,
) {
const [createInstruction1, lookupTableAddress1] =
AddressLookupTableProgram.createLookupTable({
payer: payer.publicKey,
authority: authority.publicKey,
recentSlot,
});

const [createInstruction2, lookupTableAddress2] =
AddressLookupTableProgram.createLookupTable({
payer: payer.publicKey,
authority: authority.publicKey,
recentSlot,
});

const blockhash = await connection.getLatestBlockhash();

const tx = buildAndSignTx(
[createInstruction1, createInstruction2],
payer,
blockhash.blockhash,
);
const txId = await sendAndConfirmTx(connection, tx);

return {
addresses: [lookupTableAddress1, lookupTableAddress2],
txId,
};
}

/**
* Extend state tree lookup table with new state tree and queue addresses
* @internal
* @param connection - Connection to the Solana network
* @param tableAddress - Address of the lookup table to extend
* @param newStateTreeAddress - Address of the new state tree to add
* @param newQueueAddress - Address of the new queue to add
* @param payer - Keypair of the payer
* @param authority - Keypair of the authority
*/
export async function extendStateTreeLookupTable(
connection: Rpc,
tableAddress: PublicKey,
newStateTreeAddress: PublicKey,
newQueueAddress: PublicKey,
payer: Keypair,
authority: Keypair,
) {
const instructions = AddressLookupTableProgram.extendLookupTable({
payer: payer.publicKey,
authority: authority.publicKey,
lookupTable: tableAddress,
addresses: [newStateTreeAddress, newQueueAddress],
});

const blockhash = await connection.getLatestBlockhash();

const tx = buildAndSignTx([instructions], payer, blockhash.blockhash);
const txId = await sendAndConfirmTx(connection, tx);

return {
tableAddress,
txId,
};
}

/**
* Adds full state tree address to lookup table. Acts as nullifier
* @internal
* @param connection - Connection to the Solana network
* @param stateTreeAddress - Address of the state tree to nullify
* @param nullifyTableAddress - Address nullifier lookup table to store address in
* @param stateTreeLookupTableAddress - lookup table storing all state tree addresses
* @param payer - Keypair of the payer
* @param authority - Keypair of the authority
*/
export async function nullifyLookupTable({
connection,
fullStateTreeAddress,
nullifyTableAddress,
stateTreeLookupTableAddress,
payer,
authority,
}: {
connection: Rpc;
fullStateTreeAddress: PublicKey;
nullifyTableAddress: PublicKey;
stateTreeLookupTableAddress: PublicKey;
payer: Keypair;
authority: Keypair;
}) {
// to be nullified address must be part of stateTreeLookupTable set
const stateTreeLookupTable = await connection.getAddressLookupTable(
stateTreeLookupTableAddress,
);

if (!stateTreeLookupTable) {
throw new Error('State tree lookup table not found');
}

if (
!stateTreeLookupTable.value?.state.addresses.includes(
fullStateTreeAddress,
)
) {
throw new Error(
'State tree address not found in lookup table. Pass correct address or stateTreeLookupTable',
);
}

const nullifyTable =
await connection.getAddressLookupTable(nullifyTableAddress);

if (!nullifyTable) {
throw new Error('Nullify table not found');
}
if (nullifyTable.value?.state.addresses.includes(fullStateTreeAddress)) {
throw new Error('State tree address already in nullify table');
}

const instructions = AddressLookupTableProgram.extendLookupTable({
payer: payer.publicKey,
authority: authority.publicKey,
lookupTable: nullifyTableAddress,
addresses: [fullStateTreeAddress],
});

const blockhash = await connection.getLatestBlockhash();

const tx = buildAndSignTx([instructions], payer, blockhash.blockhash);
const txId = await sendAndConfirmTx(connection, tx);

return {
txId,
};
}

/**
* Get most recent , active state tree data
* we store in lookup table for each public state tree
*/
export async function getLightStateTreeInfo(
connection: Connection,
stateTreeLookupTableAddress: PublicKey,
nullifyTableAddress: PublicKey,
) {
const stateTreeLookupTable = await connection.getAddressLookupTable(
stateTreeLookupTableAddress,
);

if (!stateTreeLookupTable) {
throw new Error('State tree lookup table not found');
}

const stateTreePubkeys = stateTreeLookupTable.value?.state.addresses || [];

const nullifyTable =
await connection.getAddressLookupTable(nullifyTableAddress);

if (!nullifyTable) {
throw new Error('Nullify table not found');
}

const nullifyTablePubkeys = nullifyTable.value?.state.addresses || [];

const activeStateTrees = stateTreePubkeys.filter(
(_, index) =>
index % 2 === 0 &&
!nullifyTablePubkeys.includes(stateTreePubkeys[index]),
);
const activeQueues = stateTreePubkeys.filter(
(_, index) =>
index % 2 !== 0 &&
!nullifyTablePubkeys.includes(stateTreePubkeys[index]),
);

if (activeStateTrees.length !== activeQueues.length) {
throw new Error(
'Must have equal number of active state trees and queues',
);
}

return {
activeStateTrees,
activeQueues,
};
}
1 change: 0 additions & 1 deletion js/stateless.js/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ export * from './parse-validity-proof';
export * from './pipe';
export * from './send-and-confirm';
export * from './sleep';
export * from './test-utils';
export * from './validation';
export * from './calculate-compute-unit-price';

0 comments on commit 0a30fb6

Please sign in to comment.