@odatano/nightgate v0.10.0
@odatano/nightgate 0.10.0 (2026-07-24)
- AttestationVault passport hardening in ONE contract change (one redeploy):
bindPassportrebind-takeover guard + registrar-gated pre-registration
(registerPassport) against first-bind squatting. - Deterministic batch apply order:
submitContractCallBatchrewrites segment
ids into call order before proving, so DEPENDENT calls run as one
transaction. Lifts the 0.9.3 order-independence restriction.
Highlights
bindPassport rebind-takeover guard
passport_bindings.insertoverwrites and onlypayload_hashownership was
checked, so any attester could re-bind a bound passportId onto their own
attestation and hijack the QR resolution (same takeover class as the 0.6.1
attest()fix). An already-bound, unregistered id now re-binds only for
the owner of its currently bound attestation; same-owner rebinding stays
allowed.
Registrar-gated pre-registration (registerPassport)
- A new constructor locks the DEPLOYER's attester identity as
registrar;
the registrar-only circuitregisterPassport(passportId, owner_id)fills
passport_owners. Registered ids bind/re-bind ONLY for their registered
attester: blocks first-bind squatting and recovers a squatted id (registrar
re-points it, the owner rebinds over the foreign binding). Unregistered ids
stay first-come-first-served (squattable by design). - New OData action
registerPassport(...): async job like
grant/revokeDisclosure (30/h per session), result
{ passportId, ownerId, contractAddress, txHash }. Browser helper
prepareRegisterPassport.
Deterministic batch apply order (submitContractCallBatch)
- The SDK randomizes each call's segment id while the ledger applies merged
intents in ascending segment order, so a dependent batch only landed by
luck (~1/3). NIGHTGATE now rewrites the batch's existing segment ids into
call order before proving (ledger-v8recomputes binding);
attest->bindPassport->anchorContentRootruns as ONE tx. - Fail-closed: if the ordering cannot be established for a multi-call batch,
the submission aborts BEFORE proving (nothing submitted) instead of
silently proving in randomized order. Duplicate circuit names keep a random
relative order among themselves. Newsrv/midnight/batch-segment-order.ts.
Notes
- Recompiled
managed/artifact (compactc 0.31.0), now 9 circuits
(anchorContentRoot/proveFieldPredicatekeys shifted too). No CDS schema
change. The deploying session's secret defines the registrar: deploy from
the session that should manage passport ownership. - Consumer action (NIGHTPASS): redeploy the vault. A redeployed vault
starts with an EMPTY ledger: switch the contract address AND re-create
needed state (attest, bindPassport, anchorContentRoot, grants), ideally
registering known passport ids first, otherwise QR resolution appears
lost. - Job-pool fix:
grantDisclosure/revokeDisclosure/registerPassportnow
run in the HEAVY pool (full ZK proof generation; light since 0.9.0 was an
oversight). - Verified: 68 suites / 1231 tests + 34-check contract regression script,
and TWO full live rounds on preprod (fresh vaults81576468…/da9b0bcf…):
deploy, first-try dependent 3-call batch with on-chain SUCCESS
(txs86bc9a0b…/4db4dea6…),registerPassport, bind on the registered
id. Two first-try batches had ~11% combined odds under the old randomized
order; the statistical 6/6-vs-0/6 stress proof runs consumer-side.