Skip to content

feat: Caldera Fusion DEX engine + mainnet hardening#71

Open
0xZunia wants to merge 32 commits intomainfrom
feature/dex-engine
Open

feat: Caldera Fusion DEX engine + mainnet hardening#71
0xZunia wants to merge 32 commits intomainfrom
feature/dex-engine

Conversation

@0xZunia
Copy link
Contributor

@0xZunia 0xZunia commented Feb 24, 2026

Summary

Protocol-native DEX engine (Caldera Fusion) with full mainnet hardening. 32 commits across 30 projects.

Caldera Fusion DEX (Phases A-E)

  • Phase A: Protocol-native AMM with constant-product pools, LP shares, and Merkle-proven state at 0x000...1009
  • Phase B: Batch auction solver with uniform clearing price — eliminates front-running, sandwich attacks, and MEV extraction
  • Phase C: Hybrid order book with escrowed limit orders, TWAP oracle with block header integration, dynamic volatility-adjusted fees
  • Phase D: Genesis deployment, 14 transaction types (7-20), REST API endpoints, node integration with three-phase block production
  • Phase E1: BST-20 token integration — trade any token pair via ManagedContractRuntime, transferable LP shares
  • Phase E2: Concentrated liquidity (Uniswap v3-style) — tick-based positions, sqrt price math, read-only SimulateSwap for batch solver, tick bitmap
  • Phase E3: Encrypted intents — DKG (Feldman VSS) threshold key generation, EC-ElGamal + AES-256-GCM encryption, IND-CCA2 security
  • Phase E4: Competitive solver network — Ed25519-signed solutions, surplus scoring, feasibility validation, solver rewards from AMM fees
  • Phase E5: Mainnet readiness — emergency pause, on-chain governance parameters, pool creation rate limiting, TWAP window (7200 blocks)

Mainnet Hardening (Phase 4)

Blockers:

  • Staking state persistence via IStakingPersistence + RocksDB (survives restarts)
  • Faucet key guard — reject startup on mainnet/testnet without explicit BASALT_FAUCET_KEY
  • WriteBatchScope throws on uncommitted dispose (was silently dropping data)
  • Debug CORS blocked on mainnet/testnet (BASALT_DEBUG=1 + chainId <= 2 = fatal)
  • ContractBridge lock timeout reduced from 30s to 10s

High:

  • Solver revert count tracking for reputation scoring
  • Mainnet config guards (network name, DataDir, ValidatorKey validation)
  • MockKycProvider optional self-approval parameter

Medium:

  • Configurable consensus timeout + P2P timeouts via ChainParameters
  • RocksDB production tuning (write buffers, compaction parallelism)
  • 5 new Prometheus metrics (peers, base fee, consensus view, finalization latency, DEX intents)
  • Exponential backoff with jitter in reconnect loop
  • Block timestamp rejection (backward + future drift)

Low:

  • Configurable log level (BASALT_LOG_LEVEL), file logging with daily rotation
  • Dockerfile HEALTHCHECK, shutdown jitter, NodeConfiguration env var docs

Post-merge fixes

  • BST-20 transfer error handling: converted throwing methods to DexResult error returns to prevent validator consensus loop crashes
  • BST-20 calldata encoding: use BasaltWriter to match BasaltReader decoding in generated dispatch
  • Contract dispatch: camelCase selector aliases, InvalidOperationException catch for unknown selectors
  • Block builder: always use BuildBlockWithDex so limit orders match even without swap intents
  • Limit order settlement: propagate order IDs through batch fills, remove spurious DEX-to-DEX self-transfers
  • TWAP carry-forward: backfill accumulators for all pools (not just those with intents), add GET /v1/dex/pools/{poolId}/price-history endpoint
  • Canonical state: run limit order matching and TWAP updates on the canonical stateDb during finalization (not the proposer's fork)
  • Zero-amount cleanup: evict filled buy orders with zero/dust remaining amounts
  • Mempool pruning: evict transactions whose sender balance dropped below required amount
  • Buy order amount fix: standardized LimitOrder.Amount to always represent token0 units (was incorrectly stored as token1 for buy orders, causing wrong remaining amounts after partial fills). Escrow computed as amount * price / PriceScale at placement. Added price improvement refunds when clearingPrice < limitPrice.

Documentation

  • Comprehensive docs/dex_design.md update: all 21 key prefixes (0x01-0x14), 26 error codes, 12 gas costs, 20 transaction types, governance parameters, emergency pause, solver network
  • DEX README updated with token0-based order amount semantics

Stats

  • 2,781 tests passing, 0 failures, 0 build warnings
  • 16 test projects

Test plan

  • dotnet build Basalt.sln — 0 errors, 0 warnings
  • dotnet test Basalt.sln — 2,781 tests, all passing
  • Set BASALT_CHAIN_ID=1 without BASALT_FAUCET_KEY -> startup should fail
  • Set BASALT_DEBUG=1 with BASALT_CHAIN_ID=1 -> startup should fail
  • Staking state round-trip through RocksDB persistence -> identical state
  • Block with backward timestamp -> rejected
  • /metrics includes basalt_peer_count, basalt_base_fee, etc.
  • Docker build + HEALTHCHECK passes
  • Buy(0.5, 100) then Sell(0.5, 40) -> buy remaining = 60 (not 80)
  • Cancel partially-filled buy order -> correct token1 refund
  • Expired buy order cleanup -> correct token1 refund

Core DEX engine as a first-class protocol feature:

- New Dex/ module in Basalt.Execution with DexState, DexEngine, DexResult
- Math library: FullMath (512-bit precision) + DexLibrary (constant-product AMM)
- Pool CRUD with configurable fee tiers (1/5/30/100 bps)
- Liquidity add/remove with geometric mean share calculation
- Single swaps via constant-product formula with slippage protection
- Limit order placement and cancellation with token escrow
- TWAP accumulator storage for on-chain price oracle
- Binary serialization for all state structs (PoolMetadata, PoolReserves, etc.)

Storage model: DEX state at system address 0x...1009 using trie storage,
providing Merkle proofs, persistence, and fork-merge atomicity.

Transaction types 7-12 (DexCreatePool through DexCancelOrder) with
full TransactionExecutor integration (gas charging, nonce management,
fork-based atomicity, proposer tip credit).

DEX error codes (10001-10012) and gas cost parameters in ChainParameters.
MaxExtraDataBytes increased to 256 for TWAP oracle data.

68 new tests covering math, state, engine, and executor integration.
All 2395+ existing tests continue to pass.
MEV-elimination mechanism via uniform clearing price batch auctions:

- BatchAuctionSolver: finds equilibrium price where buy volume meets sell
  volume, incorporating AMM reserves as liquidity of last resort. O(n*k)
  in number of intents * critical prices.
- ParsedIntent: structured representation of DexSwapIntent tx data with
  implicit limit price computation (amountIn/minAmountOut scaled by 2^64).
- BatchSettlementExecutor: applies fills at clearing price, handles
  peer-to-peer matching, AMM residual routing, TWAP updates, and
  receipt generation.
- BatchResult/FillRecord: settlement output with per-participant fills.

Three-phase BlockBuilder pipeline:
  Phase A: Execute non-intent txs (transfers, staking, liquidity, orders)
  Phase B: Group DexSwapIntent txs by pair, compute clearing prices
  Phase C: Apply fills, update reserves, generate batch receipts

Mempool intent partitioning:
  - DexSwapIntent txs routed to separate _dexIntentEntries pool
  - GetPendingDexIntents() for BlockBuilder batch retrieval
  - RemoveConfirmed checks both pools
  - Per-sender limits span both pools

12 new tests for solver, intent parsing, mempool partitioning.
All 2398 tests pass, 0 failures.
Add limit order matching with crossing detection and partial fills,
on-chain TWAP oracle with block header serialization, and volatility-
adjusted dynamic fee calculator. Wire TWAP data into BuildBlockWithDex
ExtraData for light client price feeds.
…ocumentation

Initialize DEX state at genesis (0x...1009 system account), wire
BuildBlockWithDex into NodeCoordinator for three-phase block production
with intent partitioning, add 5 REST API endpoints for DEX queries
(pools, orders, TWAP), and create full technical design document with
module README. Includes 9 end-to-end integration tests.
Enable DexEngine to dispatch BST-20 Transfer calls via ManagedContractRuntime
for non-native token pairs. Add LP token transfer/approve/transferFrom with
allowance storage (0x08 prefix, BLAKE3 key derivation). Wire runtime through
TransactionExecutor, BatchSettlementExecutor, and BlockBuilder. Add tx types
DexTransferLp (13) and DexApproveLp (14) with gas costs 40k/30k. 19 new tests.
…ent (Phase E2)

Add Uniswap v3-style concentrated liquidity: TickMath (Q64.96 sqrt price
conversions using precomputed reciprocal constants), SqrtPriceMath (token
amount deltas for price ranges), LiquidityMath (signed delta arithmetic
and liquidity-from-amounts). ConcentratedPool engine handles position
mint/burn with tick bookkeeping and multi-tick swap iteration. New storage
prefixes 0x0A-0x0D for tick info, positions, pool state, and position
counter. Transaction types 15-17 (MintPosition, BurnPosition, CollectFees)
with gas costs 120k/100k/60k. 84 new tests across 4 test files.
Implement Feldman VSS distributed key generation protocol and encrypted
intent support for MEV-resistant batch auctions.

DKG protocol:
- ThresholdCrypto: polynomial evaluation, Lagrange interpolation, share
  generation/verification over BLS12-381 scalar field
- DkgProtocol: state machine (Idle→Deal→Complaint→Justify→Finalize)
  with complaint resolution and dealer disqualification
- 40 tests covering full DKG lifecycle, threshold reconstruction, and
  edge cases (missing dealers, invalid shares)

Encrypted intents:
- EncryptedIntent struct: encrypt/decrypt swap intents using BLAKE3-derived
  symmetric keys from DKG group public key
- Transaction type 18 (DexEncryptedSwapIntent) with 100k gas cost
- BlockBuilder Phase B decrypts intents before batch settlement
- Mempool routes encrypted intents to DEX intent pool
- TransactionExecutor validates envelope format (154B minimum)
- Error codes: DexDecryptionFailed (10019), DexInvalidEpoch (10020)
- DKG message types (0x70-0x73) in network codec
- 11 tests covering encrypt/decrypt round-trip, wrong-key detection,
  executor validation, mempool routing, and block builder integration
Implement external solver competition framework where off-chain solvers
compete to provide optimal batch auction settlements.

Solver infrastructure:
- SolverManager: registration, solution window lifecycle, signature
  verification, best-solution selection with built-in solver fallback
- SolverScoring: surplus-based scoring (sum of amountOut - minAmountOut),
  feasibility validation (balances, reserves, pool existence)
- SolverSolution: signed settlement proposal struct
- SolverInfoAdapter: bridges SolverManager to REST API without circular deps

Network integration:
- Message types 0x74 (SolverRegistration), 0x75 (SolverSolution)
- MessageCodec serialization/deserialization for both message types
- NodeCoordinator handles solver registration and solution submission
- BlockBuilder.ExternalSolverProvider delegate for pluggable settlement

REST API endpoints:
- GET /v1/solvers — list registered solvers with stats
- POST /v1/solvers/register — register solver via public key
- GET /v1/dex/intents/pending — query pending intent hashes for solvers

Chain parameters:
- SolverWindowMs (default 500ms), MaxSolvers (32), SolverRewardBps (10%)

31 new tests covering solver registration, solution submission/rejection,
signature verification, surplus scoring, feasibility validation, selection
algorithm, and message codec round-trips.
Add documentation for all Phase E advanced features:
- E1: BST-20 token integration, LP token transfers/approvals
- E2: Concentrated liquidity (tick math, positions)
- E3: Encrypted intents (DKG, threshold crypto)
- E4: Solver network (registration, scoring, selection)

Update file tree, transaction type table, MEV elimination section,
REST API endpoint list, and architecture overview.
…iness

Comprehensive mainnet hardening sweep across the DEX engine, consensus,
storage, and node infrastructure:

BLOCKERS:
- B1: Staking state persistence via IStakingPersistence + RocksDB (survives restarts)
- B2: Faucet key guard — reject startup on mainnet/testnet without explicit key
- B3: WriteBatchScope throws on uncommitted dispose (was silently dropping data)
- B4: Debug CORS blocked on mainnet/testnet
- B5: ContractBridge lock timeout reduced from 30s to 10s

HIGH:
- H6: Solver revert count tracking for reputation scoring
- H7: Mainnet config guards (network name validation, DataDir, ValidatorKey)
- H9: MockKycProvider optional self-approval parameter

MEDIUM:
- M10: Configurable consensus timeout via ChainParameters
- M11: Configurable P2P timeouts (handshake, frame read, connect)
- M12: RocksDB production tuning (write buffers, compaction, parallelism)
- M13: 5 new Prometheus metrics (peers, base fee, consensus view, finalization, DEX intents)
- M14: Exponential backoff with jitter in reconnect loop
- M16: Block timestamp rejection (backward + future drift)

LOW:
- L17: Configurable log level via BASALT_LOG_LEVEL
- L18: File logging with daily rotation when BASALT_DATA_DIR set
- L19: Dockerfile HEALTHCHECK
- L20: Shutdown jitter to prevent thundering herd
- L22: NodeConfiguration XML doc for all env vars

DEX hardening (E5):
- Emergency pause (admin-controlled), governance parameter overrides
- Pool creation rate limiting, TWAP window extended to 7200 blocks
- Concentrated liquidity overflow protection, encrypted intent hardening
- Updated DEX design doc with all key prefixes, error codes, and gas costs

2,781 tests passing, 0 failures.
@0xZunia 0xZunia requested a review from Copilot February 24, 2026 20:13
…used

P-1: Emergency pause no longer blocks user withdrawals. RemoveLiquidity,
BurnPosition, and CollectFees bypass the pause check so users can always
exit their positions.

P-2: BlockBuilder now checks IsDexPaused() before running the batch
auction in Phase B. Previously, encrypted and plaintext swap intents
were still settled even when the DEX was paused.

G-1 (MaxIntentsPerBatch): confirmed NOT dead code — enforced in
NodeCoordinator via GetPendingDexIntents(effectiveMaxIntents).
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the Caldera Fusion protocol-native DEX engine alongside mainnet hardening changes (persistence, config guards, timeouts, metrics, and REST surface) to make Basalt production-ready.

Changes:

  • Introduces DEX primitives (intents, batch settlement execution, order book, concentrated liquidity math, TWAP oracle, dynamic fees) + related REST endpoints.
  • Adds solver network plumbing (solution submission, scoring/feasibility checks, signatures, message types/codec).
  • Hardens mainnet/testnet behavior (staking persistence, base-fee gating in mempool, debug/CORS and faucet key guards, RocksDB tuning, configurable transport timeouts, new metrics/healthcheck).

Reviewed changes

Copilot reviewed 80 out of 89 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
tests/Basalt.Execution.Tests/Dex/MainnetHardeningTests.cs Adds regression tests for mainnet/testnet parameter guards and mempool admission gates.
tests/Basalt.Execution.Tests/Dex/LpTokenTests.cs Validates LP transfer/approval flows and executor integration.
tests/Basalt.Execution.Tests/Dex/LiquidityMathTests.cs Covers concentrated-liquidity liquidity arithmetic helpers.
tests/Basalt.Execution.Tests/Dex/DynamicFeeTests.cs Adds dynamic fee calculator tests (pure + TWAP-integrated).
tests/Basalt.Execution.Tests/Dex/DexStateTests.cs Validates DEX state serialization and key construction.
tests/Basalt.Execution.Tests/Dex/DexMathTests.cs Covers AMM math (FullMath/DexLibrary) including rounding regression.
tests/Basalt.Core.Tests/UInt256Tests.cs Updates ChainParameters testnet expectations (security profile + DEX admin).
tests/Basalt.Consensus.Tests/Staking/StakingPersistenceTests.cs Tests staking persistence round-trip via IStakingPersistence.
tests/Basalt.Consensus.Tests/Dkg/ThresholdCryptoTests.cs Adds DKG/threshold crypto correctness tests.
tests/Basalt.Compliance.Tests/NullifierWindowTests.cs Adds windowed nullifier reset tests for replay prevention.
tests/Basalt.Compliance.Tests/IdentityRegistryGovernanceTests.cs Tests governance revocation behavior and audit log coverage.
src/storage/Basalt.Storage/TrieStateDb.cs Documents and enforces non-support for full account enumeration on trie DB.
src/storage/Basalt.Storage/RocksDb/RocksDbStore.cs Adds staking CF and production RocksDB tuning; makes WriteBatchScope dispose throw on uncommitted.
src/node/Basalt.Node/Solver/SolverSolution.cs Adds solver solution DTO for block settlement proposals.
src/node/Basalt.Node/Solver/SolverScoring.cs Implements solver surplus scoring + feasibility validation.
src/node/Basalt.Node/Solver/SolverManager.cs Manages solver registration, signature verification, solution selection, and revert tracking.
src/node/Basalt.Node/Solver/SolverInfoAdapter.cs Bridges solver/mempool info into REST API without Basalt.Node dependency.
src/node/Basalt.Node/RocksDbStakingPersistence.cs Implements RocksDB-backed staking persistence (stakes + unbonding queue).
src/node/Basalt.Node/Program.cs Adds mainnet guards, wiring for solver REST, shutdown jitter, and staking flush on shutdown.
src/node/Basalt.Node/NodeConfiguration.cs Documents env var configuration surface.
src/network/Basalt.Network/Transport/TcpTransport.cs Makes connect timeout configurable.
src/network/Basalt.Network/Transport/PeerConnection.cs Makes frame read timeout configurable.
src/network/Basalt.Network/Transport/HandshakeProtocol.cs Makes handshake timeout configurable.
src/network/Basalt.Network/Messages.cs Adds DKG and solver network message types + payload DTOs.
src/network/Basalt.Network/MessageCodec.cs Serializes/deserializes new DKG + solver messages.
src/execution/Basalt.Execution/VM/GasTable.cs Adds gas constants for DEX operations.
src/execution/Basalt.Execution/VM/ContractBridge.cs Reduces execution lock timeout and improves error message.
src/execution/Basalt.Execution/Transaction.cs Adds DEX transaction types 7–20.
src/execution/Basalt.Execution/Mempool.cs Adds DEX intent pool, base fee gating, data-size limits, and intent retrieval for batch settlement.
src/execution/Basalt.Execution/GenesisContractDeployer.cs Initializes DEX system account at genesis.
src/execution/Basalt.Execution/Dex/TwapOracle.cs Adds TWAP oracle + header serialization/parsing.
src/execution/Basalt.Execution/Dex/ParsedIntent.cs Defines swap intent parsing and derived limit price.
src/execution/Basalt.Execution/Dex/OrderBook.cs Implements crossing-order discovery, matching, and expiry cleanup.
src/execution/Basalt.Execution/Dex/Math/TickMath.cs Adds tick↔sqrtPrice conversions (ported from Uniswap v3).
src/execution/Basalt.Execution/Dex/Math/SqrtPriceMath.cs Adds sqrt-price delta math for concentrated liquidity.
src/execution/Basalt.Execution/Dex/Math/LiquidityMath.cs Adds safe liquidity delta arithmetic and liquidity-from-amounts helpers.
src/execution/Basalt.Execution/Dex/Math/FullMath.cs Adds BigInteger-backed 512-bit intermediate math helpers.
src/execution/Basalt.Execution/Dex/Math/DexLibrary.cs Adds constant-product AMM formulas and LP share math.
src/execution/Basalt.Execution/Dex/EncryptedIntent.cs Adds EC-ElGamal + AES-GCM encrypted intent format with zeroization.
src/execution/Basalt.Execution/Dex/DynamicFeeCalculator.cs Adds volatility-based dynamic fees with TWAP integration.
src/execution/Basalt.Execution/Dex/DexResult.cs Defines a unified result type for DEX operations.
src/execution/Basalt.Execution/Dex/BatchSettlementExecutor.cs Applies solver settlement fills, updates reserves/TWAP, and generates receipts.
src/execution/Basalt.Execution/Dex/BatchResult.cs Defines batch settlement outputs and fill records.
src/execution/Basalt.Execution/Basalt.Execution.csproj Grants InternalsVisibleTo for Basalt.Execution.Tests.
src/core/Basalt.Crypto/BlsCrypto.cs Adds low-level BLS G1 operations for threshold encryption.
src/core/Basalt.Core/Compliance/IComplianceVerifier.cs Adds default windowed nullifier reset API.
src/core/Basalt.Core/ChainParameters.cs Adds DEX + timeout parameters and mainnet/testnet defaults/validation.
src/core/Basalt.Core/BasaltError.cs Adds DEX + nullifier replay error codes.
src/consensus/Basalt.Consensus/Staking/StakingState.cs Adds persistence flush/load methods.
src/consensus/Basalt.Consensus/Staking/IStakingPersistence.cs Defines staking persistence interface.
src/consensus/Basalt.Consensus/PipelinedConsensus.cs Makes consensus round timeout configurable.
src/compliance/Basalt.Compliance/ZkComplianceVerifier.cs Implements windowed nullifier tracking and replay error code.
src/compliance/Basalt.Compliance/MockKycProvider.cs Makes self-approval optional for production safety.
src/compliance/Basalt.Compliance/IdentityRegistry.cs Adds governance-based revocation capability.
src/compliance/Basalt.Compliance/ComplianceEngine.cs Adds windowed nullifier reset passthrough.
src/api/Basalt.Api.Rest/RestApiEndpoints.cs Adds DEX endpoints and solver endpoints; documents debug endpoint guard.
src/api/Basalt.Api.Rest/MetricsEndpoint.cs Adds new Prometheus metrics (peers/base fee/view/finalization/DEX intents).
src/api/Basalt.Api.GraphQL/GraphQLSetup.cs Adds GraphQL cost limits.
Dockerfile Adds container HEALTHCHECK.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

CR-2: Include IsBuy, IsLimitOrder, OrderId in solver solution signature hash
CR-3a: Partial limit-order fills subtract filled amount instead of zeroing
CR-3b: Deterministic receipt hashes for limit-order fills (no more Hash256.Zero collisions)
CR-4/5: Wrap Mempool._currentBaseFee reads/writes in lock to prevent UInt256 torn reads
CR-6: Materialize keys before deleting in RocksDbStakingPersistence (unsafe lazy iterator deletion)
CR-7: Wrap finally-block persistence flushes in try/catch to ensure cleanup proceeds
CR-10: Add NullifierCount/TrackNullifier to ZkComplianceVerifier; fix 4 assertion-less tests
…(CR-8)

Replace O(totalOrders) global scan with O(poolOrders) linked-list walk
using the existing per-pool order index (L-15).
@0xZunia 0xZunia requested a review from Copilot February 24, 2026 20:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 80 out of 89 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Deployers can now specify an initial token supply that gets minted to
their address at construction time. The parameter is backward compatible
(defaults to zero) and the ContractRegistry reads it only when the
manifest contains the extra 32 bytes.
ManagedContractRuntime re-instantiates contracts on every call, causing
the constructor to re-execute Mint. Guard with _totalSupply.Get().IsZero
so initial supply is only minted once (on first deployment).
… on every call

ManagedContractRuntime re-instantiates SDK contracts on every call,
re-running constructors. 9 of 15 contracts had side-effects (admin set,
mint, config reset) that corrupted state — notably any caller became
admin on NFT/Bridge/Vault/Issuer contracts.

Add Context.IsDeploying flag: true during Deploy(), false during Execute().
All constructor side-effects now gated behind this check.
…point

Exposes per-user LP token balance for DEX pools via DexState.GetLpBalance,
enabling wallet UI to display liquidity positions.
…nsensus loop

ExecuteBst20Transfer threw BasaltException on insufficient balance instead of returning false, causing unhandled exceptions to propagate through AddLiquidity → BuildBlock → consensus loop and freeze the node.
Converted TransferTokensOut, TransferSingleTokenIn, TransferSingleTokenOut from void (throwing) to DexResult (error returns).
Updated all callers in DexEngine, TransactionExecutor, BatchSettlementExecutor, and OrderBook.
Source generator now emits both PascalCase and camelCase FNV-1a
selectors for every dispatchable method. External callers using
Ethereum-conventional camelCase (e.g. "transfer" instead of
"Transfer") no longer crash the validator with "Unknown selector".
…ntract dispatch

Unknown selector throws InvalidOperationException from generated
Dispatch(), which was unhandled in ManagedContractRuntime.Execute().
This propagated through BuildBlock into the consensus loop and froze
the validator. Now returns a failed ContractCallResult instead.
… dispatch

Unknown selectors and failing BST-20 transfers now return error
results instead of throwing, so the 4 tests that expected exceptions
are updated to assert on the returned failure status.
ExecuteBst20Transfer wrote the address argument as 20 raw bytes, but
the source-generated dispatch reads it with BasaltReader.ReadBytes()
which expects a varint length prefix. The deserialization mismatch
corrupted the arguments, causing every BST-20 token transfer in DEX
operations (AddLiquidity, Swap, RemoveLiquidity) to fail with
DexTransferFailed.

Use BasaltWriter to properly encode [varint(20) + addr + uint256] so
it matches what the generated Dispatch method reads.
Limit orders were never matched against each other because the batch
settlement only ran when swap intents existed, and even then passed
empty arrays for limit orders. This wires up the existing OrderBook
matching logic:

- Pass active limit orders to BatchAuctionSolver.ComputeSettlement
  instead of empty arrays when processing swap intent batches
- Add Phase B2: standalone limit order matching pass that scans all
  pools for crossing orders even when no swap intents are pending
- Add GetAllActiveOrders helper to collect non-expired orders per pool
…rs are updated/deleted

BatchAuctionSolver.GenerateFills hardcoded OrderId=0 on all limit order
fills because ComputeSettlement accepted List<LimitOrder> without IDs.
BatchSettlementExecutor then checked fill.OrderId > 0, which was always
false (dead code) and would also skip legitimate order #0. Together these
bugs meant limit orders were never updated or deleted after being matched,
so crossing orders remained permanently active.

- Change ComputeSettlement/GenerateFills to accept List<(ulong Id, LimitOrder)>
- Thread order IDs from GetAllActiveOrders through the solver pipeline
- Set FillRecord.OrderId from the tuple instead of hardcoding 0
- Remove broken fill.OrderId > 0 guard in BatchSettlementExecutor
…ment

BatchSettlementExecutor called TransferSingleTokenIn(DexAddress, inputToken)
before crediting the output to the order owner. Since escrowed tokens are
already held by the DEX address (deposited at order placement), this was a
self-transfer that served no purpose — and worse, it failed when the sell
fill's TransferSingleTokenOut drained the buyer's escrowed token1 before
the buy fill could "debit" it. The OverflowException was silently caught
(L-10), causing all buy fills to be skipped and orders to remain active.

Remove the TransferSingleTokenIn call entirely for limit order fills.
Only TransferSingleTokenOut is needed to send matched output to each
participant from the DEX escrow.
… swap intents

NodeCoordinator only called BuildBlockWithDex when pendingDexIntents was
non-empty, falling back to BuildBlock otherwise. Since Phase B2 (standalone
limit order matching) only exists in BuildBlockWithDex, limit orders were
never matched when no swap intents were pending.

Always call BuildBlockWithDex regardless of intent count — it handles
empty intents gracefully and Phase B2 runs every block to match crossing
limit orders.
…all pools

The TWAP carry-forward in BlockBuilder skipped pools whose accumulator
was never initialized (LastBlock == 0), which meant pools without
encrypted-intent settlements never got any TWAP snapshots stored.
Remove that guard so all pools with reserves get snapshots from their
first block of existence.

Add GET /v1/dex/pools/{poolId}/price-history endpoint that samples TWAP
accumulator snapshots over a configurable block range with automatic
interval adjustment (capped at 500 data points). Falls back to the
current spot price when no snapshot data exists.
… finalization

BlockBuilder.BuildBlockWithDexCore ran DEX phases (TWAP carry-forward,
limit order matching, settlement) on a forked stateDb that was discarded
after block building. During finalization and sync, only individual
transactions were re-executed — DEX settlement never ran on canonical
state, so orders were placed but never matched.

Extract RunTwapCarryForward and RunStandaloneLimitOrderMatching as
reusable helpers, add public ApplyDexSettlement entry point, and call it
in both HandleBlockFinalized and HandleSyncResponse. Also filter expired
and zero-amount orders from the /v1/dex/pools/{poolId}/orders API.
…unts

MulDiv round-trip in buy order fills caused fillAmount1 < order.Amount by
a few units, leaving dust remainders that could never be matched. Use exact
order.Amount for full fills, detect full consumption in MatchOrders via
both token dimensions, and clean up any orphaned zero-amount orders in
CleanupExpiredOrders as a safety net.
…ning

PruneStale only checked for stale nonces and underpriced gas, so
transactions whose sender balance dropped below value + gas after
admission stayed in the mempool indefinitely, getting re-validated
and re-rejected every block.
Buy orders previously stored Amount in token1 units, causing incorrect
remaining amounts after partial fills (e.g. Buy(0.5, 100) matched with
Sell(0.5, 40) yielded remaining=80 instead of expected 60).

Now LimitOrder.Amount always represents token0 for both buy and sell
sides. Buy order escrow is computed as amount*price/PriceScale at
placement. Cancellation, expiry cleanup, batch settlement, and order
matching all updated consistently. Price improvement refunds added for
buy fills when clearingPrice < limitPrice.
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.

2 participants