mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
main
19
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
84587ddb0f |
Resolve the market before a swap can name a halt
SettleSwap took the caller's PoolKey and never asked whether that pool existed, so key.ID() fed the halt slot, the volume shard and the fill event alike. A fabricated key names a slot nobody set, and the swap settles while the real market is halted. Resolving once above the phase switch and passing the resolved poolID down means no phase -- including one added later -- can key on anything the registry has not admitted. checkHalt no longer accepts a key, so it cannot derive one. Co-authored-by: Hanzo Dev <[email protected]> |
||
|
|
1362566d34 |
Merge github/main into the hardening branch
Both sides carried work. Ours is the security pass: the stableswap amp=0 and empty-pool halts, the wei-per-swap leak, uint256 truncation in math, three verifiers that returned a verdict without verifying, the cgo/non-cgo consensus split in cggmp21, and the starkfri soundness floor. Theirs is the fhe parameter set, the mldsa crafted-length refusal, and the naming sweep. Resolved per hunk rather than by side. Where both fixed one defect the better fix survives alone, never two guards for one bug. |
||
|
|
e0a77cceaf |
dex: the comments described a seam that no longer exists
Co-authored-by: Hanzo Dev <[email protected]> |
||
|
|
42d2759b52 |
wip: drop order/slippage code the funding rail no longer reaches
Co-authored-by: Hanzo Dev <[email protected]> |
||
|
|
f8ca4a37be |
wip: C-side funding rail un-braid (build green)
Co-authored-by: Hanzo Dev <[email protected]> |
||
|
|
2391e31aaa |
dex: the seam's unit of work is an order, not an intent
Order -> Match -> Execution -> Trade is the vocabulary; "intent" was the old
name for what an Order is. Renames the identifiers across the 0x9999 settle
precompile so the code reads in the settled terms.
Values that live on a chain keep their bytes, because renaming one of those is
a migration and not a rename:
- "lux.dex.native.intent.v1" and "lux.dex.native.intent.pending.v2" are hash
INPUTS; a byte changed there moves every derived order id and the pending
trait both repos must agree on.
- settleStateNamespace + "intent" is an on-disk key prefix; renaming it
orphans the submitted-order replay set.
- reclaimIntent(bytes32), IntentSubmitted(...) and IntentReclaimed(...) are
the deployed ABI; the signature is what hashes, so a rename would move a
selector and two topics.
Each of those now carries one line saying why the literal does not track the
identifier that names it, so the inconsistency is not "fixed" later.
TestOrderID_CrossRepoGolden still reads 5b0e8d38... and
TestSeamPendingTrait_MatchesDChainGolden still reads 5f10f9ad..., which is the
evidence no derivation input moved.
Co-authored-by: Hanzo Dev <[email protected]>
|
||
|
|
fd1cc0904e |
dex: carry the cross-chain object in the transaction, not shared memory
A settled swap could never be synced past. Both C-side consume paths (ImportSettlement, ImportPositionCollect) read the D->C object from shared memory DURING EVM execution, while the consuming Remove landed at block Accept. A node re-executing that block — bootstrapping, state-syncing, re-tracing — found the object gone, computed a reverted receipt where the network had computed a successful one, and died on the receipt root. The seam settled live and wedged every node that tried to follow. Move the object's 69 bytes into the transaction (Phase-B hookData, and the collectPosition calldata) so execution is a pure function of the block and replays byte-identically forever. Both rails now go through ONE binding primitive, bindImportObject, which also DECLARES the consumption as a log committing to the object's hash. The host authenticates that declaration against shared memory at Block.Verify, so a forged object costs the producer a block instead of forking a receipt root. The ship rule did not weaken, it moved: a C balance is still credited only by consuming a real D->C object. What changed is where that is proven. Also: - amount is no longer restated on the wire; it IS the object's amount, so there is one declaration of the fact instead of two to cross-check. - the retired DS01 tag is refused BY NAME. The fallback for an unknown tag is Phase A, so a stale settle would otherwise have been silently re-read as an intent and LOCKED the sender's input — the one mixed-fleet outcome worse than a revert. - the zero-amount refusal moved into the single binding point, so an absent object zero-padded to canonical width reports the same clear error on both rails rather than surfacing as a cross-rail violation. 336 tests pass, 0 fail. Co-authored-by: Hanzo Dev <[email protected]> |
||
|
|
af68fed375 |
dex: decomplect to canonical settle-only 0x9999 (remove embedded matcher)
ONE money path: D-Chain matches, C-Chain 0x9999 SETTLES, C never matches. - 0x9999 swap() routes ONLY to SettleSwap (native C<->D atomic seam): untagged/ DI01 => Phase A intent (lock input, write C->D object, return intent id); DS01 => Phase B settlement (consume a real D->C atomic object once, credit RECORDED amount). No-receipt-no-settle: absent a real object, Phase B reverts ErrNativeNoSettlement (TestDecomplect_NoReceiptNoSettle). - Deleted the embedded matcher: swap_sync*.go, swap_custody.go (maker order book), buildRouter/evmAMMPool in swap_amm_pool.go, and the swapDeposit/withdraw/place/ cancel selectors. A live in-trie matcher forks consensus; deterministic atomic-object consumption is fork-safe inline. - 0x9010 already non-dispatched. 0x9012 (LXRouter) value selectors exactInput*/ exactOutput* now revert ErrPrecompileMoved (PRECOMPILE_MOVED); read-only quote/ route views kept. - Cleanups (dead code removal, all unreachable via any dispatched selector): deleted the legacy engine PoolManager.Swap + LXRouter.Exact*/executeV4Swap*; deleted the vestigial makerLockedVault ledger (0 callers, always 0); deleted the unwired Block-STM scaffolding (AssertWriteSetWithin/AccessCommitment/Predict*). - Activation rides the EXISTING canonical gate 1766708400 (Dec 25 2025 16:20 PST); no new timestamp. Build CGO_ENABLED=0 (pure-Go luxfi/dex path); go.sum zap re-tag checksum refreshed. 327 dex tests PASS / 0 FAIL, go vet clean. RED-reviewed (0 critical, all drain vectors safe, fund-strand cleared, negative invariant falsified-then-restored). Co-authored-by: Hanzo Dev <[email protected]> |
||
|
|
844f3d3587 |
dex: decomplect to canonical settle-only 0x9999 (remove embedded matcher)
ONE money path: D-Chain matches, C-Chain 0x9999 SETTLES, C never matches. - 0x9999 swap() routes ONLY to SettleSwap (native C<->D atomic seam): untagged/ DI01 => Phase A intent (lock input, write C->D object, return intent id); DS01 => Phase B settlement (consume a real D->C atomic object once, credit RECORDED amount). No-receipt-no-settle: absent a real object, Phase B reverts ErrNativeNoSettlement (TestDecomplect_NoReceiptNoSettle). - Deleted the embedded matcher: swap_sync*.go, swap_custody.go (maker order book), buildRouter/evmAMMPool in swap_amm_pool.go, and the swapDeposit/withdraw/place/ cancel selectors. A live in-trie matcher forks consensus; deterministic atomic-object consumption is fork-safe inline. - 0x9010 already non-dispatched. 0x9012 (LXRouter) value selectors exactInput*/ exactOutput* now revert ErrPrecompileMoved (PRECOMPILE_MOVED); read-only quote/ route views kept. - Cleanups (dead code removal, all unreachable via any dispatched selector): deleted the legacy engine PoolManager.Swap + LXRouter.Exact*/executeV4Swap*; deleted the vestigial makerLockedVault ledger (0 callers, always 0); deleted the unwired Block-STM scaffolding (AssertWriteSetWithin/AccessCommitment/Predict*). - Activation rides the EXISTING canonical gate 1766708400 (Dec 25 2025 16:20 PST); no new timestamp. Build CGO_ENABLED=0 (pure-Go luxfi/dex path); go.sum zap re-tag checksum refreshed. 327 dex tests PASS / 0 FAIL, go vet clean. RED-reviewed (0 critical, all drain vectors safe, fund-strand cleared, negative invariant falsified-then-restored). Co-authored-by: Hanzo Dev <[email protected]> |
||
|
|
b362c1758e |
feat(0x9999): synchronous on-chain router — Gate B (joint C+D journal, real-asset settle, DEXFill event, full test suite)
0x9999.swap routes one swap across on-chain liquidity in-process and atomically:
V4 native CLOB first, falls to V2/V3 AMM when CLOB depth is insufficient, best-exec
split across both. The C balance delta and the D book/fill delta land in ONE joint
journal committed in a SINGLE cEVM block — both-or-revert-both under one EVM snapshot.
No async C->D->C, no live ZAP in Verify, no keeper, no external venue. Real ERC-20s
only (assetID = real token address); the 0x9999 vault holds the real tokens, settled
no-mint conservation-checked.
- swap_sync.go: syncSwap handler (buildSwapRequest -> dexcore.ExecuteSwap -> applyJournalC),
value-swaps gate (fail-closed unless quorum-finality engine), DEXFill C-event on the
sync money path (gated dexLogsActive — same activation fork as the async path).
- swap_amm_pool.go: V2/V3 AMM fallthrough bound to 0x9999-stored reserve rows (BindAMMPool).
- swap_custody.go: maker deposit/place/cancel/withdraw over the dexcore ledger.
- settle_module.go: dispatch untagged swap + value-enabled -> runSyncSwap; else async.
Tests (real assets, no stubs): Test9999SyncSwap_{CAndDCommitAtomically, RevertRollsBackCAndD,
ValueGateFailsClosed, ValidatorReplayNoLiveZAP, FakeProposerFillRejected,
TradeVisibleInDStateAndCEvents, ERC20ObservedDelta, NonReentrant, AMMLegMovesRealERC20EndToEnd};
Test9999Routes{CLOBWhenDepth,V3WhenCLOBEmpty}; Test9999BestExecSplitCLOBAndAMM;
Test{HFTAndEVMUseSameBook,NativeMakerEVMTaker,EVMMakerNativeTaker}SameState;
TestNo{LiveZAPSettlement,KeeperSettlementPath,VenueFallback}; TestE2E_SyncSwap_MakerRestsTakerSwaps
(native maker + EVM taker, real ERC-20, fill once, restart preserves, conservation+ownership).
Atomicity proven through a faithful EVM-snapshot boundary: MockStateDB gets a real
Snapshot/RevertToSnapshot (deep-clone) + runWithEVMSnapshot mirroring geth evm.go Call,
so a reverted swap rolls back BOTH C and D — the real production property, not a stub.
|
||
|
|
2936914451 |
feat(0x9999): synchronous on-chain router — Gate B (joint C+D journal, real-asset settle, DEXFill event, full test suite)
0x9999.swap routes one swap across on-chain liquidity in-process and atomically:
V4 native CLOB first, falls to V2/V3 AMM when CLOB depth is insufficient, best-exec
split across both. The C balance delta and the D book/fill delta land in ONE joint
journal committed in a SINGLE cEVM block — both-or-revert-both under one EVM snapshot.
No async C->D->C, no live ZAP in Verify, no keeper, no external venue. Real ERC-20s
only (assetID = real token address); the 0x9999 vault holds the real tokens, settled
no-mint conservation-checked.
- swap_sync.go: syncSwap handler (buildSwapRequest -> dexcore.ExecuteSwap -> applyJournalC),
value-swaps gate (fail-closed unless quorum-finality engine), DEXFill C-event on the
sync money path (gated dexLogsActive — same activation fork as the async path).
- swap_amm_pool.go: V2/V3 AMM fallthrough bound to 0x9999-stored reserve rows (BindAMMPool).
- swap_custody.go: maker deposit/place/cancel/withdraw over the dexcore ledger.
- settle_module.go: dispatch untagged swap + value-enabled -> runSyncSwap; else async.
Tests (real assets, no stubs): Test9999SyncSwap_{CAndDCommitAtomically, RevertRollsBackCAndD,
ValueGateFailsClosed, ValidatorReplayNoLiveZAP, FakeProposerFillRejected,
TradeVisibleInDStateAndCEvents, ERC20ObservedDelta, NonReentrant, AMMLegMovesRealERC20EndToEnd};
Test9999Routes{CLOBWhenDepth,V3WhenCLOBEmpty}; Test9999BestExecSplitCLOBAndAMM;
Test{HFTAndEVMUseSameBook,NativeMakerEVMTaker,EVMMakerNativeTaker}SameState;
TestNo{LiveZAPSettlement,KeeperSettlementPath,VenueFallback}; TestE2E_SyncSwap_MakerRestsTakerSwaps
(native maker + EVM taker, real ERC-20, fill once, restart preserves, conservation+ownership).
Atomicity proven through a faithful EVM-snapshot boundary: MockStateDB gets a real
Snapshot/RevertToSnapshot (deep-clone) + runWithEVMSnapshot mirroring geth evm.go Call,
so a reverted swap rolls back BOTH C and D — the real production property, not a stub.
|
||
|
|
c22f390d86 |
dex/0x9999: chain-observable intent id + MEV price-limit carry (swap-seam)
MEDIUM (watch correlation broken): the off-chain keeper/SDK derived the intent id with a ZERO txID (pre-landing) while the on-chain SubmitSwapIntent used the REAL txID — the ids never matched, so a keeper's watch could not correlate against a live chain. FIX: DeriveIntentID now binds (networkID,cChainID,dChainID,account,assetIn,amountIn,marketID, NONCE) with NO txID. The nonce is a taker-supplied disambiguator carried in the swap's DI01 hookData (settle_hookdata.go: deadline[32]|nonce[32]), so the off-chain and on-chain sides derive the IDENTICAL id from the IDENTICAL calldata. It replaces the former txID+callIndex axis (callIndex depended on the unknown-pre-signing txID ordering); the per-tx CallIndex host counter remains for other precompiles. Injectivity holds over (account+economic tuple+nonce); a reused tuple is replay-rejected (idempotent). aivmbridge.DeriveIntentID is a separate function (InferenceIntent) — unaffected. MEDIUM (native swap dropped SqrtPriceLimitX96 + no slippage floor): buildIntentRequest now carries the taker's worst-acceptable price into the intent. priceLimitToCLOB maps the V4 SqrtPriceLimitX96 to the CLOB quote-per-base domain (float64 bits) with the correct direction (zeroForOne SELL=floor, !zeroForOne BUY=ceiling; V4 sentinels => no limit). It rides the IntentSubmitted event so the keeper carries it onto the settling relay and the dexvm settle path refuses a fill worse than the limit (bounded sandwich/MEV). Tests (CGO_ENABLED=0): TestIntentID_OffChainEqualsOnChain (off==on, txID-independent), TestIntentID_DeterministicAndCollisionFreeAcrossNonces, TestDeriveIntentID_PureOnNonce, TestPriceLimitToCLOB_* / TestBuildIntentRequest_CarriesPriceLimit. Full dex suite green; parity (byte-identity with zap) intact. Extends fix/swap-rail-intent-record (97854ee). Within precompile v0.5.56. |
||
|
|
96fff4606c |
dex/0x9999: chain-observable intent id + MEV price-limit carry (swap-seam)
MEDIUM (watch correlation broken): the off-chain keeper/SDK derived the intent id with a ZERO txID (pre-landing) while the on-chain SubmitSwapIntent used the REAL txID — the ids never matched, so a keeper's watch could not correlate against a live chain. FIX: DeriveIntentID now binds (networkID,cChainID,dChainID,account,assetIn,amountIn,marketID, NONCE) with NO txID. The nonce is a taker-supplied disambiguator carried in the swap's DI01 hookData (settle_hookdata.go: deadline[32]|nonce[32]), so the off-chain and on-chain sides derive the IDENTICAL id from the IDENTICAL calldata. It replaces the former txID+callIndex axis (callIndex depended on the unknown-pre-signing txID ordering); the per-tx CallIndex host counter remains for other precompiles. Injectivity holds over (account+economic tuple+nonce); a reused tuple is replay-rejected (idempotent). aivmbridge.DeriveIntentID is a separate function (InferenceIntent) — unaffected. MEDIUM (native swap dropped SqrtPriceLimitX96 + no slippage floor): buildIntentRequest now carries the taker's worst-acceptable price into the intent. priceLimitToCLOB maps the V4 SqrtPriceLimitX96 to the CLOB quote-per-base domain (float64 bits) with the correct direction (zeroForOne SELL=floor, !zeroForOne BUY=ceiling; V4 sentinels => no limit). It rides the IntentSubmitted event so the keeper carries it onto the settling relay and the dexvm settle path refuses a fill worse than the limit (bounded sandwich/MEV). Tests (CGO_ENABLED=0): TestIntentID_OffChainEqualsOnChain (off==on, txID-independent), TestIntentID_DeterministicAndCollisionFreeAcrossNonces, TestDeriveIntentID_PureOnNonce, TestPriceLimitToCLOB_* / TestBuildIntentRequest_CarriesPriceLimit. Full dex suite green; parity (byte-identity with zap) intact. Extends fix/swap-rail-intent-record (97854ee). Within precompile v0.5.56. |
||
|
|
d30d0fcaf5 |
Thinking Chains: precompile (#7)
* dex/0x9999: per-intent swap escrow record — per-taker cap (MEDIUM) + deadline reclaim (HIGH) The swap rail lacked the LP rail's per-taker bound and any reclaim path: a swap's locked tokenIn was stranded forever if D never settled (Deadline hardcoded 0, no reclaim selector, SubmitCancel dead), and ImportSettlement bounded a credit only by the shared seamReserve — no per-taker cap, so an over-export for one taker could draw on others' pooled tokenIn. ONE new per-intent escrow record (native_state.go swapIntentRecord: owner, assetIn, remaining principal, deadline, status) drives BOTH fixes, created at SubmitSwapIntent — the swap-rail analog of the LP RestingOrder: MEDIUM (per-taker cap): ImportSettlement binds each settlement to the taker's OWN named Open intent (owner==recorded owner, not past deadline). The SAME-ASSET refund leg (recAsset==intent.AssetIn) is capped by + decrements the remaining locked principal (ErrSettleExceedsIntent) — the exact same-asset analog of ErrLPCollectExceedsPosition (the LP collects the asset it committed). The proceeds leg (opposite asset) is NOT input-unit-capped (output units differ from input at any price != 1 — an input-unit cap would wrongly refuse honest fills); its no-mint guard is seamReserve backing + one-time consumption + the intent binding. HIGH (reclaim liveness): a real non-zero Deadline is plumbed from an explicit DI01 intent-body word (V4 SwapParams tuple UNCHANGED) into the record. New reclaimIntent selector refunds the remaining locked principal from seamReserve to the locker once the deadline passes (one-time, deadline-gated; reclaim+late-settle are mutually exclusive via the shared remaining counter + terminal Reclaimed status; a compensating C->D Remove prevents D double-funding). So locked swap input can always exit, like deposit/withdraw. INFO: corrected the swap-rail-safety docstrings (settle9999.go, native_dchain_client.go, native_events.go) to state per-rail what C enforces vs relies on D for; fixed the false "reclaims via the cancel path" comment. Deleted the dead SubmitCancel/SubmitCollect client methods (the cancel/collect keeper events are emitted at their lifecycle sites; the swap reclaim is reclaimIntent). Regression: native_swap_intent_redteam_test.go (8 tests) — RefundBoundToOwnIntent Principal (MEDIUM cap), ProceedsNotCappedByInputPrincipal (dimension correctness), ReclaimRefundsStrandedPrincipal + ReclaimGuards + ReclaimAndSettleAreMutually Exclusive (HIGH), SettleRefusedPastDeadline, DeadlinePlumbedFromIntentBody, SettleMustNameAnOpenIntent. Full dex suite passes. Gated on red re-verify; NOT promoted to testnet/mainnet. * aivmbridge: C->A inference bridge precompile (0x0300..04). Pattern A submit-intent / Pattern B verify committed receipt (keccak-merkle). LP-5301. * aivmbridge: build-tag crossmodule parity test (CI green) The cross-module byte-equality test is the only file importing chains/aivm (resolvable only via go.work). Tag it `crossmodule` so default go test ./... (CI, no workspace) skips it; run with `go test -tags crossmodule` + workspace. Production aivmbridge stays decoupled (wire-format only). --------- Co-authored-by: zeekay <[email protected]> |
||
|
|
741b9a56df |
Thinking Chains: precompile (#7)
* dex/0x9999: per-intent swap escrow record — per-taker cap (MEDIUM) + deadline reclaim (HIGH) The swap rail lacked the LP rail's per-taker bound and any reclaim path: a swap's locked tokenIn was stranded forever if D never settled (Deadline hardcoded 0, no reclaim selector, SubmitCancel dead), and ImportSettlement bounded a credit only by the shared seamReserve — no per-taker cap, so an over-export for one taker could draw on others' pooled tokenIn. ONE new per-intent escrow record (native_state.go swapIntentRecord: owner, assetIn, remaining principal, deadline, status) drives BOTH fixes, created at SubmitSwapIntent — the swap-rail analog of the LP RestingOrder: MEDIUM (per-taker cap): ImportSettlement binds each settlement to the taker's OWN named Open intent (owner==recorded owner, not past deadline). The SAME-ASSET refund leg (recAsset==intent.AssetIn) is capped by + decrements the remaining locked principal (ErrSettleExceedsIntent) — the exact same-asset analog of ErrLPCollectExceedsPosition (the LP collects the asset it committed). The proceeds leg (opposite asset) is NOT input-unit-capped (output units differ from input at any price != 1 — an input-unit cap would wrongly refuse honest fills); its no-mint guard is seamReserve backing + one-time consumption + the intent binding. HIGH (reclaim liveness): a real non-zero Deadline is plumbed from an explicit DI01 intent-body word (V4 SwapParams tuple UNCHANGED) into the record. New reclaimIntent selector refunds the remaining locked principal from seamReserve to the locker once the deadline passes (one-time, deadline-gated; reclaim+late-settle are mutually exclusive via the shared remaining counter + terminal Reclaimed status; a compensating C->D Remove prevents D double-funding). So locked swap input can always exit, like deposit/withdraw. INFO: corrected the swap-rail-safety docstrings (settle9999.go, native_dchain_client.go, native_events.go) to state per-rail what C enforces vs relies on D for; fixed the false "reclaims via the cancel path" comment. Deleted the dead SubmitCancel/SubmitCollect client methods (the cancel/collect keeper events are emitted at their lifecycle sites; the swap reclaim is reclaimIntent). Regression: native_swap_intent_redteam_test.go (8 tests) — RefundBoundToOwnIntent Principal (MEDIUM cap), ProceedsNotCappedByInputPrincipal (dimension correctness), ReclaimRefundsStrandedPrincipal + ReclaimGuards + ReclaimAndSettleAreMutually Exclusive (HIGH), SettleRefusedPastDeadline, DeadlinePlumbedFromIntentBody, SettleMustNameAnOpenIntent. Full dex suite passes. Gated on red re-verify; NOT promoted to testnet/mainnet. * aivmbridge: C->A inference bridge precompile (0x0300..04). Pattern A submit-intent / Pattern B verify committed receipt (keccak-merkle). LP-5301. * aivmbridge: build-tag crossmodule parity test (CI green) The cross-module byte-equality test is the only file importing chains/aivm (resolvable only via go.work). Tag it `crossmodule` so default go test ./... (CI, no workspace) skips it; run with `go test -tags crossmodule` + workspace. Production aivmbridge stays decoupled (wire-format only). --------- Co-authored-by: zeekay <[email protected]> |
||
|
|
49fe03803c |
dex: native C<->D atomic settlement seam (0x9999) + Red fixes 2/3/4
The 0x9999 money path: V4 ABI swap -> NativeDChainClient -> C staged -> shared-memory export/import -> D dexvm atomic import/export (Mode A async, no BLS). C SETTLES, C never matches. Value crosses ONLY as a primary-network atomic shared-memory object. The BLS cert / VerifierRegistry / DFillReceipt value path is ripped (quarantined under dex/_deprecated_bls/). Ship rule (structural, not trust): C credited ONLY by consuming a D->C object (ImportSettlement); D funded ONLY by consuming a C->D object (SubmitSwapIntent -> dexvm executeImport). Atomic ops are STAGED in EVM state during execution (revert-aware) and flushed to shared memory at block accept over the deterministic parent->current seq window. contract.AtomicState: the optional host capability a precompile type-asserts to reach atomic shared memory (the platformvm/dexvm import/export primitive). Red fixes applied to the seam: FIX 2 (consensus-liveness chain-halt): native_staging.go FlushAcceptedAtomicOps already takes a batch; the flush is now one-batch-atomic at the host (see evm block.go/vm.go) — the SM Apply and the seq-marker advance commit all-or- nothing, closing the crash-between-Apply-and-marker -> duplicate-Put -> halt window. Regression: native_haltwindow_test.go (re-accept after a committed window is a clean no-op; crash-before-commit re-applies cleanly; the marker must ride the Apply batch). FIX 3 (conservation blast-radius): native_state.go adds seamReserve[a], the seam's OWN pot, decoupled from the depositor pot (settleVault) and the maker pot (makerLockedVault). lockIntentInput funds seamReserve; creditSettlementOutput checks+debits seamReserve. A settlement credit can never raid a depositor's claim; a withdraw can never strand a backed settlement. Invariant realHolding == settleVault + makerLockedVault + seamReserve. Regression: native_conservation_test.go (both subsystems, same asset). FIX 4 (reentrancy defense-in-depth): SettleSwap now takes the same single custody guard slot as deposit/withdraw/modifyLiquidity (enterCustodyKV), so the whole 0x9999 money surface is single-in-flight and an ERC-20 transfer callback cannot re-enter. Regression: native_callindex_test.go (callIndex determinism + intent-id collision-freedom across two swaps + a reverted sub-frame + a STATICCALL; SettleSwap non-reentrant + guard released for sequential calls). 305 prior + 10 new dex tests pass (CGO_ENABLED=0). Live-EVM-call-tree and live-crash-injection tests are CI-only (CGO + luxfi/accel LUXCPP). |
||
|
|
51828edc63 |
dex: native C<->D atomic settlement seam (0x9999) + Red fixes 2/3/4
The 0x9999 money path: V4 ABI swap -> NativeDChainClient -> C staged -> shared-memory export/import -> D dexvm atomic import/export (Mode A async, no BLS). C SETTLES, C never matches. Value crosses ONLY as a primary-network atomic shared-memory object. The BLS cert / VerifierRegistry / DFillReceipt value path is ripped (quarantined under dex/_deprecated_bls/). Ship rule (structural, not trust): C credited ONLY by consuming a D->C object (ImportSettlement); D funded ONLY by consuming a C->D object (SubmitSwapIntent -> dexvm executeImport). Atomic ops are STAGED in EVM state during execution (revert-aware) and flushed to shared memory at block accept over the deterministic parent->current seq window. contract.AtomicState: the optional host capability a precompile type-asserts to reach atomic shared memory (the platformvm/dexvm import/export primitive). Red fixes applied to the seam: FIX 2 (consensus-liveness chain-halt): native_staging.go FlushAcceptedAtomicOps already takes a batch; the flush is now one-batch-atomic at the host (see evm block.go/vm.go) — the SM Apply and the seq-marker advance commit all-or- nothing, closing the crash-between-Apply-and-marker -> duplicate-Put -> halt window. Regression: native_haltwindow_test.go (re-accept after a committed window is a clean no-op; crash-before-commit re-applies cleanly; the marker must ride the Apply batch). FIX 3 (conservation blast-radius): native_state.go adds seamReserve[a], the seam's OWN pot, decoupled from the depositor pot (settleVault) and the maker pot (makerLockedVault). lockIntentInput funds seamReserve; creditSettlementOutput checks+debits seamReserve. A settlement credit can never raid a depositor's claim; a withdraw can never strand a backed settlement. Invariant realHolding == settleVault + makerLockedVault + seamReserve. Regression: native_conservation_test.go (both subsystems, same asset). FIX 4 (reentrancy defense-in-depth): SettleSwap now takes the same single custody guard slot as deposit/withdraw/modifyLiquidity (enterCustodyKV), so the whole 0x9999 money surface is single-in-flight and an ERC-20 transfer callback cannot re-enter. Regression: native_callindex_test.go (callIndex determinism + intent-id collision-freedom across two swaps + a reverted sub-frame + a STATICCALL; SettleSwap non-reentrant + guard released for sequential calls). 305 prior + 10 new dex tests pass (CGO_ENABLED=0). Live-EVM-call-tree and live-crash-injection tests are CI-only (CGO + luxfi/accel LUXCPP). |
||
|
|
109874dda7 |
feat(dex): 0x9999 DEX V4 receipt-settlement precompile (D matches · C settles)
Replaces the deprecated embedded-AMM / inert / ERC-20-custody ZAP path with a
fork-safe receipt-settlement model: the D-Chain matches and BLS-signs a
DFillReceipt; 0x9999 (Uniswap-V4 PoolManager ABI) verifies that certificate
INLINE (BLS verify is deterministic -> fork-safe), debits/credits balances, and
marks the receipt consumed under Block-STM with fine-grained keys. The verify
path never calls a live matcher.
New:
receipt.go DFillReceipt + Merkle/wire encoding
bls_cert.go BLS quorum certificate verify (message-bound, anti-phantom)
verifier_registry.go certType (BLS day-1 -> Q/PQ/ZK) upgrade w/o ABI change
settle9999.go 0x9999 settlement entrypoint (V4 PoolManager ABI)
settle_module.go settle_custody.go settle_hookdata.go settle_stm.go settle_addr.go
halt9999.go multi-layer fund-preserving halt
dchain_client.go D-Chain receipt source client
settle_test.go settle_consensus_test.go 18 tests: E2E, no-mint conservation,
replay, restart-determinism, halt, forged-cert + wrong-chain
rejection, 0x9010 forwarder, BLS quorum/invalid/confusion/
phantom-bit, verifier registry, wire round-trips
Removed deprecated dead code: engine_inert.go + inert/custody/erc20/zap-rounding/
route-not-simulate tests (the old embedded-AMM and ERC-20-custody design).
0x9010 kept as a deprecated forwarder into the same impl (no ABI break).
Normative spec: LP-9999.
|
||
|
|
9cef96f13d |
feat(dex): 0x9999 DEX V4 receipt-settlement precompile (D matches · C settles)
Replaces the deprecated embedded-AMM / inert / ERC-20-custody ZAP path with a
fork-safe receipt-settlement model: the D-Chain matches and BLS-signs a
DFillReceipt; 0x9999 (Uniswap-V4 PoolManager ABI) verifies that certificate
INLINE (BLS verify is deterministic -> fork-safe), debits/credits balances, and
marks the receipt consumed under Block-STM with fine-grained keys. The verify
path never calls a live matcher.
New:
receipt.go DFillReceipt + Merkle/wire encoding
bls_cert.go BLS quorum certificate verify (message-bound, anti-phantom)
verifier_registry.go certType (BLS day-1 -> Q/PQ/ZK) upgrade w/o ABI change
settle9999.go 0x9999 settlement entrypoint (V4 PoolManager ABI)
settle_module.go settle_custody.go settle_hookdata.go settle_stm.go settle_addr.go
halt9999.go multi-layer fund-preserving halt
dchain_client.go D-Chain receipt source client
settle_test.go settle_consensus_test.go 18 tests: E2E, no-mint conservation,
replay, restart-determinism, halt, forged-cert + wrong-chain
rejection, 0x9010 forwarder, BLS quorum/invalid/confusion/
phantom-bit, verifier registry, wire round-trips
Removed deprecated dead code: engine_inert.go + inert/custody/erc20/zap-rounding/
route-not-simulate tests (the old embedded-AMM and ERC-20-custody design).
0x9010 kept as a deprecated forwarder into the same impl (no ABI break).
Normative spec: LP-9999.
|