Skip to content

docs: surface known trust boundaries in Vault, MultiToken, Dripper - #35

Draft
alejoamiras wants to merge 1 commit into
mainfrom
stack/closeout-warnings
Draft

docs: surface known trust boundaries in Vault, MultiToken, Dripper#35
alejoamiras wants to merge 1 commit into
mainfrom
stack/closeout-warnings

Conversation

@alejoamiras

@alejoamiras alejoamiras commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Part of a 4-PR all-or-nothing stack (#35#36#37#38) closing the implementation half of the 2026-08 security audit. All are drafts and are proposed as one unit — please review the stack as a whole rather than merging pieces. The Vault Critical (reentrancy) is deliberately NOT fixed here — see the stack summary in #38.

Documentation only. No contract logic changes.

Vault — the ordering comments asserted a guarantee the code does not provide

main.nr carries ~15 // Order matters: … to neutralize ARC-403 reentrancy comments. That reasoning holds only if a token transfer is indivisible. It isn't: when the asset or shares token has an ARC-403 hook, the hook runs inside the transfer, before the balance moves, so it observes the vault mid-operation — the exact state the ordering exists to exclude (audit F-001/F-002).

Added one authoritative block comment at the top of the contract, and corrected the recurring inline phrase (16 sites) from "to neutralize ARC-403 reentrancy" to "to order effects safely (necessary but not sufficient against a hooked token — see the note at the top)". The two enqueue settlement first… comments were left as-is: they describe total_supply ordering, not a reentrancy guarantee, and are accurate.

MultiToken — status warning

It had no per-file caveat while carrying the commitment trust-model issue (a commitment binds neither id nor amount, so it is not a payment guarantee).

Deliberately severity-accurate: it references the repo-wide unaudited status and points at the trust model, rather than copying the Vault's "not production-ready" language. Token and NFT also have no per-file banner — a Vault-style warning here would wrongly rank MultiToken below its clean siblings.

Dripper — name the mechanism

The existing "development and testing only" note didn't say why it matters. Now states it is an uncapped, permissionless minter whose only safety boundary is never being granted minter on a token that holds real value (audit F-006).

Validation

aztec-nargo fmt --check clean · aztec compile OK.

Documentation follow-ups from the 2026-08 security audit. No contract
logic changes.

- Vault (main.nr): a prominent block comment at the top records that the
  ~15 `Order matters: … reentrancy` orderings are necessary but NOT
  sufficient — they do not hold when the asset or shares token has an
  ARC-403 hook, because the hook runs inside the transfer before the
  balance moves (audit F-001/F-002). The recurring inline phrase
  "to neutralize ARC-403 reentrancy" asserted a guarantee the code does
  not provide; corrected to point at that note.
- MultiToken (README): add a status warning. It was the only token
  contract with no per-file caveat, yet it carries the commitment
  trust-model issue (a commitment binds neither id nor amount, so it is
  not a payment guarantee). Kept severity-accurate: it references the
  repo-wide unaudited status rather than implying it is as unfinished as
  the Vault.
- Dripper (README): the existing "dev/testing only" note did not name
  the mechanism. Sharpened to state it is an uncapped, permissionless
  minter whose sole safety boundary is never being a valuable token's
  minter (audit F-006).

Validated: aztec-nargo fmt --check clean, aztec compile OK.
@alejoamiras
alejoamiras force-pushed the stack/closeout-warnings branch from decb90a to 441e309 Compare August 19, 2026 16:16
@github-actions

Copy link
Copy Markdown

Benchmark Comparison

CPU Cores RAM Arch
AMD EPYC 9V74 80-Core Processor 4 16 GiB x64

Contract: escrow

🚦 Function Gates DA Gas L2 Gas Proving Time (ms)
Base PR Diff Base PR Diff Base PR Diff Base PR Diff
(partial) withdraw 485,780 485,780 3,744 3,744 587,800 587,800 11,708 15,113 +3,405 (+29.1%)
withdraw 330,054 330,054 832 832 499,700 499,700 9,443 12,208 +2,765 (+29.3%)
withdraw_nft 378,231 378,231 1,440 1,440 527,400 527,400 10,382 13,371 +2,989 (+28.8%)

Contract: logic

🚦 Function Gates DA Gas L2 Gas Proving Time (ms)
Base PR Diff Base PR Diff Base PR Diff Base PR Diff
get_escrow 390,336 390,336 192 192 456,000 456,000 10,510 13,655 +3,145 (+29.9%)
secret_key_to_public_keys 387,695 387,695 192 192 456,000 456,000 10,464 13,517 +3,053 (+29.2%)
share_escrow 304,211 304,211 1,952 1,952 520,700 520,700 9,263 12,071 +2,808 (+30.3%)

Contract: multitoken

🚦 Function Gates DA Gas L2 Gas Proving Time (ms)
Base PR Diff Base PR Diff Base PR Diff Base PR Diff
burn_private 260,232 260,232 832 832 499,700 499,700 8,493 10,986 +2,493 (+29.4%)
burn_public 223,800 223,800 416 416 638,292 638,292 8,171 10,567 +2,396 (+29.3%)
initialize_transfer_commitment 225,054 225,054 768 768 474,500 474,500 8,106 10,551 +2,445 (+30.2%)
mint_to_private 297,795 297,795 1,408 1,408 511,400 511,400 9,199 11,921 +2,722 (+29.6%)
mint_to_public 223,800 223,800 416 416 637,800 637,800 8,132 10,524 +2,392 (+29.4%)
transfer_private_to_commitment 263,571 263,571 1,024 1,024 511,400 511,400 8,535 10,974 +2,439 (+28.6%)
transfer_private_to_private 336,124 336,124 2,048 2,048 555,100 555,100 9,550 12,397 +2,847 (+29.8%)
transfer_private_to_public 306,785 306,785 1,056 1,056 714,677 714,677 9,244 11,864 +2,620 (+28.3%)
transfer_public_to_commitment 223,800 223,800 640 640 663,516 663,516 8,192 10,575 +2,383 (+29.1%)
transfer_public_to_private 298,556 298,556 1,024 1,024 683,958 683,958 9,129 11,775 +2,646 (+29.0%)
transfer_public_to_public 223,800 223,800 480 480 673,505 673,505 8,177 10,544 +2,367 (+28.9%)

Contract: nft

🚦 Function Gates DA Gas L2 Gas Proving Time (ms)
Base PR Diff Base PR Diff Base PR Diff Base PR Diff
burn_private 275,232 275,232 416 416 661,052 661,052 8,898 11,518 +2,620 (+29.4%)
burn_public 223,800 223,800 448 448 670,034 670,034 8,152 10,627 +2,475 (+30.4%)
mint_to_private 341,272 341,272 1,600 1,600 735,342 735,342 9,669 12,548 +2,879 (+29.8%)
mint_to_public 223,800 223,800 448 448 670,718 670,718 8,137 10,562 +2,425 (+29.8%)
transfer_private_to_private 249,433 249,433 832 832 499,700 499,700 8,364 10,910 +2,546 (+30.4%)
transfer_private_to_public 275,261 275,261 416 416 659,258 659,258 8,856 11,551 +2,695 (+30.4%)
transfer_public_to_private 292,557 292,557 992 992 683,268 683,268 9,033 11,754 +2,721 (+30.1%)
transfer_public_to_public 223,800 223,800 384 384 633,285 633,285 8,137 10,590 +2,453 (+30.1%)

Contract: token

🚦 Function Gates DA Gas L2 Gas Proving Time (ms)
Base PR Diff Base PR Diff Base PR Diff Base PR Diff
burn_private 303,054 303,054 1,024 1,024 713,957 713,957 9,174 11,881 +2,707 (+29.5%)
burn_public 223,800 223,800 448 448 672,632 672,632 8,149 10,547 +2,398 (+29.4%)
initialize_transfer_commitment 225,054 225,054 768 768 474,500 474,500 8,121 10,583 +2,462 (+30.3%)
mint_to_private 355,507 355,507 2,144 2,144 738,070 738,070 9,870 12,795 +2,925 (+29.6%)
mint_to_public 223,800 223,800 448 448 672,227 672,227 8,128 10,693 +2,565 (+31.6%)
transfer_private_to_commitment 259,896 259,896 992 992 511,400 511,400 8,506 11,024 +2,518 (+29.6%)
transfer_private_to_private 343,699 343,699 2,592 2,592 557,600 557,600 9,712 12,564 +2,852 (+29.4%)
transfer_private_to_public 303,110 303,110 1,024 1,024 714,023 714,023 9,174 11,931 +2,757 (+30.1%)
transfer_private_to_public_with_commitment 307,280 307,280 1,600 1,600 747,323 747,323 9,218 11,984 +2,766 (+30.0%)
transfer_public_to_commitment 223,800 223,800 576 576 662,529 662,529 8,155 10,538 +2,383 (+29.2%)
transfer_public_to_private 296,520 296,520 992 992 683,304 683,304 9,063 11,810 +2,747 (+30.3%)
transfer_public_to_public 223,800 223,800 448 448 672,548 672,548 8,157 10,597 +2,440 (+29.9%)

Contract: vault

🚦 Function Gates DA Gas L2 Gas Proving Time (ms)
Base PR Diff Base PR Diff Base PR Diff Base PR Diff
deposit_private_to_private 507,983 507,983 1,312 1,312 878,248 878,248 11,947 15,477 +3,530 (+29.5%)
deposit_private_to_private_exact 611,708 611,708 1,888 1,888 915,316 915,316 13,531 17,582 +4,051 (+29.9%)
deposit_private_to_public 435,487 435,487 768 768 862,273 862,273 11,029 14,292 +3,263 (+29.6%)
deposit_public_to_private 424,931 424,931 1,984 1,984 965,045 965,045 10,993 14,160 +3,167 (+28.8%)
deposit_public_to_private_exact 424,942 424,942 1,952 1,952 949,469 949,469 10,924 14,220 +3,296 (+30.2%)
deposit_public_to_public 223,800 223,800 832 832 897,563 897,563 8,137 10,573 +2,436 (+29.9%)
issue_private_to_private_exact 611,708 611,708 1,888 1,888 915,976 915,976 13,518 17,546 +4,028 (+29.8%)
issue_private_to_public_exact 484,222 484,222 1,344 1,344 899,998 899,998 11,685 15,181 +3,496 (+29.9%)
issue_public_to_private 346,383 346,383 1,376 1,376 921,661 921,661 9,723 12,699 +2,976 (+30.6%)
issue_public_to_public 223,800 223,800 832 832 898,253 898,253 8,165 10,543 +2,378 (+29.1%)
redeem_private_to_private_exact 614,712 614,712 1,888 1,888 915,823 915,823 13,564 17,515 +3,951 (+29.1%)
redeem_private_to_public 435,430 435,430 768 768 862,717 862,717 11,041 14,259 +3,218 (+29.1%)
redeem_public_to_private_exact 428,003 428,003 1,952 1,952 949,790 949,790 10,974 14,220 +3,246 (+29.6%)
redeem_public_to_public 223,800 223,800 832 832 898,085 898,085 8,148 10,519 +2,371 (+29.1%)
withdraw_private_to_private 510,987 510,987 1,312 1,312 878,458 878,458 11,984 15,448 +3,464 (+28.9%)
withdraw_private_to_private_exact 614,712 614,712 1,888 1,888 915,769 915,769 13,536 17,522 +3,986 (+29.4%)
withdraw_private_to_public_exact 484,165 484,165 1,344 1,344 900,232 900,232 11,668 15,102 +3,434 (+29.4%)
withdraw_public_to_private 441,260 441,260 2,528 2,528 967,356 967,356 11,089 14,369 +3,280 (+29.6%)
withdraw_public_to_public 223,800 223,800 832 832 898,388 898,388 8,190 10,525 +2,335 (+28.5%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant