-
Notifications
You must be signed in to change notification settings - Fork 5
Add client library guide back to compressed PDAs #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This reverts commit ca7ebb8.
bc62971 to
e8c8a2d
Compare
WalkthroughAdds a new, comprehensive client-library README for zk-compression covering TypeScript and Rust usage: installation, RPC setup, Merkle-tree concepts (address/state/queue), address derivation, validity proofs, account packing, instruction construction (Create/Update/Close/Reinit/Burn), and end-to-end transaction examples. Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes
Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
zk-compression-docs/compressed-pdas/client-library/README.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
zk-compression-docs/**/*.md
⚙️ CodeRabbit configuration file
zk-compression-docs/**/*.md: When reviewing documentation changes:
- Verify that all source code references in the documentation exist and are accurate
- Check CLAUDE.md to ensure the page-to-source-code mapping is updated if new pages are added
- Confirm that code examples match the actual implementation in the linked source files
- Validate that GitHub URLs in the documentation tree are correct and accessible
Files:
zk-compression-docs/compressed-pdas/client-library/README.md
🪛 LanguageTool
zk-compression-docs/compressed-pdas/client-library/README.md
[grammar] ~112-~112: This phrase is duplicated. You should probably use “Start a” only once.
Context: ...t" %} bash light test-validator Start a start a single-node Solana cluster, an RPC node...
(PHRASE_REPETITION)
[uncategorized] ~128-~128: Loose punctuation mark.
Context: ...t-client`](https://docs.rs/light-client): The RPC client that provides the ZK Com...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~129-~129: Loose punctuation mark.
Context: ...light-sdk: Program-side abstractions (macros, wrap...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~220-~220: Possible missing comma found.
Context: ...ss tree to derive and store the account address and * a state tree to store the compres...
(AI_HYDRA_LEO_MISSING_COMMA)
[typographical] ~286-~286: It appears that a comma is missing.
Context: ...blic key and other metadata. With these methods you select a random state tree to store...
(DURING_THAT_TIME_COMMA)
[uncategorized] ~305-~305: Loose punctuation mark.
Context: ...nfo contains. * tree: Merkle tree account pubkey * queue: Q...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~309-~309: Loose punctuation mark.
Context: ...erts values into the queue. * treeType: Automatically set based on which tree s...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~310-~310: Loose punctuation mark.
Context: ...election method you used. * cpiContext: Optional CPI context account for batche...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~414-~414: Loose punctuation mark.
Context: ...s these parameters**: * &[b"my-seed"]: Predefined inputs, such as strings, num...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~415-~415: Loose punctuation mark.
Context: ...t addresses. * &address_tree_info.tree: Specify the tree pubkey to ensure an ad...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~416-~416: Loose punctuation mark.
Context: ...es from identical seeds. * &program_id: Specify the program owner pubkey. {% en...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~461-~461: Loose punctuation mark.
Context: ... The RPC returns**: * compressedProof: The proof that the address does not exi...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~462-~462: Loose punctuation mark.
Context: ...n your instruction data. * rootIndices: An array with root index from the valid...
(UNLIKELY_OPENING_PUNCTUATION)
[typographical] ~463-~463: Usually, there’s no comma before “when”.
Context: ...you do not reference an existing account, when you create a compressed account. {% end...
(IF_NO_COMMA)
[uncategorized] ~491-~491: Loose punctuation mark.
Context: ... The RPC returns**: * compressedProof: The proof that the account hash exists ...
(UNLIKELY_OPENING_PUNCTUATION)
[typographical] ~525-~525: Usually, there’s no comma before “when”.
Context: ...you do not reference an existing account, when you create a compressed account. {% end...
(IF_NO_COMMA)
[typographical] ~611-~611: It appears that a comma is missing.
Context: ...mple create-and-update proof** In this example we generate one proof for the update of...
(DURING_THAT_TIME_COMMA)
[uncategorized] ~635-~635: Loose punctuation mark.
Context: ... The RPC returns:** * compressedProof: A single combined proof that verifies b...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~661-~661: The preposition ‘of’ seems more likely in this position.
Context: ...ddressWithTree]to prove non-existence in address trees. **2. The RPC returnsV...
(AI_HYDRA_LEO_REPLACE_IN_OF)
[uncategorized] ~665-~665: Loose punctuation mark.
Context: ...idityProofWithContextwith** *proof`: A single combined proof, passed to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~679-~679: Possible missing comma found.
Context: ... Pack Accounts To optimize instruction data we pack accounts into an array: * Ever...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~697-~697: Loose punctuation mark.
Context: ... account sections: 1. preAccounts: Program-specific accounts like signers ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~698-~698: Loose punctuation mark.
Context: ...rs or fee payer. 2. systemAccounts: [Light System accounts](https://www.zkc...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~857-~857: Loose punctuation mark.
Context: ...o three sections: 1. pre_accounts: Program-specific accounts (signers, fee...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1009-~1009: Possible missing comma found.
Context: ...read directly. The program hashes this data and the Light System Program verifies t...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1038-~1038: Loose punctuation mark.
Context: ... from Step 5: * packedAddressTreeInfo: Index to the address tree account used ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1113-~1113: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1150-~1150: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1187-~1187: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1240-~1240: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1246-~1246: Loose punctuation mark.
Context: ...data from Step 5: * address_tree_info: Index to the address tree account used ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1310-~1310: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1372-~1372: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1378-~1378: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1432-~1432: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1438-~1438: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1492-~1492: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1498-~1498: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1582-~1582: Possible missing comma found.
Context: ... .reinitAccount(). No account data is passed since reinit creates default-initialize...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1674-~1674: Possible missing comma found.
Context: ... .reinitAccount(). No account data is passed since reinit creates default-initialize...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1827-~1827: Possible missing comma found.
Context: ...uilding programs to create, or interact with compressed accounts. {% content-ref ur...
(AI_HYDRA_LEO_MISSING_COMMA)
🪛 markdownlint-cli2 (0.18.1)
zk-compression-docs/compressed-pdas/client-library/README.md
41-41: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
57-57: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
62-62: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
66-66: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
71-71: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
75-75: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
80-80: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
84-84: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
97-97: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
99-99: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
103-103: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
105-105: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
109-109: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
122-122: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
143-143: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
153-153: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
157-157: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
166-166: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
170-170: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
216-216: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
236-236: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
240-240: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
246-246: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
250-250: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
260-260: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
263-263: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
269-269: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
272-272: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
321-321: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
338-338: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
344-344: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
360-360: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
365-365: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
385-385: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
393-393: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
399-399: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
407-407: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
429-429: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
446-446: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
451-451: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
472-472: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
481-481: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
501-501: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
513-513: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
534-534: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
545-545: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
589-589: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
589-589: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
589-589: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
602-602: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
602-602: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
602-602: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
603-603: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
603-603: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
603-603: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
609-609: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
616-616: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
625-625: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
641-641: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
655-655: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
677-677: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
689-689: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
703-703: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
744-744: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
755-755: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
762-762: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
768-768: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
781-781: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
788-788: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
805-805: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
808-808: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
815-815: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
828-828: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
831-831: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
847-847: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
847-847: Multiple headings with the same content
(MD024, no-duplicate-heading)
863-863: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
877-877: Multiple headings with the same content
(MD024, no-duplicate-heading)
882-882: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
885-885: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
900-900: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
902-902: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
915-915: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
920-920: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
934-934: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
939-939: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
968-968: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
971-971: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
979-979: Multiple headings with the same content
(MD024, no-duplicate-heading)
984-984: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
986-986: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1002-1002: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1017-1017: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1027-1027: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1030-1030: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1034-1034: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1041-1041: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1049-1049: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1064-1064: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1067-1067: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1071-1071: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1080-1080: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1088-1088: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1102-1102: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1105-1105: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1109-1109: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1118-1118: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1126-1126: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1139-1139: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1142-1142: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1146-1146: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1155-1155: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1163-1163: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1176-1176: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1179-1179: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1183-1183: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1192-1192: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1206-1206: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1216-1216: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1222-1222: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1233-1233: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1238-1238: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1242-1242: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1249-1249: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1259-1259: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1278-1278: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1284-1284: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1303-1303: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1308-1308: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1312-1312: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1321-1321: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1331-1331: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1345-1345: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1351-1351: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1365-1365: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1370-1370: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1374-1374: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1383-1383: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1393-1393: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1406-1406: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1412-1412: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1425-1425: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1430-1430: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1434-1434: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1443-1443: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1453-1453: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1466-1466: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1472-1472: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1485-1485: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1490-1490: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1494-1494: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1503-1503: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1514-1514: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1523-1523: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1531-1531: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1539-1539: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1547-1547: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1555-1555: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1563-1563: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1571-1571: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1579-1579: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1587-1587: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1595-1595: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1607-1607: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1617-1617: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1625-1625: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1635-1635: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1643-1643: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1653-1653: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1661-1661: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1671-1671: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1679-1679: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1689-1689: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1713-1713: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1718-1718: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1727-1727: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1733-1733: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1736-1736: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1750-1750: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1752-1752: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1755-1755: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
1758-1758: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1760-1760: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1763-1763: Ordered list item prefix
Expected: 1; Actual: 3; Style: 1/1/1
(MD029, ol-prefix)
1766-1766: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1768-1768: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1779-1779: Bare URL used
(MD034, no-bare-urls)
1783-1783: Bare URL used
(MD034, no-bare-urls)
1787-1787: Bare URL used
(MD034, no-bare-urls)
1791-1791: Bare URL used
(MD034, no-bare-urls)
1795-1795: Bare URL used
(MD034, no-bare-urls)
1803-1803: Bare URL used
(MD034, no-bare-urls)
1807-1807: Bare URL used
(MD034, no-bare-urls)
1811-1811: Bare URL used
(MD034, no-bare-urls)
1815-1815: Bare URL used
(MD034, no-bare-urls)
1819-1819: Bare URL used
(MD034, no-bare-urls)
1831-1831: Files should end with a single newline character
(MD047, single-trailing-newline)
🔇 Additional comments (3)
zk-compression-docs/compressed-pdas/client-library/README.md (3)
1779-1820: GitHub code example URLs verified—all accessible.The documentation references are sound. The
add-basic-operations-examplesbranch exists in the Lightprotocol/program-examples repository, and all referenced files are present on that branch. The earlier 302 responses were standard HTTP redirects from GitHub's web interface, not errors. Both the TypeScript (anchor) and Rust (native) paths resolve correctly.
1-8: No action needed—CLAUDE.md has already been updated with the Client Library mappings.The new documentation page at
zk-compression-docs/compressed-pdas/client-library/README.mdis already properly mapped in CLAUDE.md (lines 127–140) with comprehensive cross-references for TypeScript and Rust clients, including documentation links, source repositories, and example implementations.
237-277: Verify tree configuration methods against external SDK repositories per CLAUDE.md mappings.This documentation repository doesn't contain SDK source code—methods must be verified in external light-protocol repositories referenced in CLAUDE.md:
- TypeScript methods (
getAddressTreeInfoV2,getStateTreeInfos,selectStateTreeInfo): Verify in https://github.com/Lightprotocol/light-protocol/blob/main/js/stateless.js/src/rpc.ts- Rust methods (
get_address_tree_v2,get_random_state_tree_info): Verify in https://github.com/Lightprotocol/light-protocol/tree/main/sdk-libs/client/src/rpcConfirm these methods exist and match the documented signatures in V1/V2 tree variants.
| --- | ||
| title: Client Library | ||
| description: >- | ||
| Overview to Rust and Typescript client guides. Guides include step-by-step | ||
| implementation and full code examples. | ||
| hidden: true | ||
| --- | ||
|
|
||
| # Overview | ||
|
|
||
| Use this guide to build a Typescript or Rust client. Here is the complete flow: | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| <figure><picture><source srcset="../../.gitbook/assets/client-create (1).png" media="(prefers-color-scheme: dark)"><img src="../../.gitbook/assets/client-create.png" alt=""></picture><figcaption></figcaption></figure> | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update" %} | ||
| <figure><picture><source srcset="../../.gitbook/assets/client-update (1).png" media="(prefers-color-scheme: dark)"><img src="../../.gitbook/assets/client-update.png" alt=""></picture><figcaption></figcaption></figure> | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Close" %} | ||
| <figure><picture><source srcset="../../.gitbook/assets/client-close (1).png" media="(prefers-color-scheme: dark)"><img src="../../.gitbook/assets/client-close.png" alt=""></picture><figcaption></figcaption></figure> | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Reinitialize" %} | ||
| <figure><picture><source srcset="../../.gitbook/assets/client-reinit (1).png" media="(prefers-color-scheme: dark)"><img src="../../.gitbook/assets/client-reinit.png" alt=""></picture><figcaption></figcaption></figure> | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Burn" %} | ||
| <figure><picture><source srcset="../../.gitbook/assets/client-burn (1).png" media="(prefers-color-scheme: dark)"><img src="../../.gitbook/assets/client-burn.png" alt=""></picture><figcaption></figcaption></figure> | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| {% hint style="info" %} | ||
| Ask anything via [](https://deepwiki.com/Lightprotocol/light-protocol/3.1-javascripttypescript-sdks). | ||
| {% endhint %} | ||
|
|
||
| {% stepper %} | ||
| {% step %} | ||
| ## Installation and Setup | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| The Typescript SDK consists of two packages: | ||
|
|
||
| 1. [@lightprotocol/stateless.js](https://lightprotocol.github.io/light-protocol/stateless.js/index.html)is the core RPC client that provides the ZK Compression RPC interface to query and build transactions that create or interact with compressed accounts on Solana. | ||
| 2. [@lightprotocol/compressed-token](https://lightprotocol.github.io/light-protocol/compressed-token/index.html) uses the stateless.js RPC interface to build transactions with compressed tokens. | ||
|
|
||
| {% hint style="info" %} | ||
| Use the [API documentation](https://lightprotocol.github.io/light-protocol/) to look up specific function signatures, parameters, and return types. | ||
| {% endhint %} | ||
|
|
||
| **1. Installation** | ||
| {% tabs %} | ||
| {% tab title="npm" %} | ||
| ```bash | ||
| npm install --save \ | ||
| @lightprotocol/stateless.js@0.22.1-alpha.1 \ | ||
| @lightprotocol/compressed-token@0.22.1-alpha.1 \ | ||
| @solana/web3.js | ||
| ``` | ||
| {% endtab %} | ||
|
|
||
| {% tab title="yarn" %} | ||
| ```bash | ||
| yarn add \ | ||
| @lightprotocol/stateless.js@0.22.1-alpha.1 \ | ||
| @lightprotocol/compressed-token@0.22.1-alpha.1 \ | ||
| @solana/web3.js | ||
| ``` | ||
| {% endtab %} | ||
|
|
||
| {% tab title="pnpm" %} | ||
| ```bash | ||
| pnpm add \ | ||
| @lightprotocol/stateless.js@0.22.1-alpha.1 \ | ||
| @lightprotocol/compressed-token@0.22.1-alpha.1 \ | ||
| @solana/web3.js | ||
| ``` | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **2. Create an RPC Connection** | ||
|
|
||
| {% hint style="success" %} | ||
| `Rpc` and `TestRpc` implement the same `CompressionApiInterface` for consistent usage across `TestRpc`, local test validator, and public Solana networks. | ||
| {% endhint %} | ||
|
|
||
| **Use `Rpc` for test-validator, devnet and mainnet** | ||
|
|
||
| * `Rpc` is a thin wrapper extending Solana's web3.js `Connection` class with compression-related endpoints. | ||
| * Connects to Photon indexer to query compressed accounts and prover service to generate validity proofs. | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Mainnet" %} | ||
| ```typescript | ||
| const rpc = createRpc('https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY'); | ||
| ``` | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Devnet" %} | ||
| ```typescript | ||
| const rpc = createRpc('https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY'); | ||
| ``` | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Localnet" %} | ||
| ```bash | ||
| light test-validator | ||
| ``` | ||
|
|
||
| Start a start a single-node Solana cluster, an RPC node, and a prover node at ports 8899, 8784, and 3001. | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **For unit tests, use `TestRpc`** to start a mock RPC instance that parses events and builds Merkle trees on-demand without persisting state. | ||
|
|
||
| ```typescript | ||
| const lightWasm: LightWasm = await WasmFactory.getInstance(); | ||
| const testRpc = await TestRpc.create(lightWasm); | ||
| ``` | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| Rust offers one client library, and a separate SDK for program-side development: | ||
|
|
||
| 1. [`light-client`](https://docs.rs/light-client): The RPC client that provides the ZK Compression RPC interface to query and build transactions for **compressed accounts and tokens** on Solana. | ||
| 2. [`light-sdk`](https://docs.rs/light-sdk): Program-side abstractions (macros, wrappers, CPI interface) to create and interact with compressed accounts in Solana programs. Similar to Anchor's `Account` pattern. | ||
|
|
||
| **For devnet and mainnet, use `light-client`** | ||
|
|
||
| * Connects to Photon indexer to query compressed accounts and generate validity proofs. | ||
|
|
||
| ```toml | ||
| [dependencies] | ||
| light-client = "0.16.0" | ||
| light-sdk = "0.16.0" | ||
| ``` | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Mainnet" %} | ||
| ```rust | ||
| let config = LightClientConfig::new( | ||
| "https://api.mainnet-beta.solana.com".to_string(), | ||
| Some("https://mainnet.helius.xyz".to_string()), | ||
| Some("YOUR_API_KEY".to_string()) | ||
| ); | ||
|
|
||
| let mut client = LightClient::new(config).await?; | ||
|
|
||
| client.payer = read_keypair_file("~/.config/solana/id.json")?; | ||
| ``` | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Devnet" %} | ||
| ```rust | ||
| let config = LightClientConfig::devnet( | ||
| Some("https://devnet.helius-rpc.com".to_string()), | ||
| Some("YOUR_API_KEY".to_string()) | ||
| ); | ||
|
|
||
| let mut client = LightClient::new(config).await?; | ||
|
|
||
| client.payer = read_keypair_file("~/.config/solana/id.json")?; | ||
| ``` | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Localnet" %} | ||
| ```rust | ||
| let config = LightClientConfig::local(); | ||
|
|
||
| let mut client = LightClient::new(config).await?; | ||
|
|
||
| client.payer = read_keypair_file("~/.config/solana/id.json")?; | ||
| ``` | ||
|
|
||
| Requires running `light test-validator` locally: | ||
|
|
||
| ```bash | ||
| light test-validator | ||
| ``` | ||
|
|
||
| Starts a start a single-node Solana cluster, an RPC node, and a prover node at ports 8899, 8784, and 3001. | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **For local testing, use** [**`light-program-test`**](https://docs.rs/light-program-test). | ||
|
|
||
| * Initializes a [LiteSVM](https://github.com/LiteSVM/LiteSVM) optimized for ZK Compression with auto-funded payer and TestIndexer. Requires Light CLI for program binaries. | ||
| * Use for unit and integration tests of your program or client code. | ||
|
|
||
| ```toml | ||
| [dev-dependencies] | ||
| light-program-test = "0.16.0" | ||
| light-sdk = "0.16.0" | ||
| ``` | ||
|
|
||
| ```rust | ||
| let config = ProgramTestConfig::new_v2( | ||
| true, | ||
| Some(vec![("program_create", program_create::ID)]) | ||
| ); | ||
| let mut rpc = LightProgramTest::new(config).await.unwrap(); | ||
| let payer = rpc.get_payer().insecure_clone(); | ||
| ``` | ||
|
|
||
| {% hint style="success" %} | ||
| `LightClient` and `LightProgramTest` implement the same [`Rpc`](https://docs.rs/light-client/latest/light_client/rpc/trait.Rpc.html) and [`Indexer`](https://docs.rs/light-client/latest/light_client/indexer/trait.Indexer.html) traits for consistent usage across `light-program-test`, local test validator, and public Solana networks. | ||
| {% endhint %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endstep %} | ||
|
|
||
| {% step %} | ||
| ## Tree Configuration | ||
|
|
||
| Your client must fetch metadata of two Merkle trees: | ||
|
|
||
| * an address tree to derive and store the account address and | ||
| * a state tree to store the compressed account hash. | ||
|
|
||
| {% hint style="success" %} | ||
| The protocol maintains Merkle trees. You don't need to initialize custom trees. Find the [addresses for Merkle trees here](https://www.zkcompression.com/resources/addresses-and-urls). | ||
| {% endhint %} | ||
|
|
||
| {% hint style="info" %} | ||
| V2 is currently on Devnet. Use to optimize compute unit consumption by up to 70%. | ||
| {% endhint %} | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| {% tabs %} | ||
| {% tab title="V1 Trees" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const addressTree = getDefaultAddressTreeInfo(); | ||
| const stateTreeInfos = await rpc.getStateTreeInfos(); | ||
| const outputStateTree = selectStateTreeInfo(stateTreeInfos); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="V2 Trees" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const addressTree = await rpc.getAddressTreeInfoV2(); | ||
| const stateTreeInfos = await rpc.getStateTreeInfos(); | ||
| const outputStateTree = selectStateTreeInfo(stateTreeInfos); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| {% tabs %} | ||
| {% tab title="V1 Trees" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let address_tree_info = rpc.get_address_tree_v1(); | ||
| let output_state_tree_info = rpc.get_random_state_tree_info().unwrap(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="V2 Trees" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let address_tree_info = rpc.get_address_tree_v2(); | ||
| let output_state_tree_info = rpc.get_random_state_tree_info().unwrap(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **Address Tree methods** return `TreeInfo` of address trees with the public key and other metadata for the address tree. | ||
|
|
||
| Use the address tree `TreeInfo`: | ||
|
|
||
| 1. In Step 3 to derive the address for the compressed account. | ||
| 2. In Step 4 for `getValidityProofV0()` to prove the address does not exist yet, if you create compressed accounts with address. | ||
|
|
||
| **State Tree methods** return an array of `TreeInfo` objects of state trees with public key and other metadata. With these methods you select a random state tree to store the compressed account hash. | ||
|
|
||
| Use the state tree `TreeInfo`: | ||
|
|
||
| 1. In Step 4 for `getValidityProofV0()` to prove the account hash exists in the state tree, if you update/close/reinit/burn a compressed account. | ||
| 2. In Step 5 for packing accounts to optimize instruction data. | ||
|
|
||
| * Assigns indices to accounts instead of repeating full pubkeys | ||
|
|
||
| {% hint style="info" %} | ||
| - Account hashes can move to different state trees after each state transition. | ||
| - Since trees fill up over time, your programs must be able to handle accounts from different state trees within the same transaction. | ||
| - **Best practice**: minimize the number of different trees per transaction. | ||
| {% endhint %} | ||
|
|
||
| <details> | ||
|
|
||
| <summary>Expand to learn what pubkeys and other metadata of a Merkle tree <code>TreeInfo</code> contains.</summary> | ||
|
|
||
| * `tree`: Merkle tree account pubkey | ||
| * `queue`: Queue account pubkey of queue associated with a Merkle tree | ||
| * Buffers updates of compressed accounts before they are added to the Merkle tree. | ||
| * Clients and programs do not interact with the queue. The Light System Program inserts values into the queue. | ||
| * `treeType`: Automatically set based on which tree selection method you used. | ||
| * `cpiContext`: Optional CPI context account for batched operations across multiple programs (may be null, currently on devnet) | ||
| * Allows a single zero-knowledge proof to verify compressed accounts from different programs in one instruction | ||
| * Reduces instruction data size and compute unit costs when multiple programs interact with compressed accounts | ||
| * `nextTreeInfo`: Next tree to use when current tree reaches \~95% capacity (may be null). | ||
| * The SDK automatically switches to next tree when present. Developers don't need to handle tree rollovers manually. | ||
| * The protocol creates new trees, once existing trees fill up. | ||
|
|
||
| </details> | ||
| {% endstep %} | ||
|
|
||
| {% step %} | ||
| ## Derive Address | ||
|
|
||
| Derive a persistent address as a unique identifier for your compressed account, similar to [program-derived addresses (PDAs)](https://solana.com/docs/core/pda). | ||
|
|
||
| * Use the derivation method that matches your address tree type from the previous step (V1 or V2). | ||
| * Like PDAs, compressed account addresses don't belong to a private key; rather, they're derived from the program that owns them. | ||
| * The key difference to PDAs is that compressed accounts require an **address tree** parameter. | ||
|
|
||
| {% hint style="info" %} | ||
| V2 is currently on Devnet. Use to optimize compute unit consumption by up to 70%. | ||
| {% endhint %} | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| {% tabs %} | ||
| {% tab title="V1 Address Trees" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const seed = deriveAddressSeed( | ||
| [Buffer.from('my-seed')], | ||
| programId | ||
| ); | ||
| const address = deriveAddress(seed, addressTree.tree); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Derive the seed**: | ||
|
|
||
| * Seeds are predefined inputs, such as strings, numbers or other account addresses. | ||
| * Specify `programId` to combine with your seeds | ||
|
|
||
| **2. Then, derive the address**: | ||
|
|
||
| * Pass the derived 32-byte `seed` from the first step | ||
| * Specify `addressTree.tree` pubkey | ||
| {% endtab %} | ||
|
|
||
| {% tab title="V2 Address Trees" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const seed = deriveAddressSeedV2( | ||
| [Buffer.from('my-seed')] | ||
| ); | ||
| const address = deriveAddressV2(seed, addressTree.tree, programId); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Derive the seed**: | ||
|
|
||
| * Seeds are predefined inputs, such as strings, numbers or other account addresses. | ||
|
|
||
| **2. Then, derive the address**: | ||
|
|
||
| * Pass the derived 32-byte `seed` from the first step. | ||
| * Specify `addressTree.tree` pubkey to ensure an address is unique to an address tree. Different trees produce different addresses from identical seeds. | ||
| * Specify `programId` in the address derivation. V2 includes it here instead of the first step. | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| {% tabs %} | ||
| {% tab title="V1 Address Trees" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use light_sdk::address::v1::derive_address; | ||
|
|
||
| let (address, _) = derive_address( | ||
| &[b"my-seed"], | ||
| &address_tree_info.tree, | ||
| &program_id, | ||
| ); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="V2 Address Trees" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use light_sdk::address::v2::derive_address; | ||
|
|
||
| let (address, _) = derive_address( | ||
| &[b"my-seed"], | ||
| &address_tree_info.tree, | ||
| &program_id, | ||
| ); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **Pass these parameters**: | ||
|
|
||
| * `&[b"my-seed"]`: Predefined inputs, such as strings, numbers or other account addresses. | ||
| * `&address_tree_info.tree`: Specify the tree pubkey to ensure an address is unique to this address tree. Different trees produce different addresses from identical seeds. | ||
| * `&program_id`: Specify the program owner pubkey. | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| {% hint style="info" %} | ||
| Use the same address tree for both address derivation and all subsequent operations: | ||
|
|
||
| * To create a compressed account, pass the address to the validity proof, to prove the address does not exist yet. | ||
| * To update/close, use the address to fetch the current account with `getCompressedAccount(address)` / `get_compressed_account(address)`. | ||
| {% endhint %} | ||
| {% endstep %} | ||
|
|
||
| {% step %} | ||
| ## Validity Proof | ||
|
|
||
| Fetch a validity proof from your RPC provider that supports ZK Compression (Helius, Triton, ...). The proof type depends on the operation: | ||
|
|
||
| * To create a compressed account, you must prove the **address doesn't already exist** in the address tree. | ||
| * To update or close a compressed account, you must **prove its account hash exists** in a state tree. | ||
| * You can **combine multiple addresses and hashes in one proof** to optimize compute cost and instruction data. | ||
|
|
||
| {% hint style="info" %} | ||
| [Here's a full guide](https://www.zkcompression.com/resources/json-rpc-methods/getvalidityproof) to the `getValidityProofV0()` / `get_validity_proof()` method. | ||
| {% endhint %} | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const proof = await rpc.getValidityProofV0( | ||
| [], | ||
| [{ address: bn(address.toBytes()), tree: addressTree.tree, queue: addressTree.queue }] | ||
| ); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Pass these parameters**: | ||
|
|
||
| * Leave (`[]`) empty to create compressed accounts, since no compressed account exists yet to reference. | ||
| * Specify the derived address with its `tree` and `queue` pubkeys from the address tree `TreeInfo`. | ||
|
|
||
| **2. The RPC returns**: | ||
|
|
||
| * `compressedProof`: The proof that the address does not exist in the address tree, passed to the program in your instruction data. | ||
| * `rootIndices`: An array with root index from the validity proof for the address tree. | ||
| * Empty `leafIndices` array, since you do not reference an existing account, when you create a compressed account. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update, Close, Reinit, Burn" %} | ||
| {% hint style="info" %} | ||
| These operations proof that the account hash exists in the state tree. The difference is in your program's instruction handler. | ||
| {% endhint %} | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const hash = compressedAccount.hash; | ||
| const tree = compressedAccount.treeInfo.tree; | ||
| const queue = compressedAccount.treeInfo.queue; | ||
|
|
||
| const proof = await rpc.getValidityProofV0( | ||
| [{ hash, tree, queue }], | ||
| [] | ||
| ); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Pass these parameters**: | ||
|
|
||
| * Specify the account `hash` along with `tree` and `queue` pubkeys from the compressed account's `TreeInfo`. | ||
| * (`[]`) remains empty, since the proof verifies the account hash exists in a state tree, not that the address doesn't exist in an address tree. | ||
|
|
||
| **2. The RPC returns**: | ||
|
|
||
| * `compressedProof`: The proof that the account hash exists in the state tree, passed to the program in your instruction data. | ||
| * `rootIndices` and `leafIndices` arrays with proof metadata to pack accounts (Step 5). | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let rpc_result = rpc | ||
| .get_validity_proof( | ||
| vec![], | ||
| vec![AddressWithTree { | ||
| address: *address, | ||
| tree: address_tree_info.tree, | ||
| }], | ||
| None, | ||
| ) | ||
| .await? | ||
| .value; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Pass these parameters**: | ||
|
|
||
| * Leave (`vec![]`) empty to create compressed accounts, since no compressed account exists yet to reference. | ||
| * Specify the new address with `tree` pubkey from the address tree `TreeInfo` in `vec![AddressWithTree]`. Rust does not have a queue field, different from Typescript. | ||
|
|
||
| **2. The RPC returns `ValidityProofWithContext`**: | ||
|
|
||
| * `proof` to prove that the address does not exist in the address tree, passed to the program in your instruction data. | ||
| * `addresses` with the public key and metadata of the address tree to pack accounts (Step 5). | ||
| * An empty `accounts` field, since you do not reference an existing account, when you create a compressed account. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update, Close, Reinit, Burn" %} | ||
| {% hint style="info" %} | ||
| These operations proof that the account hash exists in the state tree. The difference is in your program's instruction handler. | ||
| {% endhint %} | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let hash = compressed_account.hash; | ||
|
|
||
| let rpc_result = rpc | ||
| .get_validity_proof( | ||
| vec![hash], | ||
| vec![], | ||
| None, | ||
| ) | ||
| .await? | ||
| .value; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Pass these parameters**: | ||
|
|
||
| * Specify the `hash` extracted from the compressed account in `vec![hash]` to prove its existence in the state tree. | ||
| * (`vec![]`) remains empty, since the proof verifies the account hash exists in a state tree, not that the address doesn't exist in an address tree. | ||
|
|
||
| **2. The RPC returns `ValidityProofWithContext`**: | ||
|
|
||
| * `proof` with the proof that the account hash exists in the state tree, passed to the program in your instruction data. | ||
| * `accounts` with the public key and metadata of the state tree to pack accounts (Step 5). | ||
| * An empty `addresses` field (only needed when creating an address). | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| ### Optimize with Single Combined Proofs | ||
|
|
||
| {% hint style="info" %} | ||
| **Advantages of combined proofs**: | ||
|
|
||
| * You only add one validity proof with 128 bytes in size instead of two to your instruction data. | ||
| * Reduction of compute unit consumption by at least 100k CU, since combined proofs are verified in a single CPI by the Light System Program. | ||
| {% endhint %} | ||
|
|
||
| The specific combinations and maximums to combine proofs depend on the circuit version (v1 or v2) and the proof type. | ||
|
|
||
| * Combine multiple hashes **or** multiple addresses in a single proof, or | ||
| * multiple hashes **and** addresses in a single combined proof. | ||
|
|
||
| {% tabs %} | ||
| {% tab title="V1 Circuits" %} | ||
| V1 circuits can prove in a single proof | ||
|
|
||
| * 1, 2, 3, 4, or 8 hashes, | ||
| * 1, 2, 3, 4, or 8 addresses, or | ||
| * multiple hashes or addresses in any combination of the below. | ||
|
|
||
| | **Single Combined Proofs** | Any combination of | | ||
| | -------------------------- | :----------------: | | ||
| | Hashes | 1, 2, 3, 4, 8 | | ||
| | Addresses | 1, 2, 4, 8 | | ||
| {% endtab %} | ||
|
|
||
| {% tab title="V2 Circuits" %} | ||
| V2 circuits can prove in a single proof | ||
|
|
||
| * 1 to 20 hashes, | ||
| * 1 to 32 addresses, or | ||
| * multiple hashes or addresses in any combination of the below. | ||
|
|
||
| | **Single Combined Proofs** | Any combination of | | ||
| | -------------------------- | :----------------: | | ||
| | Hashes | 1 to 4 | | ||
| | Addresses | 1 to 4 | | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| {% hint style="info" %} | ||
| The combinations and maximums are determined by the available circuit verifying keys. Different proof sizes require different circuits optimized for that specific combination. View the [source code here](https://github.com/Lightprotocol/light-protocol/tree/871215642b4b5b69d2bcd7eca22542346d0e2cfa/program-libs/verifier/src/verifying_keys). | ||
| {% endhint %} | ||
|
|
||
| **Example create-and-update proof** | ||
|
|
||
| In this example we generate one proof for the update of an existing account, and the creation of a new account. | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const hash = compressedAccount.hash; | ||
| const tree = compressedAccount.treeInfo.tree; | ||
| const queue = compressedAccount.treeInfo.queue; | ||
|
|
||
| const proof = await rpc.getValidityProofV0( | ||
| [{ hash, tree, queue }], | ||
| [{ address: bn(address.toBytes()), tree: addressTree.tree, queue: addressTree.queue }] | ||
| ); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Pass these parameters**: | ||
|
|
||
| * Specify one or more account `hash` values along with `tree` and `queue` pubkeys from the compressed account's `TreeInfo`. | ||
| * Specify one or more derived addresses with `tree` and `queue` pubkeys from the address tree `TreeInfo`. | ||
|
|
||
| **2. The RPC returns:** | ||
|
|
||
| * `compressedProof`: A single combined proof that verifies both the account hash exists in the state tree and the address does not exist in the address tree, passed to the program in your instruction data. | ||
| * `rootIndices` and `leafIndices` arrays with proof metadata to build `PackedAddressTreeInfo` and `PackedStateTreeInfo` (Step 5). | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let hash = compressed_account.hash; | ||
|
|
||
| let rpc_result = rpc | ||
| .get_validity_proof( | ||
| vec![hash], | ||
| vec![AddressWithTree { | ||
| address: *address, | ||
| tree: address_tree_info.tree, | ||
| }], | ||
| None, | ||
| ) | ||
| .await? | ||
| .value; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Pass these parameters**: | ||
|
|
||
| * Specify one or more `hash` values extracted from compressed accounts in `vec![hash]` to prove existence in the state trees. | ||
| * Specify one or more addresses with `tree` pubkey from the address tree `TreeInfo` in `vec![AddressWithTree]` to prove non-existence in address trees. | ||
|
|
||
| **2. The RPC returns `ValidityProofWithContext` with** | ||
|
|
||
| * `proof`: A single combined proof, passed to the program in your instruction data. | ||
| * `addresses` with the public key and metadata of the address tree to pack accounts (Step 5). | ||
| * `accounts` with the public key and metadata of the state tree to pack accounts (Step 5). | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| {% hint style="info" %} | ||
| See the full [create-and-update program example with tests](https://github.com/Lightprotocol/program-examples/tree/main/create-and-update). | ||
| {% endhint %} | ||
| {% endstep %} | ||
|
|
||
| {% step %} | ||
| ## Pack Accounts | ||
|
|
||
| To optimize instruction data we pack accounts into an array: | ||
|
|
||
| * Every packed account is assigned to an u8 index. | ||
| * Indices are included in instruction data, instead of 32 byte pubkeys. | ||
| * The indices point to the instructions accounts | ||
| * in anchor to `remainingAccounts`, and | ||
| * in native programs to the account info slice. | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| ### 1. Initialize PackedAccounts | ||
|
|
||
| ```typescript | ||
| const packedAccounts = new PackedAccounts(); | ||
| ``` | ||
|
|
||
| `PackedAccounts` creates a helper instance with three empty account sections: | ||
|
|
||
| 1. **`preAccounts`**: Program-specific accounts like signers or fee payer. | ||
| 2. **`systemAccounts`**: [Light System accounts](https://www.zkcompression.com/resources/addresses-and-urls#system-accounts) for proof verification and CPI calls to update state and address trees | ||
| 3. **`treeAccounts`**: State trees, address trees, and queue accounts from validity proof | ||
|
|
||
| **Final array structure:** | ||
|
|
||
| ``` | ||
| [preAccounts] [systemAccounts] [treeAccounts] | ||
| ↑ ↑ ↑ | ||
| Signers, Light System state trees, | ||
| fee payer accounts address trees, | ||
| queues | ||
| ``` | ||
|
|
||
| {% hint style="info" %} | ||
| * The instance maintains an internal deduplication map that assigns sequential u8 indices (0, 1, 2...) when you call `insertOrGet()`. | ||
| * If the same pubkey is inserted multiple times, it returns the cached index. | ||
| * For example, if the input state tree equals the output state tree, both return the same index. | ||
| {% endhint %} | ||
|
|
||
| ### 2. Add Light System Accounts | ||
|
|
||
| Populate the `systemAccounts` section with Light System accounts. These accounts are needed for proof verification and CPI calls to update state and address trees. | ||
|
|
||
| {% code overflow="wrap" %} | ||
|
|
||
| ```typescript | ||
| const systemAccountConfig = SystemAccountMetaConfig.new(programId); | ||
| packedAccounts.addSystemAccounts(systemAccountConfig); | ||
| ``` | ||
|
|
||
| {% endcode %} | ||
|
|
||
| 1. Pass your program ID to `SystemAccountMetaConfig.new(programId)` to configure system accounts | ||
| 2. Call `addSystemAccounts(systemAccountConfig)` - the SDK populates `systemAccounts` with Light System accounts, including the CPI signer PDA derived from your program ID | ||
|
|
||
| {% hint style="info" %} | ||
| Program-specific accounts (signers, fee payer) are passed to `.accounts()` in your instruction and are not added to `PackedAccounts`. | ||
| {% endhint %} | ||
|
|
||
| ### 3. Pack Tree Accounts from Validity Proof | ||
|
|
||
| Populate the `treeAccounts` section with tree pubkeys from the validity proof and receive u8 indices to use in instruction data. | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const addressMerkleTreePubkeyIndex = | ||
| packedAccounts.insertOrGet(addressTree); | ||
| const addressQueuePubkeyIndex = | ||
| packedAccounts.insertOrGet(addressQueue); | ||
|
|
||
| const packedAddressTreeInfo = { | ||
| rootIndex: proofRpcResult.rootIndices[0], | ||
| addressMerkleTreePubkeyIndex, // u8 index: 0 | ||
| addressQueuePubkeyIndex, // u8 index: 1 | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 1. Call `insertOrGet()` with the address tree and address queue pubkeys from `addressTree` TreeInfo | ||
|
|
||
| * Each call returns a sequential index starting from 0 (first call returns 0, second returns 1) | ||
|
|
||
| 2. Pass the `packedAddressTreeInfo` in your instruction data (Step 6) | ||
|
|
||
| {% endtab %} | ||
|
|
||
| {% tab title="Update, Close, Reinit, Burn" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const tree = compressedAccount.treeInfo.tree; | ||
| const queue = compressedAccount.treeInfo.queue; | ||
|
|
||
| const merkleTreePubkeyIndex = packedAccounts.insertOrGet(tree); | ||
| const queuePubkeyIndex = packedAccounts.insertOrGet(queue); | ||
|
|
||
| const packedInputAccounts = { | ||
| merkleTreePubkeyIndex, // u8 index: 0 | ||
| queuePubkeyIndex, // u8 index: 1 | ||
| leafIndex: proofRpcResult.leafIndices[0], | ||
| rootIndex: proofRpcResult.rootIndices[0], | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 1. Call `insertOrGet()` with the state tree and queue pubkeys from the compressed account's `compressedAccount.treeInfo` | ||
|
|
||
| * Each call returns a sequential index starting from 0 (first call returns 0, second returns 1) | ||
|
|
||
| 2. Pass the returned indices along with `leafIndex` and `rootIndex` from the validity proof in your instruction data (Step 6) | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| #### Tree Accounts by Instructions Type | ||
|
|
||
| | Instruction | Address Tree | State Tree | Nullifier Queue | Output State Tree | | ||
| | ----------------------- | ------------------------ | -------------------- | --------------- | ----------------------- | | ||
| | Create | ✓ (proves non-existence) | - | - | ✓ (stores new hash) | | ||
| | Update / Close / Reinit | - | ✓ (proves existence) | ✓ (nullifies) | ✓ (stores updated hash) | | ||
| | Burn | - | ✓ (proves existence) | ✓ (nullifies) | - | | ||
|
|
||
| ### 4. Pack Output State Tree | ||
|
|
||
| Pack the output state tree to specify where the new or updated account state will be stored. | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const outputStateTreeIndex = | ||
| packedAccounts.insertOrGet(outputStateTree); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 1. Call `insertOrGet()` with the output state tree pubkey from `outputStateTree` TreeInfo | ||
|
|
||
| * Returns the u8 index (continues sequential numbering from previous `insertOrGet()` calls) | ||
|
|
||
| 2. Pass `outputStateTreeIndex` in your instruction data (Step 6) | ||
|
|
||
| {% hint style="info" %} | ||
| * **Create**: Stores new account hash in output state tree | ||
| * **Update/Close/Reinit**: Stores updated account hash in output state tree (may be same tree as input or different) | ||
| * **Burn**: No output state tree | ||
| {% endhint %} | ||
|
|
||
| ### 5. Finalize Packed Accounts | ||
|
|
||
| Call `toAccountMetas()` to convert packed accounts into the final array for your instruction. | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const { remainingAccounts, systemStart, packedStart } = | ||
| packedAccounts.toAccountMetas(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 1. Call `toAccountMetas()` on your PackedAccounts instance | ||
| * Returns an object with three fields: | ||
| * `remainingAccounts`: `AccountMeta[]` array containing all accounts (system accounts + tree accounts) | ||
| * `systemStart`: Offset indicating where system accounts start in the array (used internally by Light System Program) | ||
| * `packedStart`: Offset indicating where tree accounts start in the array (used internally by Light System Program) | ||
| 2. You have now prepared all components needed for the next step: | ||
| * `remainingAccounts` - to pass to `.remainingAccounts()` in your Anchor instruction builder | ||
| * From Section 3: `packedAddressTreeInfo` (Create) OR `packedInputAccounts` (Update/Close/Reinit/Burn) | ||
| * From Section 4: `outputStateTreeIndex` (Create/Update/Close/Reinit only - Burn has no output state tree) | ||
|
|
||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| ### 1. Initialize PackedAccounts | ||
|
|
||
| ```rust | ||
| let mut remaining_accounts = PackedAccounts::default(); | ||
| ``` | ||
|
|
||
| Creates a PackedAccounts instance that manages account deduplication and indexing for compressed account operations. | ||
|
|
||
| The instance organizes accounts into three sections: | ||
|
|
||
| 1. **`pre_accounts`**: Program-specific accounts (signers, fee payer) | ||
| 2. **`system_accounts`**: [Light System accounts](https://www.zkcompression.com/resources/addresses-and-urls#system-accounts) for proof verification and CPI calls to update state and address trees | ||
| 3. **`tree_accounts`**: State trees, address trees, and queue accounts added dynamically via `insert_or_get()` | ||
|
|
||
| **Final array structure:** | ||
|
|
||
| ``` | ||
| [pre_accounts] [system_accounts] [tree_accounts] | ||
| ↑ ↑ ↑ | ||
| Signers, Light System state trees, | ||
| fee payer accounts address trees, | ||
| queues | ||
| ``` | ||
|
|
||
| {% hint style="info" %} | ||
| * The instance maintains an internal deduplication map that assigns sequential u8 indices (0, 1, 2...) when you call `insert_or_get()`. | ||
| * If the same pubkey is inserted multiple times, it returns the cached index. | ||
| * For example, if the input state tree equals the output state tree, both return the same index. | ||
| {% endhint %} | ||
|
|
||
| ### 2. Add Light System Accounts | ||
|
|
||
| Populate the `system_accounts` with [Light System accounts](https://www.zkcompression.com/resources/addresses-and-urls#system-accounts) needed for proof verification and CPI calls to update state and address trees. | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let config = SystemAccountMetaConfig::new(program::ID); | ||
| remaining_accounts.add_system_accounts(config)?; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 1. Pass your program ID to `SystemAccountMetaConfig::new(program_id)` to configure system accounts | ||
| 2. Call `add_system_accounts(config)?` - the SDK populates `system_accounts` with [Light System accounts](https://www.zkcompression.com/resources/addresses-and-urls#system-accounts), including the CPI signer PDA derived from your program ID. | ||
|
|
||
| ### 3. Pack Tree Accounts | ||
|
|
||
| Add tree and queue accounts to the packed accounts array and retrieve indices for the instruction data. The specific trees used depend on your operation type. | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| Add the address tree and address queue pubkeys to the accounts array and retrieve their indices. | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let packed_accounts = rpc_result.pack_tree_infos(&mut remaining_accounts); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 1. Call `pack_tree_infos()` on the RPC result from `get_validity_proof()` | ||
| * Returns `PackedTreeInfos` with `.address_trees` field | ||
| * Contains `PackedAddressTreeInfo` with indices for address tree, address queue, and root index | ||
| 2. Use `packed_accounts.address_trees[0]` in your instruction data (Step 6) | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update / Close / Reinit" %} | ||
| Add the state tree and nullifier queue pubkeys to the accounts array and retrieve their indices. | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let packed_tree_accounts = rpc_result | ||
| .pack_tree_infos(&mut remaining_accounts) | ||
| .state_trees | ||
| .unwrap(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 1. Call `pack_tree_infos()` on the RPC result and extract `.state_trees.unwrap()` | ||
| * Returns `PackedStateTreeInfos` containing: | ||
| * `packed_tree_infos`: Array with `PackedStateTreeInfo` (indices for state tree, nullifier queue, leaf index, root index) | ||
| * `output_tree_index`: u8 index for output state tree to store the compressed account hash | ||
| 2. Use both `packed_tree_accounts.packed_tree_infos[0]` and `packed_tree_accounts.output_tree_index` in your instruction data (Step 6) | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Burn" %} | ||
| Add the state tree and nullifier queue pubkeys to the accounts array and retrieve their indices. Burn permanently removes the account without creating output state. | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let packed_tree_accounts = rpc_result | ||
| .pack_tree_infos(&mut remaining_accounts) | ||
| .state_trees | ||
| .unwrap(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 1. Call `pack_tree_infos()` on the RPC result and extract `.state_trees.unwrap()` | ||
| * Returns `PackedStateTreeInfos` with `packed_tree_infos` array (indices for state tree, nullifier queue, leaf index, root index) | ||
| * No `output_tree_index` field - Burn permanently removes the account without creating output state | ||
| 2. Use `packed_tree_accounts.packed_tree_infos[0]` in your instruction data (Step 6) | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| #### Tree Accounts by Instructions Type | ||
|
|
||
| | Instruction | Address Tree | State Tree | Nullifier Queue | Output State Tree | | ||
| | ----------------------- | ------------------------ | -------------------- | --------------- | ----------------------- | | ||
| | Create | ✓ (proves non-existence) | - | - | ✓ (stores new hash) | | ||
| | Update / Close / Reinit | - | ✓ (proves existence) | ✓ (nullifies) | ✓ (stores updated hash) | | ||
| | Burn | - | ✓ (proves existence) | ✓ (nullifies) | - | | ||
|
|
||
| ### 4. Pack Output State Tree (Anchor Create Only) | ||
|
|
||
| For Anchor Create instructions, pack the output state tree to store the new account hash. | ||
|
|
||
| {% hint style="info" %} | ||
| * **Anchor Create**: Requires separate `pack_output_tree_index()` call (shown below) | ||
| * **Update/Close/Reinit**: `output_tree_index` already includes this in `PackedStateTreeInfos` from Step 3 | ||
| * **Burn**: Has no output state tree | ||
| {% endhint %} | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let output_state_tree_index = output_state_tree_info | ||
| .pack_output_tree_index(&mut remaining_accounts)?; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Call `pack_output_tree_index()` on the output state tree `TreeInfo` | ||
|
|
||
| * Returns u8 index for the output state tree | ||
| * This index is passed to your program instruction's `output_state_tree_index` parameter | ||
|
|
||
| ### 5. Finalize Packed Accounts | ||
|
|
||
| Convert packed accounts into the final array for your instruction. | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let (remaining_accounts, _, _) = remaining_accounts.to_account_metas(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Call `to_account_metas()` on your `PackedAccounts` instance | ||
|
|
||
| * Returns a tuple with three elements: | ||
| * `remaining_accounts`: `Vec<AccountMeta>` containing all accounts (system accounts + tree accounts) | ||
| * `system_start`: Offset where system accounts start (used internally by Light System Program) | ||
| * `packed_start`: Offset where tree accounts start (used internally by Light System Program) | ||
| * Pass `remaining_accounts` to `.remaining_accounts()` in your Anchor instruction builder | ||
|
|
||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endstep %} | ||
|
|
||
| {% step %} | ||
| ## Instruction Data | ||
|
|
||
| Build your instruction data with the validity proof, tree account indices, and complete account data. | ||
|
|
||
| {% hint style="info" %} | ||
| Compressed account data must be passed in instruction data because only the Merkle root hash is stored on-chain. Regular accounts store full data on-chain for programs to read directly. | ||
|
|
||
| The program hashes this data and the Light System Program verifies the hash against the root in a Merkle tree account. | ||
| {% endhint %} | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const proof = { | ||
| 0: proofRpcResult.compressedProof, | ||
| }; | ||
|
|
||
| const instructionData = { | ||
| proof, | ||
| addressTreeInfo: packedAddressTreeInfo, | ||
| outputStateTreeIndex: outputStateTreeIndex, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * Wrap the `compressedProof` from Step 4 to prove that the address does not exist yet in the specified address tree. | ||
|
|
||
| **2. Specify Merkle trees to store address and account hash** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `packedAddressTreeInfo`: Index to the address tree account used to derive the address, from Step 5 Section 3 | ||
| * `outputStateTreeIndex`: Index to the state tree account that will store the compressed account hash, from Step 5 Section 4 | ||
|
|
||
| **3. Pass initial account data** | ||
|
|
||
| * Add custom fields to your instruction struct for any initial data your program requires. | ||
| * In this example, a `message` field defines the initial account state. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const proof = { | ||
| 0: proofRpcResult.compressedProof, | ||
| }; | ||
|
|
||
| const instructionData = { | ||
| proof, | ||
| accountMeta: { | ||
| treeInfo: packedStateTreeInfo, | ||
| address: compressedAccount.address, | ||
| outputStateTreeIndex: outputStateTreeIndex | ||
| }, | ||
| currentMessage: currentAccount.message, | ||
| newMessage, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * Wrap the `compressedProof` from Step 4 to prove the account hash exists in the state tree. | ||
|
|
||
| **2. Specify input hash and output state tree** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `accountMeta` points to the input hash and specifies the output state tree: | ||
| * `treeInfo: packedStateTreeInfo`: Packed indices pointing to the existing account hash that will be nullified, from Step 5 Section 3 | ||
| * `address`: Account's derived address from Step 3 | ||
| * `outputStateTreeIndex`: Index to the state tree that will store the updated account hash, from Step 5 Section 3 | ||
|
|
||
| **3. Pass current account data** | ||
|
|
||
| * Pass the complete current account data. The program reconstructs the existing account hash from this data to verify it matches the hash in the state tree. | ||
| * In this example, `currentMessage` from the fetched account and `newMessage` for the update. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Close" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const proof = { | ||
| 0: proofRpcResult.compressedProof, | ||
| }; | ||
|
|
||
| const instructionData = { | ||
| proof, | ||
| accountMeta: { | ||
| treeInfo: packedStateTreeInfo, | ||
| address: compressedAccount.address, | ||
| outputStateTreeIndex: outputStateTreeIndex | ||
| }, | ||
| currentMessage: currentAccount.message, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * Wrap the `compressedProof` from Step 4 to prove the account hash exists in the state tree. | ||
|
|
||
| **2. Specify input hash and output state tree** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `accountMeta`: | ||
| * `treeInfo: packedStateTreeInfo`: Packed indices to the account hash being closed, from Step 5 Section 3 | ||
| * `address`: Account's derived address from Step 3 | ||
| * `outputStateTreeIndex`: Index to the state tree that will store a hash with zero values, from Step 5 Section 3 | ||
|
|
||
| **3. Pass current account data** | ||
|
|
||
| * Pass the complete current account data. The program reconstructs the account hash to verify it exists before closing. | ||
| * In this example, `currentMessage` from the fetched account. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Reinit" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const proof = { | ||
| 0: proofRpcResult.compressedProof, | ||
| }; | ||
|
|
||
| const instructionData = { | ||
| proof, | ||
| accountMeta: { | ||
| treeInfo: packedStateTreeInfo, | ||
| address: compressedAccount.address, | ||
| outputStateTreeIndex: outputStateTreeIndex | ||
| }, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * Wrap the `compressedProof` from Step 4 to prove the account hash exists in the state tree. | ||
|
|
||
| **2. Specify input hash and output state tree** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `accountMeta`: | ||
| * `treeInfo: packedStateTreeInfo`: Packed indices to the account hash being reinitialized, from Step 5 Section 3 | ||
| * `address`: Account's derived address from Step 3 | ||
| * `outputStateTreeIndex`: Index to the state tree that will store the reinitialized account hash, from Step 5 Section 3 | ||
|
|
||
| **3. Account data initialization** | ||
|
|
||
| * Reinitialize creates an account with default-initialized values (e.g., `Pubkey` as all zeros, numbers as `0`, strings as empty). | ||
| * To set custom values, update the account in the same or a separate transaction. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Burn" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const proof = { | ||
| 0: proofRpcResult.compressedProof, | ||
| }; | ||
|
|
||
| const instructionData = { | ||
| proof, | ||
| accountMeta: { | ||
| treeInfo: packedStateTreeInfo, | ||
| address: compressedAccount.address | ||
| }, | ||
| currentMessage: currentAccount.message, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * Wrap the `compressedProof` from Step 4 to prove the account hash exists in the state tree. | ||
|
|
||
| **2. Specify input hash** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `accountMeta`: | ||
| * `treeInfo: packedStateTreeInfo`: Packed indices to the account hash being burned, from Step 5 Section 3 | ||
| * `address`: Account's derived address from Step 3 | ||
| * No `outputStateTreeIndex` - Burn permanently removes the account with no output state | ||
|
|
||
| **3. Pass current account data** | ||
|
|
||
| * Pass the complete current account data for hash reconstruction before burning. | ||
| * In this example, `currentMessage` from the fetched account. | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% tabs %} | ||
| {% tab title="Anchor" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use anchor_lang::InstructionData; | ||
|
|
||
| let instruction_data = create::instruction::CreateAccount { | ||
| proof: rpc_result.proof, | ||
| address_tree_info: packed_accounts.address_trees[0], | ||
| output_state_tree_index: output_state_tree_index, | ||
| message, | ||
| } | ||
| .data(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Native" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use borsh::BorshSerialize; | ||
|
|
||
| let instruction_data = CreateInstructionData { | ||
| proof: rpc_result.proof, | ||
| address_tree_info: packed_address_tree_info, | ||
| output_state_tree_index: output_state_tree_index, | ||
| message, | ||
| }; | ||
| let serialized = instruction_data.try_to_vec().unwrap(); | ||
| let data = [&[InstructionType::Create as u8][..], &serialized[..]].concat(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * `proof`: Validity proof from Step 4 proving the address does not exist yet in the specified address tree. | ||
|
|
||
| **2. Specify Merkle trees to store address and account hash** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `address_tree_info`: Index to the address tree account used to derive the address, from Step 5 Section 3 | ||
| * `output_state_tree_index`: Index to the state tree account that will store the compressed account hash, from Step 5 Section 4 | ||
|
|
||
| **3. Pass initial account data** | ||
|
|
||
| * Add custom fields to your instruction struct for any initial data your program requires. | ||
| * In this example, a `message` field defines the initial account state. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update" %} | ||
| {% tabs %} | ||
| {% tab title="Anchor" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use anchor_lang::InstructionData; | ||
| use light_sdk::instruction::account_meta::CompressedAccountMeta; | ||
|
|
||
| let current_account = MyCompressedAccount::deserialize( | ||
| &mut compressed_account.data.as_ref().unwrap().data.as_slice(), | ||
| )?; | ||
|
|
||
| let instruction_data = update::instruction::UpdateAccount { | ||
| proof: rpc_result.proof, | ||
| current_account, | ||
| account_meta: CompressedAccountMeta { | ||
| tree_info: packed_tree_accounts.packed_tree_infos[0], | ||
| address: compressed_account.address.unwrap(), | ||
| output_state_tree_index: packed_tree_accounts.output_tree_index, | ||
| }, | ||
| new_message, | ||
| } | ||
| .data(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Native" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use borsh::BorshSerialize; | ||
|
|
||
| let current_account = MyCompressedAccount::deserialize( | ||
| &mut compressed_account.data.as_ref().unwrap().data.as_slice(), | ||
| )?; | ||
|
|
||
| let instruction_data = UpdateInstructionData { | ||
| proof: rpc_result.proof, | ||
| current_account, | ||
| account_meta: CompressedAccountMeta { | ||
| tree_info: packed_tree_accounts.packed_tree_infos[0], | ||
| address: compressed_account.address.unwrap(), | ||
| output_state_tree_index: packed_tree_accounts.output_tree_index, | ||
| }, | ||
| new_message, | ||
| }; | ||
| let serialized = instruction_data.try_to_vec().unwrap(); | ||
| let data = [&[InstructionType::Update as u8][..], &serialized[..]].concat(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * `proof`: Validity proof from Step 4 proving the account hash exists in the state tree. | ||
|
|
||
| **2. Specify input hash and output state tree** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `account_meta` points to the input hash and specifies the output state tree: | ||
| * `tree_info`: Packed indices pointing to the existing account hash that will be nullified, from Step 5 Section 3 | ||
| * `address`: Account's derived address from Step 3 | ||
| * `output_state_tree_index`: Index to the state tree that will store the updated account hash, from Step 5 Section 3 | ||
|
|
||
| **3. Pass current account data** | ||
|
|
||
| * Pass the complete current account data. The program reconstructs the existing account hash from this data to verify it matches the hash in the state tree. | ||
| * In this example, `current_account` (deserialized from fetched account) and `new_message` for the update. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Close" %} | ||
| {% tabs %} | ||
| {% tab title="Anchor" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use anchor_lang::InstructionData; | ||
| use light_sdk::instruction::account_meta::CompressedAccountMeta; | ||
|
|
||
| let instruction_data = close::instruction::CloseAccount { | ||
| proof: rpc_result.proof, | ||
| account_meta: CompressedAccountMeta { | ||
| tree_info: packed_tree_accounts.packed_tree_infos[0], | ||
| address: compressed_account.address.unwrap(), | ||
| output_state_tree_index: packed_tree_accounts.output_tree_index, | ||
| }, | ||
| current_message, | ||
| } | ||
| .data(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Native" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use borsh::BorshSerialize; | ||
|
|
||
| let instruction_data = CloseInstructionData { | ||
| proof: rpc_result.proof, | ||
| account_meta: CompressedAccountMeta { | ||
| tree_info: packed_tree_accounts.packed_tree_infos[0], | ||
| address: compressed_account.address.unwrap(), | ||
| output_state_tree_index: packed_tree_accounts.output_tree_index, | ||
| }, | ||
| current_message, | ||
| }; | ||
| let serialized = instruction_data.try_to_vec().unwrap(); | ||
| let data = [&[InstructionType::Close as u8][..], &serialized[..]].concat(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * `proof`: Validity proof from Step 4 proving the account hash exists in the state tree. | ||
|
|
||
| **2. Specify input hash and output state tree** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `account_meta`: | ||
| * `tree_info`: Packed indices to the account hash being closed, from Step 5 Section 3 | ||
| * `address`: Account's derived address from Step 3 | ||
| * `output_state_tree_index`: Index to the state tree that will store a hash with zero values, from Step 5 Section 3 | ||
|
|
||
| **3. Pass current account data** | ||
|
|
||
| * Pass the complete current account data. The program reconstructs the account hash to verify it exists before closing. | ||
| * In this example, `current_message` from the fetched account. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Reinit" %} | ||
| {% tabs %} | ||
| {% tab title="Anchor" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use anchor_lang::InstructionData; | ||
| use light_sdk::instruction::account_meta::CompressedAccountMeta; | ||
|
|
||
| let instruction_data = reinit::instruction::ReinitAccount { | ||
| proof: rpc_result.proof, | ||
| account_meta: CompressedAccountMeta { | ||
| tree_info: packed_tree_accounts.packed_tree_infos[0], | ||
| address: compressed_account.address.unwrap(), | ||
| output_state_tree_index: packed_tree_accounts.output_tree_index, | ||
| }, | ||
| } | ||
| .data(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Native" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use borsh::BorshSerialize; | ||
|
|
||
| let instruction_data = ReinitInstructionData { | ||
| proof: rpc_result.proof, | ||
| account_meta: CompressedAccountMeta { | ||
| tree_info: packed_tree_accounts.packed_tree_infos[0], | ||
| address: compressed_account.address.unwrap(), | ||
| output_state_tree_index: packed_tree_accounts.output_tree_index, | ||
| }, | ||
| }; | ||
| let serialized = instruction_data.try_to_vec().unwrap(); | ||
| let data = [&[InstructionType::Reinit as u8][..], &serialized[..]].concat(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * `proof`: Validity proof from Step 4 proving the account hash exists in the state tree. | ||
|
|
||
| **2. Specify input hash and output state tree** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `account_meta`: | ||
| * `tree_info`: Packed indices to the account hash being reinitialized, from Step 5 Section 3 | ||
| * `address`: Account's derived address from Step 3 | ||
| * `output_state_tree_index`: Index to the state tree that will store the reinitialized account hash, from Step 5 Section 3 | ||
|
|
||
| **3. Account data initialization** | ||
|
|
||
| * Reinitialize creates an account with default-initialized values (e.g., `Pubkey` as all zeros, numbers as `0`, strings as empty). | ||
| * To set custom values, update the account in the same or a separate transaction. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Burn" %} | ||
| {% tabs %} | ||
| {% tab title="Anchor" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use anchor_lang::InstructionData; | ||
| use light_sdk::instruction::account_meta::CompressedAccountMetaBurn; | ||
|
|
||
| let instruction_data = burn::instruction::BurnAccount { | ||
| proof: rpc_result.proof, | ||
| account_meta: CompressedAccountMetaBurn { | ||
| tree_info: packed_tree_accounts.packed_tree_infos[0], | ||
| address: compressed_account.address.unwrap(), | ||
| }, | ||
| current_message, | ||
| } | ||
| .data(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Native" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| use borsh::BorshSerialize; | ||
|
|
||
| let instruction_data = BurnInstructionData { | ||
| proof: rpc_result.proof, | ||
| account_meta: CompressedAccountMetaBurn { | ||
| tree_info: packed_tree_accounts.packed_tree_infos[0], | ||
| address: compressed_account.address.unwrap(), | ||
| }, | ||
| current_message, | ||
| }; | ||
| let serialized = instruction_data.try_to_vec().unwrap(); | ||
| let data = [&[InstructionType::Burn as u8][..], &serialized[..]].concat(); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **1. Validity Proof** | ||
|
|
||
| * `proof`: Validity proof from Step 4 proving the account hash exists in the state tree. | ||
|
|
||
| **2. Specify input hash** | ||
|
|
||
| Include the Merkle tree metadata from Step 5: | ||
|
|
||
| * `account_meta`: | ||
| * `tree_info`: Packed indices to the account hash being burned, from Step 5 Section 3 | ||
| * `address`: Account's derived address from Step 3 | ||
| * No `output_state_tree_index` - Burn permanently removes the account with no output state | ||
|
|
||
| **3. Pass current account data** | ||
|
|
||
| * Pass the complete current account data for hash reconstruction before burning. | ||
| * In this example, `current_message` from the fetched account. | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endstep %} | ||
|
|
||
| {% step %} | ||
| ## Instruction | ||
|
|
||
| Build the instruction with your `program_id`, `accounts`, and `data` from Step 6. Pass the accounts array you built in Step 5. | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const instruction = await program.methods | ||
| .createAccount(proof, packedAddressTreeInfo, outputStateTreeIndex, message) | ||
| .accounts({ | ||
| signer: payer.publicKey | ||
| }) | ||
| .remainingAccounts(packedAccounts.toAccountMetas().remainingAccounts) | ||
| .instruction(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof, packed address tree info, output state tree index from Step 6, and initial account data (e.g., `message`) as separate parameters to `.createAccount()`. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const instruction = await program.methods | ||
| .updateAccount(proof, currentAccount, compressedAccountMeta, newMessage) | ||
| .accounts({ | ||
| signer: payer.publicKey | ||
| }) | ||
| .remainingAccounts(packedAccounts.toAccountMetas().remainingAccounts) | ||
| .instruction(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof, current account data, compressed account metadata from Step 6, and new account data as separate parameters to `.updateAccount()`. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Close" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const instruction = await program.methods | ||
| .closeAccount(proof, compressedAccountMeta, message) | ||
| .accounts({ | ||
| signer: payer.publicKey | ||
| }) | ||
| .remainingAccounts(packedAccounts.toAccountMetas().remainingAccounts) | ||
| .instruction(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof, compressed account metadata from Step 6, and current account data as separate parameters to `.closeAccount()`. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Reinit" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const instruction = await program.methods | ||
| .reinitAccount(proof, compressedAccountMeta) | ||
| .accounts({ | ||
| signer: payer.publicKey | ||
| }) | ||
| .remainingAccounts(packedAccounts.toAccountMetas().remainingAccounts) | ||
| .instruction(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof and compressed account metadata from Step 6 as separate parameters to `.reinitAccount()`. No account data is passed since reinit creates default-initialized zero values. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Burn" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const instruction = await program.methods | ||
| .burnAccount(proof, compressedAccountMeta, currentMessage) | ||
| .accounts({ | ||
| signer: payer.publicKey | ||
| }) | ||
| .remainingAccounts(packedAccounts.toAccountMetas().remainingAccounts) | ||
| .instruction(); | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof, compressed account metadata (without `outputStateTreeIndex`) from Step 6, and current account data as separate parameters to `.burnAccount()`. | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let instruction = Instruction { | ||
| program_id: create::ID, | ||
| accounts: [ | ||
| vec![AccountMeta::new(payer.pubkey(), true)], | ||
| remaining_accounts, | ||
| ] | ||
| .concat(), | ||
| data: instruction_data, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof, packed address tree info, output state tree index from Step 6, and initial account data (e.g., `message`) as separate parameters to `.createAccount()`. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let instruction = Instruction { | ||
| program_id: update::ID, | ||
| accounts: [ | ||
| vec![AccountMeta::new(payer.pubkey(), true)], | ||
| remaining_accounts, | ||
| ] | ||
| .concat(), | ||
| data: instruction_data, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof, current account data, compressed account metadata from Step 6, and new account data as separate parameters to `.updateAccount()`. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Close" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let instruction = Instruction { | ||
| program_id: close::ID, | ||
| accounts: [ | ||
| vec![AccountMeta::new(payer.pubkey(), true)], | ||
| remaining_accounts, | ||
| ] | ||
| .concat(), | ||
| data: instruction_data, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof, compressed account metadata from Step 6, and current account data as separate parameters to `.closeAccount()`. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Reinit" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let instruction = Instruction { | ||
| program_id: reinit::ID, | ||
| accounts: [ | ||
| vec![AccountMeta::new(payer.pubkey(), true)], | ||
| remaining_accounts, | ||
| ] | ||
| .concat(), | ||
| data: instruction_data, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof and compressed account metadata from Step 6 as separate parameters to `.reinitAccount()`. No account data is passed since reinit creates default-initialized zero values. | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Burn" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| let instruction = Instruction { | ||
| program_id: burn::ID, | ||
| accounts: [ | ||
| vec![AccountMeta::new(payer.pubkey(), true)], | ||
| remaining_accounts, | ||
| ] | ||
| .concat(), | ||
| data: instruction_data, | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| Pass the proof, compressed account metadata (without `outputStateTreeIndex`) from Step 6, and current account data as separate parameters to `.burnAccount()`. | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| **What to include:** | ||
|
|
||
| 1. **Pass program-specific accounts** as defined by your program's IDL (signer, feepayer). | ||
| 2. **Add all remaining accounts** with `.remainingAccounts()` from Step 5: | ||
| * Light System accounts, added via `PackedAccounts.addSystemAccounts()` | ||
| * Merkle tree and queue accounts, added via `PackedAccounts.insertOrGet()` | ||
| 3. **Build the instruction**: | ||
| * Anchor converts `.accounts({ signer })` to `AccountMeta[]` using the program's IDL | ||
| * `.remainingAccounts()` appends the complete packed accounts array | ||
| * Returns `TransactionInstruction` with `programId`, merged `keys`, and serialized instruction `data` | ||
|
|
||
| {% endcode %} | ||
| {% endstep %} | ||
|
|
||
| {% step %} | ||
| ## Send Transaction | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| {% code overflow="wrap" %} | ||
| ```typescript | ||
| const blockhash = await rpc.getLatestBlockhash(); | ||
| const signedTx = buildAndSignTx( | ||
| [instruction], | ||
| payer, | ||
| blockhash.blockhash, | ||
| [] | ||
| ); | ||
| const signature = await sendAndConfirmTx(rpc, signedTx); | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| {% code overflow="wrap" %} | ||
| ```rust | ||
| rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) | ||
| .await | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endstep %} | ||
| {% endstepper %} | ||
|
|
||
| # Full Code Examples | ||
|
|
||
| Full TypeScript test examples using local test validator. | ||
|
|
||
| 1. Install the Light CLI first to download program binaries: | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```bash | ||
| npm -g i @lightprotocol/zk-compression-cli@0.27.1-alpha.2 | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 2. Start local test validator: | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```bash | ||
| light test-validator | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| 3. Then run tests in a separate terminal: | ||
|
|
||
| {% code overflow="wrap" %} | ||
| ```bash | ||
| anchor test --skip-local-validator | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| {% hint style="warning" %} | ||
| For help with debugging, see the [Error Cheatsheet](https://www.zkcompression.com/resources/error-cheatsheet). | ||
| {% endhint %} | ||
|
|
||
| {% tabs %} | ||
| {% tab title="Typescript" %} | ||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/anchor/create/tests/create.ts" %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/anchor/update/tests/update.ts" %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Close" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/anchor/close/tests/close.ts" %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Reinit" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/anchor/reinit/tests/reinit.ts" %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Burn" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/anchor/burn/tests/burn.ts" %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Rust" %} | ||
| {% tabs %} | ||
| {% tab title="Create" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/native/programs/create/tests/test.rs" %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Update" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/native/programs/update/tests/test.rs" %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Close" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/native/programs/close/tests/test.rs" %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Reinit" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/native/programs/reinit/tests/test.rs" %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="Burn" %} | ||
| {% @github-files/github-code-block url="https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/basic-operations/native/programs/burn/tests/test.rs" %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
| # Next Steps | ||
|
|
||
| Start building programs to create, or interact with compressed accounts. | ||
|
|
||
| {% content-ref url="../guides/" %} | ||
| [guides](../guides/) | ||
| {% endcontent-ref %} No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Address cumulative markdown formatting issues flagged by linting tools.
The static analysis tool markdownlint-cli2 flagged numerous formatting issues throughout the document, including:
- Missing blank lines around headings (MD022)
- Fenced code blocks not surrounded by blank lines (MD031)
- Emphasis used instead of proper headings (MD036)
- Table formatting issues (MD055, MD056)
- Bare URLs without proper markdown link formatting (MD034)
- Missing single trailing newline at end of file (MD047)
While many of these are cosmetic, they reduce compliance with markdown standards and may impact documentation rendering on certain platforms.
These formatting issues are low-priority but addressing them will improve documentation quality. Key areas to fix include:
- Blank lines around headings: Add blank lines above/below all
##,###etc. headings - Code block spacing: Ensure all
```languageblocks have blank lines before and after - Table formatting: Add leading/trailing pipes to tables for consistency
- Use proper link syntax: Convert bare URLs (lines 1779-1820) to
[text](url)format - Remove trailing newlines: Ensure file ends with exactly one newline
🧰 Tools
🪛 LanguageTool
[grammar] ~112-~112: This phrase is duplicated. You should probably use “Start a” only once.
Context: ...t" %} bash light test-validator Start a start a single-node Solana cluster, an RPC node...
(PHRASE_REPETITION)
[uncategorized] ~128-~128: Loose punctuation mark.
Context: ...t-client`](https://docs.rs/light-client): The RPC client that provides the ZK Com...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~129-~129: Loose punctuation mark.
Context: ...light-sdk: Program-side abstractions (macros, wrap...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~220-~220: Possible missing comma found.
Context: ...ss tree to derive and store the account address and * a state tree to store the compres...
(AI_HYDRA_LEO_MISSING_COMMA)
[typographical] ~286-~286: It appears that a comma is missing.
Context: ...blic key and other metadata. With these methods you select a random state tree to store...
(DURING_THAT_TIME_COMMA)
[uncategorized] ~305-~305: Loose punctuation mark.
Context: ...nfo contains. * tree: Merkle tree account pubkey * queue: Q...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~309-~309: Loose punctuation mark.
Context: ...erts values into the queue. * treeType: Automatically set based on which tree s...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~310-~310: Loose punctuation mark.
Context: ...election method you used. * cpiContext: Optional CPI context account for batche...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~414-~414: Loose punctuation mark.
Context: ...s these parameters**: * &[b"my-seed"]: Predefined inputs, such as strings, num...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~415-~415: Loose punctuation mark.
Context: ...t addresses. * &address_tree_info.tree: Specify the tree pubkey to ensure an ad...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~416-~416: Loose punctuation mark.
Context: ...es from identical seeds. * &program_id: Specify the program owner pubkey. {% en...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~461-~461: Loose punctuation mark.
Context: ... The RPC returns**: * compressedProof: The proof that the address does not exi...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~462-~462: Loose punctuation mark.
Context: ...n your instruction data. * rootIndices: An array with root index from the valid...
(UNLIKELY_OPENING_PUNCTUATION)
[typographical] ~463-~463: Usually, there’s no comma before “when”.
Context: ...you do not reference an existing account, when you create a compressed account. {% end...
(IF_NO_COMMA)
[uncategorized] ~491-~491: Loose punctuation mark.
Context: ... The RPC returns**: * compressedProof: The proof that the account hash exists ...
(UNLIKELY_OPENING_PUNCTUATION)
[typographical] ~525-~525: Usually, there’s no comma before “when”.
Context: ...you do not reference an existing account, when you create a compressed account. {% end...
(IF_NO_COMMA)
[typographical] ~611-~611: It appears that a comma is missing.
Context: ...mple create-and-update proof** In this example we generate one proof for the update of...
(DURING_THAT_TIME_COMMA)
[uncategorized] ~635-~635: Loose punctuation mark.
Context: ... The RPC returns:** * compressedProof: A single combined proof that verifies b...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~661-~661: The preposition ‘of’ seems more likely in this position.
Context: ...ddressWithTree]to prove non-existence in address trees. **2. The RPC returnsV...
(AI_HYDRA_LEO_REPLACE_IN_OF)
[uncategorized] ~665-~665: Loose punctuation mark.
Context: ...idityProofWithContextwith** *proof`: A single combined proof, passed to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~679-~679: Possible missing comma found.
Context: ... Pack Accounts To optimize instruction data we pack accounts into an array: * Ever...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~697-~697: Loose punctuation mark.
Context: ... account sections: 1. preAccounts: Program-specific accounts like signers ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~698-~698: Loose punctuation mark.
Context: ...rs or fee payer. 2. systemAccounts: [Light System accounts](https://www.zkc...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~857-~857: Loose punctuation mark.
Context: ...o three sections: 1. pre_accounts: Program-specific accounts (signers, fee...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1009-~1009: Possible missing comma found.
Context: ...read directly. The program hashes this data and the Light System Program verifies t...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1038-~1038: Loose punctuation mark.
Context: ... from Step 5: * packedAddressTreeInfo: Index to the address tree account used ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1113-~1113: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1150-~1150: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1187-~1187: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1240-~1240: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1246-~1246: Loose punctuation mark.
Context: ...data from Step 5: * address_tree_info: Index to the address tree account used ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1310-~1310: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1372-~1372: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1378-~1378: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1432-~1432: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1438-~1438: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1492-~1492: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1498-~1498: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1582-~1582: Possible missing comma found.
Context: ... .reinitAccount(). No account data is passed since reinit creates default-initialize...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1674-~1674: Possible missing comma found.
Context: ... .reinitAccount(). No account data is passed since reinit creates default-initialize...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1827-~1827: Possible missing comma found.
Context: ...uilding programs to create, or interact with compressed accounts. {% content-ref ur...
(AI_HYDRA_LEO_MISSING_COMMA)
🪛 markdownlint-cli2 (0.18.1)
41-41: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
57-57: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
62-62: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
66-66: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
71-71: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
75-75: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
80-80: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
84-84: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
97-97: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
99-99: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
103-103: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
105-105: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
109-109: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
122-122: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
143-143: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
153-153: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
157-157: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
166-166: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
170-170: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
216-216: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
236-236: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
240-240: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
246-246: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
250-250: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
260-260: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
263-263: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
269-269: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
272-272: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
321-321: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
338-338: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
344-344: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
360-360: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
365-365: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
385-385: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
393-393: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
399-399: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
407-407: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
429-429: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
446-446: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
451-451: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
472-472: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
481-481: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
501-501: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
513-513: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
534-534: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
545-545: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
589-589: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
589-589: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
589-589: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
602-602: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
602-602: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
602-602: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
603-603: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
603-603: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
603-603: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
609-609: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
616-616: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
625-625: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
641-641: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
655-655: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
677-677: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
689-689: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
703-703: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
744-744: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
755-755: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
762-762: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
768-768: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
781-781: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
788-788: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
805-805: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
808-808: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
815-815: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
828-828: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
831-831: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
847-847: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
847-847: Multiple headings with the same content
(MD024, no-duplicate-heading)
863-863: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
877-877: Multiple headings with the same content
(MD024, no-duplicate-heading)
882-882: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
885-885: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
900-900: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
902-902: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
915-915: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
920-920: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
934-934: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
939-939: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
968-968: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
971-971: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
979-979: Multiple headings with the same content
(MD024, no-duplicate-heading)
984-984: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
986-986: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1002-1002: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1017-1017: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1027-1027: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1030-1030: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1034-1034: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1041-1041: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1049-1049: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1064-1064: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1067-1067: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1071-1071: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1080-1080: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1088-1088: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1102-1102: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1105-1105: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1109-1109: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1118-1118: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1126-1126: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1139-1139: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1142-1142: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1146-1146: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1155-1155: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1163-1163: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1176-1176: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1179-1179: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1183-1183: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1192-1192: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1206-1206: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1216-1216: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1222-1222: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1233-1233: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1238-1238: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1242-1242: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1249-1249: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1259-1259: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1278-1278: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1284-1284: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1303-1303: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1308-1308: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1312-1312: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1321-1321: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1331-1331: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1345-1345: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1351-1351: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1365-1365: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1370-1370: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1374-1374: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1383-1383: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1393-1393: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1406-1406: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1412-1412: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1425-1425: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1430-1430: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1434-1434: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1443-1443: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1453-1453: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1466-1466: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1472-1472: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1485-1485: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1490-1490: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1494-1494: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1503-1503: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1514-1514: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1523-1523: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1531-1531: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1539-1539: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1547-1547: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1555-1555: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1563-1563: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1571-1571: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1579-1579: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1587-1587: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1595-1595: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1607-1607: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1617-1617: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1625-1625: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1635-1635: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1643-1643: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1653-1653: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1661-1661: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1671-1671: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1679-1679: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1689-1689: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1713-1713: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1718-1718: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1727-1727: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1733-1733: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1736-1736: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1750-1750: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1752-1752: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1755-1755: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
1758-1758: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1760-1760: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1763-1763: Ordered list item prefix
Expected: 1; Actual: 3; Style: 1/1/1
(MD029, ol-prefix)
1766-1766: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1768-1768: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1779-1779: Bare URL used
(MD034, no-bare-urls)
1783-1783: Bare URL used
(MD034, no-bare-urls)
1787-1787: Bare URL used
(MD034, no-bare-urls)
1791-1791: Bare URL used
(MD034, no-bare-urls)
1795-1795: Bare URL used
(MD034, no-bare-urls)
1803-1803: Bare URL used
(MD034, no-bare-urls)
1807-1807: Bare URL used
(MD034, no-bare-urls)
1811-1811: Bare URL used
(MD034, no-bare-urls)
1815-1815: Bare URL used
(MD034, no-bare-urls)
1819-1819: Bare URL used
(MD034, no-bare-urls)
1831-1831: Files should end with a single newline character
(MD047, single-trailing-newline)
🤖 Prompt for AI Agents
In zk-compression-docs/compressed-pdas/client-library/README.md (lines 1-1831)
the linter reported many markdown formatting problems (missing blank lines
around headings MD022, fenced code blocks not surrounded by blank lines MD031,
emphasis used instead of headings MD036, table formatting MD055/MD056, bare URLs
MD034, and missing single trailing newline MD047). Fix by inserting a blank line
above and below every heading and every fenced code block, convert
emphasis-styled section titles to proper Markdown headings where appropriate,
normalize all tables with leading and trailing pipe characters and consistent
column separators, replace bare URLs with descriptive [text](url) links for the
links around lines ~1779-1820, and ensure the file ends with exactly one
newline; run markdownlint-cli2 after changes and iterate until no remaining
warnings.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
zk-compression-docs/compressed-pdas/client-library/README.md (1)
41-1831: Address cumulative markdown formatting issues.The comprehensive markdown linting issues flagged in the previous review persist (MD022, MD031, MD036, MD034, MD047, MD055, MD056). While these are style/compliance issues rather than correctness problems, they should be resolved to meet documentation standards. The previous review provided detailed guidance on each category of fixes needed.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
zk-compression-docs/compressed-pdas/client-library/README.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
zk-compression-docs/**/*.md
⚙️ CodeRabbit configuration file
zk-compression-docs/**/*.md: When reviewing documentation changes:
- Verify that all source code references in the documentation exist and are accurate
- Check CLAUDE.md to ensure the page-to-source-code mapping is updated if new pages are added
- Confirm that code examples match the actual implementation in the linked source files
- Validate that GitHub URLs in the documentation tree are correct and accessible
Files:
zk-compression-docs/compressed-pdas/client-library/README.md
🪛 LanguageTool
zk-compression-docs/compressed-pdas/client-library/README.md
[uncategorized] ~127-~127: Loose punctuation mark.
Context: ...t-client`](https://docs.rs/light-client): The RPC client that provides the ZK Com...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~128-~128: Loose punctuation mark.
Context: ...light-sdk: Program-side abstractions (macros, wrap...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~219-~219: Possible missing comma found.
Context: ...ss tree to derive and store the account address and * a state tree to store the compres...
(AI_HYDRA_LEO_MISSING_COMMA)
[typographical] ~285-~285: It appears that a comma is missing.
Context: ...blic key and other metadata. With these methods you select a random state tree to store...
(DURING_THAT_TIME_COMMA)
[uncategorized] ~304-~304: Loose punctuation mark.
Context: ...nfo contains. * tree: Merkle tree account pubkey * queue: Q...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~308-~308: Loose punctuation mark.
Context: ...erts values into the queue. * treeType: Automatically set based on which tree s...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~309-~309: Loose punctuation mark.
Context: ...election method you used. * cpiContext: Optional CPI context account for batche...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~413-~413: Loose punctuation mark.
Context: ...s these parameters**: * &[b"my-seed"]: Predefined inputs, such as strings, num...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~414-~414: Loose punctuation mark.
Context: ...t addresses. * &address_tree_info.tree: Specify the tree pubkey to ensure an ad...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~415-~415: Loose punctuation mark.
Context: ...es from identical seeds. * &program_id: Specify the program owner pubkey. {% en...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~460-~460: Loose punctuation mark.
Context: ... The RPC returns**: * compressedProof: The proof that the address does not exi...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~461-~461: Loose punctuation mark.
Context: ...n your instruction data. * rootIndices: An array with root index from the valid...
(UNLIKELY_OPENING_PUNCTUATION)
[typographical] ~462-~462: Usually, there’s no comma before “when”.
Context: ...you do not reference an existing account, when you create a compressed account. {% end...
(IF_NO_COMMA)
[uncategorized] ~490-~490: Loose punctuation mark.
Context: ... The RPC returns**: * compressedProof: The proof that the account hash exists ...
(UNLIKELY_OPENING_PUNCTUATION)
[typographical] ~524-~524: Usually, there’s no comma before “when”.
Context: ...you do not reference an existing account, when you create a compressed account. {% end...
(IF_NO_COMMA)
[typographical] ~610-~610: It appears that a comma is missing.
Context: ...mple create-and-update proof** In this example we generate one proof for the update of...
(DURING_THAT_TIME_COMMA)
[uncategorized] ~634-~634: Loose punctuation mark.
Context: ... The RPC returns:** * compressedProof: A single combined proof that verifies b...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~660-~660: The preposition ‘of’ seems more likely in this position.
Context: ...ddressWithTree]to prove non-existence in address trees. **2. The RPC returnsV...
(AI_HYDRA_LEO_REPLACE_IN_OF)
[uncategorized] ~664-~664: Loose punctuation mark.
Context: ...idityProofWithContextwith** *proof`: A single combined proof, passed to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~678-~678: Possible missing comma found.
Context: ... Pack Accounts To optimize instruction data we pack accounts into an array: * Ever...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~696-~696: Loose punctuation mark.
Context: ... account sections: 1. preAccounts: Program-specific accounts like signers ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~697-~697: Loose punctuation mark.
Context: ...rs or fee payer. 2. systemAccounts: [Light System accounts](https://www.zkc...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~856-~856: Loose punctuation mark.
Context: ...o three sections: 1. pre_accounts: Program-specific accounts (signers, fee...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1008-~1008: Possible missing comma found.
Context: ...read directly. The program hashes this data and the Light System Program verifies t...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1037-~1037: Loose punctuation mark.
Context: ... from Step 5: * packedAddressTreeInfo: Index to the address tree account used ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1112-~1112: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1149-~1149: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1186-~1186: Loose punctuation mark.
Context: ...e metadata from Step 5: * accountMeta: * treeInfo: packedStateTreeInfo: Pa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1239-~1239: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1245-~1245: Loose punctuation mark.
Context: ...data from Step 5: * address_tree_info: Index to the address tree account used ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1309-~1309: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1371-~1371: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1377-~1377: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1431-~1431: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1437-~1437: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1491-~1491: Loose punctuation mark.
Context: ...abs %} 1. Validity Proof * proof: Validity proof from Step 4 proving the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1497-~1497: Loose punctuation mark.
Context: ... metadata from Step 5: * account_meta: * tree_info: Packed indices to the ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~1581-~1581: Possible missing comma found.
Context: ... .reinitAccount(). No account data is passed since reinit creates default-initialize...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1673-~1673: Possible missing comma found.
Context: ... .reinitAccount(). No account data is passed since reinit creates default-initialize...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~1826-~1826: Possible missing comma found.
Context: ...uilding programs to create, or interact with compressed accounts. {% content-ref ur...
(AI_HYDRA_LEO_MISSING_COMMA)
🪛 markdownlint-cli2 (0.18.1)
zk-compression-docs/compressed-pdas/client-library/README.md
41-41: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
57-57: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
62-62: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
66-66: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
71-71: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
75-75: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
80-80: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
84-84: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
97-97: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
99-99: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
103-103: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
105-105: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
109-109: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
111-111: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
121-121: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
142-142: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
152-152: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
156-156: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
165-165: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
169-169: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
215-215: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
235-235: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
239-239: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
245-245: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
249-249: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
259-259: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
262-262: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
268-268: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
271-271: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
320-320: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
337-337: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
343-343: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
359-359: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
364-364: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
384-384: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
392-392: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
398-398: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
406-406: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
428-428: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
445-445: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
450-450: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
471-471: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
480-480: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
500-500: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
512-512: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
533-533: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
544-544: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
588-588: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
588-588: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
588-588: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
601-601: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
601-601: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
601-601: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
602-602: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe
(MD055, table-pipe-style)
602-602: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe
(MD055, table-pipe-style)
602-602: Table column count
Expected: 2; Actual: 1; Too few cells, row will be missing data
(MD056, table-column-count)
608-608: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
615-615: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
624-624: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
640-640: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
654-654: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
676-676: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
688-688: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
702-702: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
743-743: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
754-754: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
761-761: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
767-767: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
780-780: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
787-787: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
804-804: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
807-807: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
814-814: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
827-827: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
830-830: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
846-846: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
846-846: Multiple headings with the same content
(MD024, no-duplicate-heading)
862-862: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
876-876: Multiple headings with the same content
(MD024, no-duplicate-heading)
881-881: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
884-884: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
899-899: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
901-901: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
914-914: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
919-919: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
933-933: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
938-938: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
967-967: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
970-970: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
978-978: Multiple headings with the same content
(MD024, no-duplicate-heading)
983-983: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
985-985: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1001-1001: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1016-1016: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1026-1026: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1029-1029: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1033-1033: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1040-1040: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1048-1048: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1063-1063: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1066-1066: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1070-1070: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1079-1079: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1087-1087: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1101-1101: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1104-1104: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1108-1108: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1117-1117: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1125-1125: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1138-1138: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1141-1141: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1145-1145: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1154-1154: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1162-1162: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1175-1175: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1178-1178: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1182-1182: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1191-1191: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1205-1205: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1215-1215: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1221-1221: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1232-1232: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1237-1237: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1241-1241: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1248-1248: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1258-1258: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1277-1277: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1283-1283: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1302-1302: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1307-1307: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1311-1311: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1320-1320: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1330-1330: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1344-1344: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1350-1350: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1364-1364: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1369-1369: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1373-1373: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1382-1382: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1392-1392: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1405-1405: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1411-1411: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1424-1424: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1429-1429: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1433-1433: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1442-1442: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1452-1452: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1465-1465: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1471-1471: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1484-1484: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1489-1489: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1493-1493: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1502-1502: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1513-1513: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1522-1522: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1530-1530: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1538-1538: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1546-1546: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1554-1554: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1562-1562: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1570-1570: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1578-1578: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1586-1586: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1594-1594: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1606-1606: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1616-1616: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1624-1624: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1634-1634: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1642-1642: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1652-1652: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1660-1660: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1670-1670: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1678-1678: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1688-1688: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1712-1712: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above
(MD022, blanks-around-headings)
1717-1717: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1726-1726: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1732-1732: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1735-1735: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1749-1749: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1751-1751: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1754-1754: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1
(MD029, ol-prefix)
1757-1757: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1759-1759: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1762-1762: Ordered list item prefix
Expected: 1; Actual: 3; Style: 1/1/1
(MD029, ol-prefix)
1765-1765: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1767-1767: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
1778-1778: Bare URL used
(MD034, no-bare-urls)
1782-1782: Bare URL used
(MD034, no-bare-urls)
1786-1786: Bare URL used
(MD034, no-bare-urls)
1790-1790: Bare URL used
(MD034, no-bare-urls)
1794-1794: Bare URL used
(MD034, no-bare-urls)
1802-1802: Bare URL used
(MD034, no-bare-urls)
1806-1806: Bare URL used
(MD034, no-bare-urls)
1810-1810: Bare URL used
(MD034, no-bare-urls)
1814-1814: Bare URL used
(MD034, no-bare-urls)
1818-1818: Bare URL used
(MD034, no-bare-urls)
1830-1830: Files should end with a single newline character
(MD047, single-trailing-newline)
🔇 Additional comments (3)
zk-compression-docs/compressed-pdas/client-library/README.md (3)
1778-1820: Verify GitHub URLs point to stable branches before publishing.The code example URLs reference the branch
add-basic-operations-examples, which appears to be a feature branch:https://github.com/Lightprotocol/program-examples/blob/add-basic-operations-examples/...Per documentation guidelines, confirm:
- This branch will be merged to
main(or another stable branch) before or concurrent with this PR publication- The branch won't be deleted, or the URLs should be updated to reference
mainafter merge- The code examples in that branch match the exact API shown in this guide
If this branch is WIP, consider updating the URLs to reference the target stable branch.
1-1831: Verify CLAUDE.md page-to-source mapping is updated.Per the coding guidelines, when new documentation pages are added to
zk-compression-docs/, theCLAUDE.mdfile must be updated with the page-to-source-code mapping. This new file (zk-compression-docs/compressed-pdas/client-library/README.md) should have a corresponding entry inCLAUDE.md.Please verify that
CLAUDE.mdhas been updated to include this new page mapping.
57-82: I'll help you verify the review comment thoroughly. Let me gather the necessary information:Now I need to run shell scripts to verify the repository details per the coding guidelines:
Based on my verification, I've found critical issues with the review comment itself. The comment correctly identifies that the specified versions don't exist, but the proposed solution may be incorrect.
The latest version of @lightprotocol/compressed-token is 0.22.0, not the
0.22.1-alpha.1specified in the documentation, nor the0.9.0suggested as the fix. Importantly, the official Light Protocol documentation shows installation commands without version specifiers, indicating that packages should be installed at their latest stable versions rather than with pinned versions.The review comment conflates two problems: it correctly identifies that the versions in the docs don't exist, but then suggests a potentially incorrect replacement version. This is a critical issue because following the review as written would still leave the documentation broken—just with a different broken version number.
Remove version pinning entirely and allow npm to install latest stable releases, or specify the current latest stable version 0.22.0.
| light test-validator | ||
| ``` | ||
|
|
||
| Starts a start a single-node Solana cluster, an RPC node, and a prover node at ports 8899, 8784, and 3001. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix duplicated phrase in Rust Localnet instructions.
Line 183 contains a repeated "start a" phrase that should be corrected for clarity.
-Starts a start a single-node Solana cluster, an RPC node, and a prover node at ports 8899, 8784, and 3001.
+Starts a single-node Solana cluster, an RPC node, and a prover node at ports 8899, 8784, and 3001.🤖 Prompt for AI Agents
In zk-compression-docs/compressed-pdas/client-library/README.md around line 183,
the sentence contains a duplicated phrase "start a start a"; remove the extra
"start a" so the sentence reads correctly (e.g., "Starts a single-node Solana
cluster, an RPC node, and a prover node at ports 8899, 8784, and 3001.") and
ensure punctuation/capitalization remains consistent with surrounding
instructions.
Summary
Restores the client library README guide for compressed PDAs that was removed from main.
This guide provides step-by-step implementation for building TypeScript and Rust clients with:
Changes
zk-compression-docs/compressed-pdas/client-library/README.md(1,831 lines)Summary by CodeRabbit