feat(bootstrap): typed constructor inputs in deploy form#530
Merged
Conversation
Port `crates/explorer/ui/src/shared/utils/abi.ts` to Rust as `katana_bootstrap::abi`. Provides `parse_abi` (constructor + read/write function lists with resolved `TypeNode` inputs) and `to_calldata` (encode a `serde_json::Value` against a `TypeNode` into felts), so the bootstrap crate can later accept typed constructor inputs instead of raw felt arrays. JSON Schema generation, `sortedAbi`, and the form-binding helpers from the TS source are intentionally not ported — no Rust caller needs them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the single raw-calldata text field in the "Add contract" modal with per-argument inputs derived from the selected class's constructor ABI. Each field shows the argument name, a dimmed type hint (e.g. `ContractAddress`, `u256`, `Array<felt252>`), and a text editor. Values are encoded via `abi::to_calldata` on save, so the executor and manifest format are unchanged. The modal is now split into two bordered sections — "Contract" (class picker, label, salt, unique) and "Constructor" (typed args or raw fallback) — making the constructor block visually distinct. Key details: - u256 is special-cased in resolve_type to stay Primitive (user types a single number, split_u256 handles the rest) instead of requiring a JSON struct literal. - class_options() (ABI parse + embedded class decompression) is deferred to class-cycling and Enter/build only — no longer called per-keystroke, which fixes paste lag. - Editing an existing entry with raw calldata stays in raw mode to avoid lossy reverse-encoding; empty calldata adopts typed mode. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Treat `core::byte_array::ByteArray` the same way as u256 — resolve it as a Primitive in the type AST so the user types a plain string instead of filling in the raw struct fields (data, pending_word, pending_word_len). The encoder splits the string into 31-byte big-endian felt chunks following Cairo's ByteArray Serde layout: [num_full_chunks, ...chunks, pending_word, pending_word_len] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…itives ContractAddress, ClassHash, EthAddress, and StorageAddress are single- felt wrapper structs in the Sierra ABI. Without special-casing, the struct branch tries to JSON-parse a bare hex value as an object and fails. Treat them as transparent primitives so the user enters one hex/decimal value that encodes directly as a felt. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The edit form was resetting all constructor inputs to empty because from_existing always created fresh TextInputs. Add from_calldata — the inverse of to_calldata — to decode existing raw felts back into display strings and pre-fill the typed inputs. Supports round-tripping single-felt primitives, u256, ByteArray, bools, structs, arrays, and options. Falls back gracefully (empty field) when decoding isn't possible. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Label completed rows with `class hash:` and `address:` so the results are immediately readable. Align the labels so hex values line up across declare and deploy rows, and use cyan instead of dark gray so they're actually visible. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: cc45d37 | Previous: caae2a8 | Ratio |
|---|---|---|---|
CompiledClass(fixture)/compress |
2712365 ns/iter (± 7843) |
2737238 ns/iter (± 48212) |
0.99 |
CompiledClass(fixture)/decompress |
2874446 ns/iter (± 15939) |
2894584 ns/iter (± 14002) |
0.99 |
ExecutionCheckpoint/compress |
32 ns/iter (± 8) |
35 ns/iter (± 8) |
0.91 |
ExecutionCheckpoint/decompress |
25 ns/iter (± 3) |
25 ns/iter (± 2) |
1 |
PruningCheckpoint/compress |
32 ns/iter (± 8) |
34 ns/iter (± 8) |
0.94 |
PruningCheckpoint/decompress |
25 ns/iter (± 7) |
25 ns/iter (± 3) |
1 |
VersionedHeader/compress |
645 ns/iter (± 9) |
642 ns/iter (± 8) |
1.00 |
VersionedHeader/decompress |
813 ns/iter (± 17) |
814 ns/iter (± 21) |
1.00 |
StoredBlockBodyIndices/compress |
77 ns/iter (± 6) |
76 ns/iter (± 7) |
1.01 |
StoredBlockBodyIndices/decompress |
36 ns/iter (± 8) |
36 ns/iter (± 7) |
1 |
StorageEntry/compress |
162 ns/iter (± 2) |
148 ns/iter (± 3) |
1.09 |
StorageEntry/decompress |
141 ns/iter (± 2) |
139 ns/iter (± 3) |
1.01 |
ContractNonceChange/compress |
161 ns/iter (± 2) |
148 ns/iter (± 3) |
1.09 |
ContractNonceChange/decompress |
233 ns/iter (± 3) |
236 ns/iter (± 3) |
0.99 |
ContractClassChange/compress |
224 ns/iter (± 3) |
200 ns/iter (± 2) |
1.12 |
ContractClassChange/decompress |
249 ns/iter (± 3) |
251 ns/iter (± 3) |
0.99 |
ContractStorageEntry/compress |
158 ns/iter (± 4) |
161 ns/iter (± 4) |
0.98 |
ContractStorageEntry/decompress |
309 ns/iter (± 3) |
307 ns/iter (± 8) |
1.01 |
GenericContractInfo/compress |
136 ns/iter (± 6) |
132 ns/iter (± 3) |
1.03 |
GenericContractInfo/decompress |
102 ns/iter (± 3) |
102 ns/iter (± 4) |
1 |
Felt/compress |
82 ns/iter (± 6) |
82 ns/iter (± 5) |
1 |
Felt/decompress |
55 ns/iter (± 5) |
57 ns/iter (± 5) |
0.96 |
BlockHash/compress |
81 ns/iter (± 5) |
82 ns/iter (± 6) |
0.99 |
BlockHash/decompress |
55 ns/iter (± 7) |
56 ns/iter (± 4) |
0.98 |
TxHash/compress |
81 ns/iter (± 4) |
82 ns/iter (± 5) |
0.99 |
TxHash/decompress |
54 ns/iter (± 7) |
56 ns/iter (± 5) |
0.96 |
ClassHash/compress |
81 ns/iter (± 6) |
82 ns/iter (± 5) |
0.99 |
ClassHash/decompress |
55 ns/iter (± 8) |
56 ns/iter (± 5) |
0.98 |
CompiledClassHash/compress |
81 ns/iter (± 5) |
82 ns/iter (± 6) |
0.99 |
CompiledClassHash/decompress |
54 ns/iter (± 1) |
56 ns/iter (± 5) |
0.96 |
BlockNumber/compress |
47 ns/iter (± 2) |
47 ns/iter (± 3) |
1 |
BlockNumber/decompress |
25 ns/iter (± 1) |
25 ns/iter (± 0) |
1 |
TxNumber/compress |
47 ns/iter (± 3) |
47 ns/iter (± 5) |
1 |
TxNumber/decompress |
26 ns/iter (± 0) |
26 ns/iter (± 0) |
1 |
FinalityStatus/compress |
1 ns/iter (± 0) |
1 ns/iter (± 0) |
1 |
FinalityStatus/decompress |
12 ns/iter (± 1) |
12 ns/iter (± 0) |
1 |
TypedTransactionExecutionInfo/compress |
16232 ns/iter (± 74) |
18106 ns/iter (± 539) |
0.90 |
TypedTransactionExecutionInfo/decompress |
3587 ns/iter (± 203) |
3696 ns/iter (± 121) |
0.97 |
VersionedContractClass/compress |
375 ns/iter (± 67) |
379 ns/iter (± 11) |
0.99 |
VersionedContractClass/decompress |
778 ns/iter (± 21) |
783 ns/iter (± 15) |
0.99 |
MigratedCompiledClassHash/compress |
146 ns/iter (± 6) |
160 ns/iter (± 5) |
0.91 |
MigratedCompiledClassHash/decompress |
146 ns/iter (± 6) |
139 ns/iter (± 4) |
1.05 |
ContractInfoChangeList/compress |
1683 ns/iter (± 40) |
1611 ns/iter (± 45) |
1.04 |
ContractInfoChangeList/decompress |
2217 ns/iter (± 376) |
2246 ns/iter (± 387) |
0.99 |
BlockChangeList/compress |
661 ns/iter (± 22) |
696 ns/iter (± 57) |
0.95 |
BlockChangeList/decompress |
896 ns/iter (± 151) |
913 ns/iter (± 162) |
0.98 |
ReceiptEnvelope/compress |
30469 ns/iter (± 830) |
32091 ns/iter (± 1820) |
0.95 |
ReceiptEnvelope/decompress |
6002 ns/iter (± 213) |
6186 ns/iter (± 304) |
0.97 |
TrieDatabaseValue/compress |
169 ns/iter (± 3) |
172 ns/iter (± 30) |
0.98 |
TrieDatabaseValue/decompress |
215 ns/iter (± 1) |
230 ns/iter (± 1) |
0.93 |
TrieHistoryEntry/compress |
288 ns/iter (± 1) |
290 ns/iter (± 1) |
0.99 |
TrieHistoryEntry/decompress |
260 ns/iter (± 9) |
269 ns/iter (± 9) |
0.97 |
This comment was automatically generated by workflow using github-action-benchmark.
|
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #530 +/- ##
==========================================
- Coverage 73.32% 66.45% -6.88%
==========================================
Files 209 308 +99
Lines 23132 41842 +18710
==========================================
+ Hits 16961 27805 +10844
- Misses 6171 14037 +7866 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bootstrap TUI currently requires users to enter constructor calldata as raw comma-separated felt values. This is error-prone and requires manually looking up the ABI to know the expected argument order, types, and encoding (e.g. u256 must be split into low/high felts, ByteArray must be chunked into 31-byte words).
This PR adds an ABI parsing layer (
crates/bootstrap/src/abi.rs) that extracts the constructor signature from a Sierra class and resolves each input into a typed AST. The deploy form in the TUI now introspects the selected class's ABI and presents one labeled input field per constructor argument, showing the argument name and a type hint. Values are automatically encoded into the correct felt sequence on save — users type a plain number foru256, a string forByteArray, JSON for arrays/structs, and hex literals for felts.u256andByteArrayare special-cased to resolve as primitives rather than their underlying struct representations, so the user enters a single value instead of filling in internal fields like{low, high}or{data, pending_word, pending_word_len}.When a class has no introspectable ABI (legacy classes, missing or invalid ABI), the form falls back to the original raw calldata input. Editing an existing deploy entry that already has raw calldata preserves it in raw mode to avoid lossy reverse-encoding.
The expensive
class_options()call (ABI parsing + embedded class decompression) is deferred to class-cycling and save only — it no longer runs per-keystroke, keeping paste and typing responsive.Test plan
abi.rscovering type resolution, calldata encoding (u256 split, ByteArray chunking, struct flattening, arrays, options, booleans), edge cases (Span-as-array, nested structs, u256/ByteArray struct-in-ABI resolution)tui.rscovering typed/raw mode selection, form build encoding, class sync with value carry-over, focus navigation, and error reporting🤖 Generated with Claude Code