Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/light-examples-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
include:
- program: token-escrow-test
sub-tests: '[
"cargo test-sbf -p token-escrow -- --test-threads=1"
"cargo test-sbf -p token-escrow"
]'
- program: counter-test
sub-tests: '["cargo test-sbf -p counter"]'
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/light-system-programs-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,10 @@ jobs:
for subtest in "${sub_tests[@]}"
do
echo "$subtest"
eval "RUSTFLAGS=\"-D warnings\" $subtest"

RUSTFLAGS="-D warnings" eval "$subtest"
if [ "$subtest" == "cargo-test-sbf -p e2e-test" ]; then
pnpm --filter @lightprotocol/programs run build-compressed-token-small
RUSTFLAGS="-D warnings" eval "$subtest -- --test test_10_all"
fi
done
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@ output.txt
.nx/workspace-data
output1.txt
.zed

**/.claude/settings.local.json
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ pub fn cpi_compressed_token_transfer_pda<'info>(
compress_or_decompress_amount: None,
cpi_context: Some(cpi_context),
lamports_change_account_merkle_tree_index: None,
with_transaction_hash: false,
};

let mut inputs = Vec::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ pub fn cpi_compressed_token_withdrawal<'info>(
compress_or_decompress_amount: None,
cpi_context: Some(cpi_context),
lamports_change_account_merkle_tree_index: None,
with_transaction_hash: false,
};

let mut inputs = Vec::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub fn cpi_compressed_token_transfer<'info>(
compress_or_decompress_amount: None,
cpi_context: None,
lamports_change_account_merkle_tree_index: None,
with_transaction_hash: false,
};

let mut inputs = Vec::new();
Expand Down
1 change: 1 addition & 0 deletions examples/anchor/token-escrow/src/escrow_with_pda/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ pub fn create_withdrawal_escrow_instruction(
None,
None,
&[],
false,
);

let merkle_tree_indices = add_and_get_remaining_account_indices(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub fn withdrawal_cpi_compressed_token_transfer<'info>(
compress_or_decompress_amount: None,
cpi_context: None,
lamports_change_account_merkle_tree_index: None,
with_transaction_hash: false,
};

let mut inputs = Vec::new();
Expand Down
1 change: 1 addition & 0 deletions forester/tests/batched_state_async_indexer_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ async fn compressed_token_transfer<R: RpcConnection, I: Indexer<R>>(
None,
false,
&[],
false,
)
.unwrap();
println!(
Expand Down
3 changes: 2 additions & 1 deletion js/compressed-token/tests/e2e/mint-to.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,10 @@ describe('mintTo', () => {
await assertMintTo(rpc, mint, amount, bob.publicKey);

/// wrong authority
/// is not checked in cToken program, so it throws invalid owner inside spl token program.
await expect(
mintTo(rpc, payer, mint, bob.publicKey, Keypair.generate(), amount),
).rejects.toThrowError(/custom program error: 0x1782/);
).rejects.toThrowError(/custom program error: 0x4/);

/// with output state merkle tree defined
await mintTo(
Expand Down
8 changes: 8 additions & 0 deletions js/stateless.js/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ export const INVOKE_CPI_DISCRIMINATOR = Buffer.from([
49, 212, 191, 129, 39, 194, 43, 196,
]);

export const INVOKE_CPI_WITH_READ_ONLY_DISCRIMINATOR = Buffer.from([
86, 47, 163, 166, 21, 223, 92, 8,
]);

export const INVOKE_CPI_WITH_ACCOUNT_INFO_DISCRIMINATOR = Buffer.from([
228, 34, 128, 84, 47, 139, 86, 240,
]);

export const INSERT_INTO_QUEUES_DISCRIMINATOR = Buffer.from([
180, 143, 159, 153, 35, 46, 248, 163,
]);
Expand Down
92 changes: 92 additions & 0 deletions js/stateless.js/src/programs/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,98 @@ export const InstructionDataInvokeCpiLayout: Layout<InstructionDataInvokeCpi> =
),
]);

export const CompressedProofLayout = struct(
[array(u8(), 32, 'a'), array(u8(), 64, 'b'), array(u8(), 32, 'c')],
'compressedProof',
);

export const CompressedCpiContextLayout = struct(
[
bool('set_context'),
bool('first_set_context'),
u8('cpi_context_account_index'),
],
'compressedCpiContext',
);

export const NewAddressParamsAssignedPackedLayout = struct(
[
array(u8(), 32, 'seed'),
u8('address_queue_account_index'),
u8('address_merkle_tree_account_index'),
u16('address_merkle_tree_root_index'),
bool('assigned_to_account'),
u8('assigned_account_index'),
],
'newAddressParamsAssignedPacked',
);

export const PackedMerkleContextLayout = struct(
[
u8('merkle_tree_pubkey_index'),
u8('queue_pubkey_index'),
u32('leaf_index'),
bool('prove_by_index'),
],
'packedMerkleContext',
);

export const InAccountLayout = struct(
[
array(u8(), 8, 'discriminator'),
array(u8(), 32, 'data_hash'),
PackedMerkleContextLayout,
u16('root_index'),
u64('lamports'),
option(array(u8(), 32), 'address'),
],
'inAccount',
);

export const PackedReadOnlyAddressLayout = struct(
[
array(u8(), 32, 'address'),
u16('address_merkle_tree_root_index'),
u8('address_merkle_tree_account_index'),
],
'packedReadOnlyAddress',
);

export const PackedReadOnlyCompressedAccountLayout = struct(
[
array(u8(), 32, 'account_hash'),
PackedMerkleContextLayout,
u16('root_index'),
],
'packedReadOnlyCompressedAccount',
);

export const InstructionDataInvokeCpiWithReadOnlyLayout = struct([
u8('mode'),
u8('bump'),
publicKey('invoking_program_id'),
u64('compress_or_decompress_lamports'),
bool('is_compress'),
bool('with_cpi_context'),
bool('with_transaction_hash'),
CompressedCpiContextLayout,
option(CompressedProofLayout, 'proof'),
vec(NewAddressParamsAssignedPackedLayout, 'new_address_params'),
vec(InAccountLayout, 'input_compressed_accounts'),
vec(
struct([CompressedAccountLayout, u8('merkleTreeIndex')]),
'output_compressed_accounts',
),
vec(PackedReadOnlyAddressLayout, 'read_only_addresses'),
vec(PackedReadOnlyCompressedAccountLayout, 'read_only_accounts'),
]);

export function decodeInstructionDataInvokeCpiWithReadOnly(buffer: Buffer) {
return InstructionDataInvokeCpiWithReadOnlyLayout.decode(
buffer.slice(INVOKE_DISCRIMINATOR.length + 4),
);
}

export function decodeInstructionDataInvoke(
buffer: Buffer,
): InstructionDataInvoke {
Expand Down
18 changes: 17 additions & 1 deletion js/stateless.js/src/test-helpers/test-rpc/get-parsed-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
defaultStaticAccountsStruct,
INSERT_INTO_QUEUES_DISCRIMINATOR,
INVOKE_CPI_DISCRIMINATOR,
INVOKE_CPI_WITH_READ_ONLY_DISCRIMINATOR,
INVOKE_DISCRIMINATOR,
} from '../../constants';
import {
Expand All @@ -22,8 +23,12 @@ import {
} from '../../programs';
import { Rpc } from '../../rpc';
import { InstructionDataInvoke, PublicTransactionEvent } from '../../state';
import { decodePublicTransactionEvent } from '../../programs/layout';
import {
decodeInstructionDataInvokeCpiWithReadOnly,
decodePublicTransactionEvent,
} from '../../programs/layout';
import { Buffer } from 'buffer';
import { convertInvokeCpiWithReadOnlyToInvoke } from '../../utils';

type Deserializer<T> = (data: Buffer, tx: ParsedTransactionWithMeta) => T;

Expand Down Expand Up @@ -221,6 +226,9 @@ export function parseLightTransaction(
const discriminatorStr = bs58.encode(discriminator);
const invokeDiscriminatorStr = bs58.encode(INVOKE_DISCRIMINATOR);
const invokeCpiDiscriminatorStr = bs58.encode(INVOKE_CPI_DISCRIMINATOR);
const invokeCpiWithReadOnlyDiscriminatorStr = bs58.encode(
INVOKE_CPI_WITH_READ_ONLY_DISCRIMINATOR,
);
if (discriminatorStr === invokeDiscriminatorStr) {
invokeData = decodeInstructionDataInvoke(Buffer.from(data));
foundSystemInstruction = true;
Expand All @@ -231,6 +239,14 @@ export function parseLightTransaction(
foundSystemInstruction = true;
break;
}
if (discriminatorStr == invokeCpiWithReadOnlyDiscriminatorStr) {
const decoded = decodeInstructionDataInvokeCpiWithReadOnly(
Buffer.from(data),
);
invokeData = convertInvokeCpiWithReadOnlyToInvoke(decoded);
foundSystemInstruction = true;
break;
}
}
if (!foundSystemInstruction) return null;

Expand Down
84 changes: 83 additions & 1 deletion js/stateless.js/src/utils/conversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ import { Buffer } from 'buffer';
import { bn, createBN254 } from '../state/BN254';
import { FIELD_SIZE } from '../constants';
import { keccak_256 } from '@noble/hashes/sha3';
import { Keypair } from '@solana/web3.js';
import { Keypair, PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import camelcaseKeys from 'camelcase-keys';
import {
InstructionDataInvoke,
PackedCompressedAccountWithMerkleContext,
CompressedAccount,
OutputCompressedAccountWithPackedContext,
PackedMerkleContext,
QueueIndex,
} from '../state/types';
import { NewAddressParamsPacked } from './address';

export function byteArrayToKeypair(byteArray: number[]): Keypair {
return Keypair.fromSecretKey(Uint8Array.from(byteArray));
Expand Down Expand Up @@ -96,3 +105,76 @@ export function pushUniqueItems<T>(items: T[], map: T[]): void {
}
});
}

export function convertInvokeCpiWithReadOnlyToInvoke(
data: any,
): InstructionDataInvoke {
const proof = data.proof
? {
a: data.proof.a,
b: data.proof.b,
c: data.proof.c,
}
: null;

// Convert new address params to NewAddressParamsPacked format
const newAddressParams: NewAddressParamsPacked[] =
data.new_address_params.map((params: any) => ({
seed: params.seed,
addressMerkleTreeRootIndex: params.address_merkle_tree_root_index,
addressMerkleTreeAccountIndex:
params.address_merkle_tree_account_index,
addressQueueAccountIndex: params.address_queue_account_index,
}));

// Convert input_compressed_accounts to PackedCompressedAccountWithMerkleContext format
const inputCompressedAccountsWithMerkleContext: PackedCompressedAccountWithMerkleContext[] =
data.input_compressed_accounts.map((account: any) => {
const compressedAccount: CompressedAccount = {
owner: new PublicKey(Buffer.alloc(32)),
lamports: account.lamports,
address: account.address,
data: null,
};

const merkleContext: PackedMerkleContext = {
merkleTreePubkeyIndex:
account.packedMerkleContext.merkle_tree_pubkey_index,
nullifierQueuePubkeyIndex:
account.packedMerkleContext.queue_pubkey_index,
leafIndex: account.packedMerkleContext.leaf_index,
queueIndex: account.packedMerkleContext.prove_by_index
? ({ queueId: 0, index: 0 } as QueueIndex)
: null,
};

return {
compressedAccount,
merkleContext,
rootIndex: account.root_index,
readOnly: false,
};
});

// Convert output_compressed_accounts to OutputCompressedAccountWithPackedContext format
const outputCompressedAccounts: OutputCompressedAccountWithPackedContext[] =
data.output_compressed_accounts.map((account: any) => ({
compressedAccount: {
owner: account.compressedAccount.owner,
lamports: account.compressedAccount.lamports,
address: account.compressedAccount.address,
data: account.compressedAccount.data,
},
merkleTreeIndex: account.merkleTreeIndex,
}));

return {
proof,
inputCompressedAccountsWithMerkleContext,
outputCompressedAccounts,
relayFee: null,
newAddressParams,
compressOrDecompressLamports: data.compress_or_decompress_lamports,
isCompress: data.is_compress,
};
}
Loading