Repository navigation
Conversation
…it (#848) * test: pin the ledger-entry ceiling that makes MAX_HISTORY_ENTRIES unreachable MAX_HISTORY_ENTRIES is documented as preventing storage DoS by capping the history vector, but it cannot be reached. A SpendingLimitData holding 816 entries serializes to 65,592 bytes, past the mainnet contractDataEntrySizeBytes limit of 65,536, so enforce fails with an untyped host budget error and HistoryCapacityExceeded is never returned. The measured ceiling is 815. This is visible in the existing suite: enforce_history_capacity_exceeded reaches 1000 only because it calls disable_resource_limits(). That call is a normal idiom here, used in eight places across four files for tests that deliberately exceed mainnet limits, so this is not a claim that the test is wrong. It does mean no test currently covers the interaction between the constant and the platform limit. Adds two tests that pin both sides of the boundary under mainnet defaults: filling to 815 succeeds and leaves the guard untouched, and 816 fails with Error(Budget, ExceededLimit). Documents the ceiling on the constant. The constant itself is left at 1000. Lowering it would be a behavioural change for accounts currently holding more than the new value in-window, and the right value is a judgement about headroom that belongs to the maintainers. The open question is in the linked issue. Note the second test asserts a host budget error rather than a contract error code, so it does not use the usual Error(Contract, #NNNN) form. stellar-accounts: 183 passed. * fix: cap spending history at the reachable ledger entry limit MAX_HISTORY_ENTRIES was 1000, but a SpendingLimitData holding 816 entries serializes to 65,592 bytes, past the mainnet contractDataEntrySizeBytes limit of 65,536. The guard could therefore never fire: enforce failed with an untyped host budget error before HistoryCapacityExceeded could be returned. Set the cap to 815, the largest history that fits in one ledger entry, so the guard is reachable and callers get the typed error. enforce_history_capacity_exceeded was only passing because it disabled resource limits, which is why the unreachable cap went unnoticed; it now runs under mainnet defaults. A new test writes one entry past the cap straight to storage so the ceiling is pinned by a test rather than a comment.
…#853) * feat(confidential): escrow the sender-auditor secret in sponge lane 2 Widens the sender-auditor sponge from two lanes to three and adds an auditor-side escrow of the delegation viewing key. Lane 2 carries the new spendable blinding on the checkpoint operations (W_a5, T_a9, S_a6) and dvk_i on spender transfers (O_a9); S14 escrows dvk_i to the owner's auditor at set_spender under a new domain tag. The auditor can now recover the full Pedersen opening of C_spend and C_a rather than the value alone. * cite instead of copy in CLAUDE.md * docs(confidential): make the sender-auditor channel three-lane throughout DESIGN_cont §8.1/§8.2/§8.4/§8.5 still read the sender channel two-wide and still claimed no auditor can open C_spend; SDK §11 and OVERVIEW's visibility table omitted lane 2 entirely. Scope the spend-side opening to the checkpoint events that escrow it, restore V2 in the vk contract-binding lists, and move the lane-2 semantics out of DESIGN §2.5 into §8.1. * feat(confidential): emit the allowance salts in delegation events `SetSpender` gains `sigma_a` and `SpenderTransfer` gains `sigma_a_new`, both already proof-bound public inputs. Without them the owner's auditor cannot derive `r_a` and open `C_a`, contradicting DESIGN_cont §8.5. Event assertions in the happy-path tests now compare the typed `#[contractevent]` struct rather than counting events. * test(confidential): cover the lane-2 escrow constraints, drop the dead helper Adds the missing negative tests for W_a5, T_a9, S_a6, S14 and O_a9 -- each constraint could be deleted without failing a test. `encrypt_auditor_sender_balance` has no circuit caller since the sender channel went three-lane; `sponge_squeeze_2` is now the prefix of `sponge_squeeze_3` so their agreement is structural rather than test-pinned. Also corrects the RevokeSpender and `op_i` rationales, which did not hold. * docs(confidential): correct the auditor's opening scope and the tag-17 home The lane-2 escrow does not lapse at a merge: one auditor_id serves both of an account's channels, so the same key holds every inbound blinding and carries the opening forward by addition. §8.1, §9.4, SDK §11, OVERVIEW and SELECTIVE_DISCLOSURE said otherwise. Also fills in the event and payload tables with the fields this branch added, specifies the auditor-side dvk escrow in §8.5 (DESIGN.md is over its LaTeX budget), and makes the COMPLIANCE §5.3 clawback sketch consume and re-emit the escrow instead of leaving r_s unresolved. * docs(confidential): state what actually separates tag 17 from tag 11 * feat(confidential): escrow r_a to the owner's auditor instead of dvk_i S14 and O_a9 escrowed the delegation viewing key, which is deterministic and permanent per (owner, spender) and survives revoke-then-re-delegate, so one leaked ciphertext opened every allowance state for that pair, past and future. Both now escrow the blinding of the allowance commitment the operation writes -- r_a at set_spender, r_a' at spender_transfer -- which is what the auditor actually needs to open C_a. Tag 17 becomes ESCROWED_ALLOWANCE_BLINDING_AUDITOR (value unchanged) and lane 2 is uniformly a commitment blinding, never a key. Zero ACIR delta: both blindings were already constrained witnesses in scope. Payload and event fields are renamed, so this is an SDK-visible ABI change. DESIGN_cont §8.5's forward-only and rotation-remediation claims were false and are replaced with an event-scoped claim: a rotated-in key holds no opening until the delegation's next state change, and a retired key that already holds one can still carry it through a public homomorphic fold. * docs(confidential): fix stale auditor-side dvk_i escrow references Seven spots still described S14 and SpenderTransfer lane 2 as escrowing dvk_i. The SELECTIVE_DISCLOSURE §8 note was the substantive one: it ruled out a lane-2 disclosure variant on the grounds that the lane masks a key, which no longer holds now that it carries r_a'. * docs(confidential): drop the restated blast-radius paragraph in §8.5 The leak scope it describes is already stated by the dvk_i comparison paragraph above it, which ends "a leaked r_a ciphertext costs one state". * fix(confidential): key spender-transfer pads to the fresh allowance salt A reverted `confidential_transfer_from` leaves the delegation entry untouched, so the stored `sigma_a` recurred on the retry along with the ephemeral scalar and every channel pad derived from it, O_a9's lane[2] included; a retry that changed the amount published the difference in the clear. O7, O9, O_a2 and O_a6 now absorb the prover-chosen `sigma_a'`, which `SpenderTransfer` emits in place of the stored salt, and `SetSpender` drops its salt since no auditor path reads either. Documents the rotation assert as O14 and regenerates the spender-transfer VK and fixtures. * docs(confidential): write sponge lanes as lane[i] instead of "lane N" Bare cardinals read as ordinals -- "lane 2" invites "second lane" when it means the third slot, index 2. Every specific-lane reference now uses the zero-based index notation, defined normatively in DESIGN.md 2.5, and the ambiguous [0..1] range in the prefix-property formulas is replaced by an explicit per-index equality.
* feat(confidential)!: make revoke_spender proofless Revocation folds the escrowed allowance commitment back into the owner's spendable commitment by homomorphic addition, exactly like merge (DESIGN §7.4). The escrowed amount was range-proven when the delegation was created and re-bounded on every spender transfer, and the next spend re-bounds the result, so the RevokeSpender circuit proved nothing the protocol did not already know. The auditor stays in sync because the escrowed r_a it holds from the delegation's last state change (S14 / O_a9) opens the folded commitment directly. BREAKING CHANGE: revoke_spender drops its `data` argument, the RevokeSpender event carries `(a_tilde, allowance_salt)` instead of the checkpoint fields, `on_revoke_spender` loses its payload, and CircuitType::RevokeSpender is removed. * docs(confidential): consolidate auditor rotation capability and fix stale revoke references Move the rotation decryption rule into DESIGN_cont §8.3 as its single normative site and reduce §8.1, §8.2 and §8.5 to pointers, adding the fact none of them stated: re-anchoring a rotated-in key is not one-time, since every later fold whose addend predates the rotation returns the holder to unopened. Correct the escrowed value named in revoke_spender's docs (r_a via S14/O_a9, not dvk_i), remove the phantom force_revoke_spender across five docs and storage.rs, drop the deleted V* constraint citations, and state the clawback precondition COMPLIANCE §5.3 constraint 2 needs. Assert the homomorphic fold in tests and collapse revoke_spender's duplicate account read. * test(confidential): cover revoking an expired delegation * docs(confidential): cite instead of restate around the proofless revoke Drops the Clawback references the core recovery text acquired (COMPLIANCE §5 is outline only), lets §9.5 account for RevokeSpender folds inside the anchor window, and trims the restated §7.9/§8.5 rationale to citations. * docs(confidential): cut restated sponge and salt-freshness claims in §2.5 The prefix property was derived twice and the width assignment restated a third time; the pad-freshness paragraph re-glossed $s$ and compressed the revert argument that §6.2 owns. State each once and cite the rest. * docs(confidential): deduplicate §5.2 and fix stale revoke claims §5.2 stated the checkpoint set three times and the per-event update rules twice; step 6 now cites the update table and carries only the replay-specific skip rules. Corrects the spendable-side recovery claims in DESIGN, INDEXER, SDK, and OVERVIEW, which omitted the post-checkpoint RevokeSpender fold. * docs(confidential): fold §5.3 Note into the r_e-reuse argument The Note duplicated DESIGN_cont §8.1's auditor channels and pre-stated the S14 caveat the next paragraph spelled out in full. Cite §8.1, §8.5 and §2.5 instead of restating them. * docs(confidential): fix salt-emission claims, restructure §6.2 transfer nonce Corrects the claim that the consumed allowance salt never reaches events: `SpenderTransfer` emits its replacement as `sigma_a_new`, so the salt a later revoke folds against sits in the preceding transfer's event. Restructures the transfer-nonce subsection motivation-first and trims restated constraint rationale across §7.5-§7.9. * docs(confidential): deduplicate §8 auditor sections Cut restated prose across §8.1-§8.5 in favour of citations: the lane[2] slot description folds into DESIGN §2.5, and the rotation, pad-freshness, mode-exclusivity, and cost claims now cite §8.3, §5.3, §2.5, and §10.3 instead of restating them. Also retargets a stale §5.5 cross-reference for the auditor's encrypted scalar to §8.1. * docs(confidential): prose style * docs(confidential): fix typo flagged by CI `unparseable` -> `unparsable`.
* feat(confidential): add compliance clawback Adds the opt-in `ConfidentialClawback` trait (`clawback`, `force_revoke_spender`), the clawback Noir circuit with `CircuitType::Clawback = 6`, and its specification in COMPLIANCE.md §5 written against the `r_a`-escrow auditor model. * docs(confidential): review prose * docs(confidential): specify blinding accumulation in the SDK DESIGN.md and SDK.md disagreed on whether W_spend.r is reduced per fold; SDK.md §4.6, §10.1 and §10.7 now own the rule, requiring exact-integer accumulation with a single mod-q reduction at the curve boundary and testing encodability on the reduction rather than the accumulator. DESIGN.md §5.2 keeps only the cross-reference, and DESIGN_cont.md §10.4 gains clawback in its fold list. * docs(confidential): add Clawback event in the table * refactor(confidential): number the Clawback circuit at 100 Core circuits keep 0..=4; circuits shipped by optional extensions start at 100. Drops the retired-discriminant note. * docs(confidential): tighten compliance module docs Name what each sentence refers to instead of "gates on it"/"that", spell out `destination` in the None/Some(d) settlement cases, and drop idioms and a duplicated inline comment, per review on #855.
* support rwa muxed address * optimizations Co-authored-by: Yigit Can Gokmen <yigitcangokmen98@gmail.com>
* fix(confidential): bind auditor key in clawback * fix(confidential): bind a per-account nonce into clawback proofs A seizure's public inputs were fully restorable — a deposit and merge of `alpha` return the commitments to their pre-seizure values — so an approved proof could execute again. The account's clawback nonce is now a public input and advances on every seizure. * docs(confidential): note that the clawback destination is not gated COMPLIANCE.md §5.4 owns the claim; the two clawback docstrings state it and cite the section.
* fix(fee-abstraction): consume the whole eager approval in collect_fee Eager mode approved max_fee_amount but spent only fee_amount, so the unspent allowance survived into the arbitrary target invocation and could be drained by a later forward. Pull max_fee_amount, pay the fee and refund the remainder so no allowance is left behind. * tests: events Co-authored-by: knQzx <75641500+knQzx@users.noreply.github.com>
* docs(confidential): align SDK and SELECTIVE_DISCLOSURE with DESIGN
Witness assembly now names all six circuits, drawn-scalar and
citation lists match DESIGN, and the D-auditor sponge reads each
channel at its fixed width. DESIGN_cont §11 corrects struct-field
order to the sorted form the contracttype macro emits.
* docs(confidential): split the specification into a topic-per-file tree
Mechanical move of DESIGN, DESIGN_cont, SDK, SELECTIVE_DISCLOSURE, COMPLIANCE, INDEXER, and OVERVIEW into docs/{protocol,sdk,selective-disclosure}/ and lower-case single files. Headings are de-numbered and re-levelled and cited bold labels become headings; body text is unchanged. Citations still use the old section numbers and are rewritten in the next commit.
* docs(confidential): cite the specification by path and anchor
Every section-number citation in the docs, the Rust and Noir comments, and the agent guides becomes a relative path with a GitHub heading anchor. docs/README.md maps the set, and docs/check_links.py, run by the new docs workflow, fails CI on a missing file or heading, a duplicate anchor within a file, or a file over the LaTeX rendering budget.
* docs(confidential): give each duplicated fact one home
The recovery procedure, checkpoint set, and T0 anchor are stated only in protocol/wallet-state.md; the domain-tag table lives only in protocol/domain-separators.md, now with the layer that absorbs each tag; the per-lane auditor map moves into protocol/auditing.md; the overview and the SDK cite these instead of restating them. ACIR opcode counts are no longer quoted in prose, leaving circuits/constraints.baseline as their only record.
* docs(confidential): use one math style
Drop the markdown-only backslash escape before subscripts inside math spans, which GitHub renders identically with and without (checked through its markdown API), keep LaTeX's own escaped underscore inside \text{}, and lift overview.md's single-dollar spans to $$. Citations that sat inside \text{} become plain section titles.
* ci(confidential): check documentation references with lychee
Replace the bespoke checker with lychee-action over the module's Markdown plus a generated link list of the Rust, Noir, and guide citations. The one heading that carried LaTeX now uses a code span, since lychee and GitHub slug math differently.
* docs(confidential): give the specification a reading path
The split left the index author-facing, overview.md unreachable from any path, and no file pointing to the next one. The index now opens with where to start, every file ends with previous/up/next links, and the operations index lists its operations in order.
* docs(confidential): point footers at their map subsection
Footers now read "Index" and anchor to the README subsection that lists
the file: #protocol for the specification, #companions for the rest.
* docs(confidential): escape subscripts so GitHub renders the math
GitHub parses a `$$…$$` span's contents with its markdown inline parser before
MathJax sees them, so an unescaped `_` flanked by punctuation pairs with the next
one in the same paragraph and the resulting `<em>` destroyed both spans. 187 of
1756 spans rendered as literal text; the escape is stripped again on the way to
MathJax, so `\_` still arrives as a subscript.
* ci(docs): restrict workflow token to contents: read
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix: coderabbit suggestions
* docs(confidential): tidy protocol README front matter
List the protocol files as bullets, rename the third Approach item to "Dual-balance model", and drop the CAP-80 aside from the abstract.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs(confidential): specify the per-role aggregate disclosure circuits
The aggregate spec only tabulated the D-recipient shape, so the D-sender aggregate it prescribed could not be assembled (#849). Each role now has per-event inputs, witnesses, and constraints, with per-event keys so an aggregate may span accounts; padding, threshold agreement, the auditor channel, and the decrypt domain are pinned down as well.
* feat(accounts): commit signers to a structured AuthDigestPreimage Signers now commit to an AuthDigestPreimage of the smart account address, the host signature payload, and the selected context rule IDs. External signers sign its SHA-256 digest, and delegated signers authorize the struct through require_auth_for_args, so their auth entry carries named fields instead of an opaque hash. * fix(accounts): re-export getters * feat(accounts): expose auth_digest and test real authorization entries Add an `auth_digest` view so `AuthDigestPreimage` enters the contract spec and clients can verify a digest through simulation. New tests build the smart account's and the delegated signer's authorization entries by hand and drive them through the host's `__check_auth`. Document the client-side flow and the entry that simulation does not return. * fix: typo * fix: export get_validated_context_by_id
* uniform contract type composition via Compose Select the ContractType uniformly by listing what the token is made of: `type ContractType = Compose<(AllowList,)>`, for every fungible and non-fungible contract type. Resolution is a type-level pairwise fold, so additive extensions (`Burnable`, `Royalties`) may be listed as well: they are ignored by the resolution (an additive-only list resolves to `Base`), letting developers list every extension they use without knowing which ones override behavior and which merely add it. Invalid lists fail at compile time with curated diagnostics naming the offending pair. No behavioral change: every list resolves to an already existing contract type, and all examples, README snippets, trait docs and Architecture.md are converted to the uniform form. Also fixes stale trait-doc bullet lists (missing Vault/FungibleVotes/NonFungibleVotes, incorrect NonFungibleBurnable incompatibility claims).
* make votes work with enumerable and consecutive
* consecutive and royalty support
…s drained A zero-balance recovery target could be removed and re-registered under another identity before the old wallet's tokens were recovered, so a later recover_balance moved them under the wrong identity and MaxBalance skipped the debit/credit as a same-identity transfer. The IRS now keeps a RecoveredFrom link and rejects removing or re-recovering a target while its old wallet still holds a balance in a linked token (IRSError::PendingRecovery).
…ated per wallet Sibling wallets of one identity each carry their own country data and nothing reconciles them, so a jurisdiction change is applied by the operator to every wallet registered under that identity.
|
Important Review skippedToo many files! This PR contains 180 files, which is 30 over the limit of 150. To get a review, reduce the PR to 150 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to Team to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Essentials Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (180)
You can disable this status message by setting the Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
fix #886