Files
zeekay a081f8489b dex(0x9999): decentralize halt authority + commit the value-path proof tests
HIGH-3 (centralized key): the 0x9999 emergency-halt authority was a single
hardcoded EOA (DefaultDAOTreasury 0x9011…94714), which per memory is the devnet
"Maker" derivable from LUX_MNEMONIC — so anyone with the dev mnemonic could
setHaltAsset(real,true) (censor) or setHaltGlobal(true) (DoS the whole DEX). It
also gated seedSeamReserve/creditPositionFee. A single admin key, not governance.

Fix: the halt + pot-seeding authority is now the per-NETWORK DEX governance
controller resolved at RUNTIME from contract.AtomicState.GovernanceController()
(the same seam networkID/cChainID/dChainID flow through) — a governance CONTRACT
the host binds from its deployment topology, NEVER a dev-mnemonic EOA.

  - contract.AtomicState gains GovernanceController() common.Address.
  - halt9999.go: new governanceController(state) helper + ErrSettleNoGovernance;
    fail-closed when no AtomicState or the network configured no controller (zero
    address) — every halt/seed reverts, no default key to abuse. Strictly safer
    than a default key: an unset network can be neither censored nor DoS'd.
  - settle_module.go: DELETE DefaultDAOTreasury (the mnemonic EOA) and the
    SettleContract.protocolFeeController field; SettleContract is now stateless
    w.r.t. authority. The 4 gates (setHaltGlobal/Scoped, seedSeamReserve,
    creditPositionFee) resolve gov from runtime, then check caller == gov.
  - access_observer.go: observingAccessibleState forwards GovernanceController to
    the inner (fail-closed when non-atomic) so the L2 write-set wrapper preserves
    the capability.
  - Conservation is unchanged: only the authority resolution moved; value-movement
    logic (observed-delta seed, the pots, checkHalt) is untouched.

HIGH-1/HIGH-2 (integrity): commit the RED #5/#8/#11 proof tests that were
untracked — gatec_red_probe_test.go + gatec_red_dos_test.go — so the value path's
behavior is reproducible at this commit.

LOW-1: swap_sync.go doc comment updated (pre-permissionless "registry admission"
wording → the permissionless canonical resolver) so doc + behavior agree.

TDD (halt_governance_test.go + dex_test.go rewrite, all green):
  - the retired 0x9011 EOA can NO LONGER halt (ErrUnauthorized);
  - an arbitrary EOA cannot halt;
  - ONLY the configured governance controller can halt (global/asset/market) and
    the halt BITES — TestHIGH3_HaltBitesARealFill: governance halts a real market,
    a fillable swap reverts ErrMarketHalted, the retired EOA cannot lift it, only
    governance lifts it, then the swap fills;
  - with no governance configured, NOBODY can halt (fail-closed, ErrSettleNoGovernance);
  - the retired EOA cannot seed pots either;
  - RED CASE 6 (governance cannot mint/move funds) still passes under the new authority.
2026-06-22 22:50:00 -07:00

87 lines
4.3 KiB
Go

// Copyright (C) 2025-2026, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package contract
import (
"github.com/luxfi/geth/common"
"github.com/luxfi/ids"
"github.com/luxfi/vm/chains/atomic"
)
// AtomicState is the OPTIONAL host capability a precompile type-asserts when it
// must move value across chains via the primary network's atomic shared memory —
// the same import/export shared-memory primitive platformvm and the dexvm use.
//
// It is intentionally NOT part of AccessibleState: the vast majority of
// precompiles never touch shared memory, and AccessibleState has many test/mock
// implementers. A precompile that needs it does:
//
// atomicState, ok := accessibleState.(contract.AtomicState)
//
// and reverts cleanly when ok is false (the host did not wire a shared-memory
// capable runtime — single-chain dev / a non-atomic harness). The host's
// concrete AccessibleState (the EVM's accessibleStateAdapter, via the registry
// bridge) implements this by sourcing the runtime from the consensus context.
//
// THE INVARIANT THIS ENABLES (the DEX 0x9999 ship rule): a precompile can credit
// a local-chain balance from a cross-chain settlement ONLY by consuming a peer's
// atomic export object out of AtomicMemory() (Get + a Remove applied via Apply),
// and can fund a peer's chain ONLY by writing an atomic export object into
// AtomicMemory() (a Put applied via Apply). No value crosses without an atomic
// shared-memory object on the wire.
type AtomicState interface {
// AtomicMemory returns this chain's atomic shared-memory handle, or nil when
// the host wired no shared memory (single-chain dev). A nil return MUST make
// the calling precompile revert rather than fabricate value.
AtomicMemory() atomic.SharedMemory
// NetworkID is the numeric network identifier (1=mainnet, 2=testnet, ...). It
// scopes a cross-chain object's identity so an object minted on one network can
// never be consumed on another.
NetworkID() uint32
// ChainID is THIS chain's id (the C-Chain / EVM chain executing the precompile).
// It is the source chain id a C->D export object is keyed under and the
// destination chain id a D->C settlement object names.
ChainID() ids.ID
// CChainID is the C-Chain id used as the cross-chain settlement peer's view of
// this chain. On the C-Chain itself this equals ChainID(); it is surfaced
// separately so the binding is explicit and survives chains that distinguish
// the two.
CChainID() ids.ID
// GovernanceController is the DEX governance authority address — the ONLY caller
// permitted to toggle the 0x9999 settlement kill switches (setHaltGlobal/Market/
// Asset) and seed the settlement pots. It is a per-NETWORK governance CONTRACT
// (Governor/Timelock/multisig) resolved by the host from its deployment topology,
// supplied here through the SAME runtime seam as CChainID/DChainID — ZERO per-net
// config file. It is NEVER an EOA derivable from a dev mnemonic.
//
// The zero address means NO governance authority is configured on this network;
// the calling precompile MUST then treat every halt/seed call as fail-closed
// (revert), so an unset authority can DoS no one — there is no single admin key
// that could halt the DEX. A halt is governance, never a hardcoded key.
GovernanceController() common.Address
// DChainID is the D-Chain (dexvm) blockchain id the C<->D atomic seam routes
// objects to/from, resolved by the host from the chain topology (the consensus
// context's blockchain-alias lookup of "D"). It is ids.Empty on a network with
// no dexvm deployed; the calling precompile MUST revert in that case rather than
// guess a peer (the on-ramp is honestly closed until D exists). This is the
// runtime-resolved replacement for a per-network configured D target — the DEX
// settlement seam is always-on with ZERO per-net config, and the D peer is a
// deterministic property of the running network, identical on every validator.
DChainID() ids.ID
// TxID is the id of the transaction currently executing this precompile call.
// Combined with CallIndex it makes a per-call cross-chain object id injective.
TxID() ids.ID
// CallIndex is this precompile invocation's index within the current tx
// (0-based, monotonic). Two invocations in one tx get distinct indices so their
// derived cross-chain object ids never collide.
CallIndex() uint32
}