Documentation
¶
Overview ¶
Package registry is the DEX's real-assets-only enforcement layer: the single, orthogonal place that decides which assets and which markets are admissible.
It exists to make ONE property structural rather than incidental: every asset the DEX ledger can ever credit or debit corresponds to a REAL object on-chain (an ERC-20 contract on the C-Chain, the C-Chain native coin, or a UTXO asset on the X-Chain). There is no "D-native asset" class, no synthetic asset, no ASCII-ticker identity, and no declared-but-unbacked credit. An asset's identity is a canonical hash of WHERE IT REALLY LIVES — so two parties, given the same chain, derive the same 32-byte AssetID, and a fabricated asset has no preimage.
This package is deliberately independent of the matcher (which lives in-process in the C-Chain settlement precompile) and of the proxy's settle path. It is a pure identity + admission primitive: derive an AssetID, register a real asset, gate a market on two registered assets. Verification against live chain state is injected (ChainVerifier) so the same logic backs both the offline CI manifest validator and the node's fail-closed startup gate.
Index ¶
- Constants
- Variables
- func DeriveAssetID(networkID uint32, sourceChainID ids.ID, kind AssetKind, ref []byte) (ids.ID, error)
- func MarketID(networkID uint32, baseAssetID, quoteAssetID ids.ID, venueConfig []byte) ids.ID
- func RefuseUnderSyntheticConfig(class NetworkClass, policy DexAssetPolicy, reg *Registry, ...) error
- type Asset
- type AssetKind
- type Bytes
- type CChainConfirmer
- type ChainVerifier
- type ConsensusMode
- type DexAssetPolicy
- type LaunchAssertions
- type Manifest
- type Market
- type NetworkClass
- type Registry
- func (r *Registry) AllowsKind(k AssetKind) bool
- func (r *Registry) CreateMarket(m Market) (ids.ID, error)
- func (r *Registry) Each(fn func(id ids.ID, a Asset))
- func (r *Registry) EachMarket(fn func(id ids.ID, m Market))
- func (r *Registry) Len() int
- func (r *Registry) MustResolveEnabled(id ids.ID) (Asset, error)
- func (r *Registry) Register(a Asset, v ChainVerifier) (ids.ID, error)
- func (r *Registry) Resolve(id ids.ID) (Asset, bool)
- func (r *Registry) ResolveMarket(id ids.ID) (Market, bool)
- type RiskTier
- type RuntimeVerifier
- func (rv *RuntimeVerifier) ConfirmCChain(networkID uint32, _ uint64, cChainID ids.ID) error
- func (rv *RuntimeVerifier) VerifyERC20(networkID uint32, cChainID ids.ID, addr []byte) (uint8, error)
- func (rv *RuntimeVerifier) VerifyEVMNative(networkID uint32, cChainID ids.ID) (uint8, error)
- func (rv *RuntimeVerifier) VerifyUTXOAsset(networkID uint32, sourceChainID ids.ID, assetID ids.ID) (uint8, error)
- type ValueModeStatus
Constants ¶
const ( MainnetEVMChainID uint64 = 96369 TestnetEVMChainID uint64 = 96368 DevnetEVMChainID uint64 = 96370 LocalnetEVMChainID uint64 = 1337 )
EVM chainIDs of the three networks that ship a committed manifest. These are the eth_chainId values, NOT the consensus networkIDs (1/2/3). Localnet (1337) is handled separately because its C-Chain id is not fixed.
const NoByzantineFinalityClaim = "DEX value active under HONEST_VALIDATOR_LABELED (CFT parity): no Byzantine-finality claim"
NoByzantineFinalityClaim is the EXACT status string a HONEST_VALIDATOR_LABELED activation surfaces. It is a constant so the UI/status surface and any audit tooling can match it byte-for-byte; the launch posture must never be silently presented as Byzantine-final.
Variables ¶
var ( // ErrInvalidKind is returned when an asset's kind is not one of the three. ErrInvalidKind = errors.New("registry: asset kind is not EVM_NATIVE, ERC20 or UTXO") // ErrBadRef is returned when an asset's canonical reference does not match the // shape its kind requires (e.g. a 19-byte ERC-20 address). ErrBadRef = errors.New("registry: canonical reference does not match asset kind") // ErrEmptyChainID is returned when the source chain of an asset is the empty id. ErrEmptyChainID = errors.New("registry: asset source chain id is empty") )
var ( // ErrValueModeUnset is returned when value activation is requested with no legal // value mode declared. ErrValueModeUnset = errors.New("registry: refuse DEX value activation — consensus mode is UNSET (no Byzantine-finality and no labeled CFT-parity declared)") // ErrValueModeIllegal is returned for any consensus mode that is not one of the // two legal value modes. ErrValueModeIllegal = errors.New("registry: refuse DEX value activation — consensus mode is not QUORUM_FINALITY or HONEST_VALIDATOR_LABELED") // ErrLaunchAssertionsUnmet is returned when HONEST_VALIDATOR_LABELED is requested // without the full caps-on + real-assets-only + halt-ready bundle. ErrLaunchAssertionsUnmet = errors.New("registry: refuse HONEST_VALIDATOR_LABELED value activation — caps-on + real-assets-only + halt-ready not all asserted") )
var ( // ErrSyntheticOnValueNet is returned when any synthetic flag is true on // mainnet or testnet. ErrSyntheticOnValueNet = errors.New("startup: synthetic asset/market/liquidity flag set on a value-bearing network (mainnet/testnet)") // ErrEnabledMarketUnknownAsset is returned when an enabled market references an // asset that is not in the registry (synthetic). ErrEnabledMarketUnknownAsset = errors.New("startup: enabled market references an unknown/synthetic asset") // ErrBadAllowedKind is returned when dexAllowedAssetKinds contains a token that // is not one of the three real kinds. ErrBadAllowedKind = errors.New("startup: dexAllowedAssetKinds contains a non-real kind") )
var ( // ErrSameAsset is returned when a market names the same asset on both sides. ErrSameAsset = errors.New("registry: market base and quote assets are identical") // ErrNetworkMismatch is returned when a market's network does not match an asset's. ErrNetworkMismatch = errors.New("registry: market network does not match asset network") // ErrDuplicateMarket is returned when a MarketID already exists. ErrDuplicateMarket = errors.New("registry: market already exists") )
var ( // ErrUnknownAsset is returned when a market (or any caller) references an // AssetID that is not registered — the structural form of "synthetic asset". ErrUnknownAsset = errors.New("registry: asset is not registered (unknown/synthetic)") // ErrAssetDisabled is returned when a referenced asset is registered but disabled. ErrAssetDisabled = errors.New("registry: asset is registered but disabled") // ErrKindNotAllowed is returned when an asset's kind is not in the active // dexAllowedAssetKinds policy. ErrKindNotAllowed = errors.New("registry: asset kind not in allowed-kinds policy") // ErrDuplicateAsset is returned when registering an AssetID that already exists. ErrDuplicateAsset = errors.New("registry: asset already registered") )
var EVMNativeMarker = make([]byte, 20) // 20 zero bytes == EVM address(0)
EVMNativeMarker is the fixed on-chain reference for the C-Chain native coin. EVM_NATIVE has no contract address, so its canonical reference is this constant 20-byte marker (the EVM zero address — the EVM's own sentinel for "the native coin"). Folding a fixed, kind-tagged marker means every party derives the same EVM_NATIVE AssetID for a given (networkID, C-chainID) and nobody can invent a second native asset.
var ErrManifestHashMismatch = errors.New("registry: manifest content hash does not match the pinned expected hash (the file was modified from the CI-approved artifact)")
ErrManifestHashMismatch is returned when a manifest's actual content SHA-256 does not equal the pinned expected hash — the file was edited (a fabricated address, an extra asset) away from the CI-approved artifact. Fail-closed: the node refuses to load it.
var ErrNoEmbeddedManifest = fmt.Errorf("registry: no embedded asset manifest for this EVM chainID")
ErrNoEmbeddedManifest is returned when no committed manifest exists for an EVM chainID (e.g. localnet 1337, or an unknown sovereign chainID). The caller decides whether to synthesise a native-only manifest (localnet) or stay fail-closed.
Functions ¶
func DeriveAssetID ¶
func DeriveAssetID(networkID uint32, sourceChainID ids.ID, kind AssetKind, ref []byte) (ids.ID, error)
DeriveAssetID computes the canonical, consensus-native 32-byte identity of a real on-chain asset. The identity is a length-prefixed SHA-256 fold over, in order:
domAssetV1 | networkID | sourceChainID | kind | canonicalRef
matching the per-kind formulas exactly:
ERC20: H(networkID, C-chainID, ERC20, token-address) EVM_NATIVE: H(networkID, C-chainID, EVM_NATIVE, native-marker) UTXO: H(networkID, X-chain-id, UTXO, assetID)
sourceChainID is the C-Chain id for EVM_NATIVE/ERC20 and the UTXO source chain id (X-Chain) for UTXO. The fold is length-prefixed (each field's length precedes its bytes) so no two distinct field tuples share a preimage, and the kind byte domain-separates the three classes. The result is an ids.ID — the SAME identity space the on-chain atomic objects already use (AtomicInput.Asset, AtomicOutput.Asset, RelayOrderTx.AssetOut) — so a registered AssetID is directly comparable to the asset a real cross-chain object carries. It is NEVER a string ticker.
func MarketID ¶
MarketID computes the canonical identity of a market from its two asset identities and the venue configuration:
marketID = H(networkID, baseAssetID, quoteAssetID, venueConfig)
baseAssetID and quoteAssetID are themselves canonical AssetIDs (so a market is pinned to real assets by construction — you cannot name a market over a synthetic asset because there is no AssetID for one). venueConfig is the canonical bytes of the venue parameters (tick size, lot size, fee tier, etc.) that distinguish two venues on the same pair; callers pass its canonical serialization.
func RefuseUnderSyntheticConfig ¶
func RefuseUnderSyntheticConfig( class NetworkClass, policy DexAssetPolicy, reg *Registry, chainLabelFor func(chainID ids.ID) string, ) error
RefuseUnderSyntheticConfig is the SINGLE fail-closed startup gate. It is called once at VM Initialize, BEFORE the chain accepts work, with the already-populated registry and the VM's network + policy. It refuses startup (returns an error, which the VM turns into a hard init failure) if ANY of the following hold:
- dexAllowedAssetKinds contains a non-real kind (it may only ever be a subset of {EVM_NATIVE, ERC20, UTXO}).
- (mainnet OR testnet) AND any synthetic flag (assets/markets/liquidity) true.
- Any ENABLED market references an asset not in the registry (unknown/synthetic), references a disabled asset, or spans a network mismatch.
- Any registered asset carries a forbidden reference: a Liquidity (white-label) universe chain, mock/synthetic/phantom liquidity, an ASCII-ticker asset id, or a declared-but-unbacked credit shape. (The positive reality check happened at Register; this is the residual deny-scan over whatever is enabled, plus the Liquidity/mock label scan that reality alone would not catch.)
It returns nil ONLY when the registry is fully real and the policy is locked down for the network. Anything ambiguous fails closed.
chainLabelFor maps a source chain id to its human label so the off-network-universe scan can run; pass a function that yields "" for unknown ids (an unknown id simply cannot be a known white-label universe, and its asset already passed the reality gate at Register).
Types ¶
type Asset ¶
type Asset struct {
// NetworkID is the Lux network this asset lives on (1 mainnet, 2 testnet, ...).
NetworkID uint32 `json:"networkID"`
// ChainID is the SOURCE chain id: the C-Chain id for EVM_NATIVE/ERC20, the
// UTXO source-chain id (X-Chain) for UTXO.
ChainID ids.ID `json:"chainID"`
// Kind is the asset class (EVM_NATIVE | ERC20 | UTXO).
Kind AssetKind `json:"assetKind"`
// CanonicalRef is the on-chain reference bytes: the 20-byte ERC-20 address, the
// 20-byte native marker, or the 32-byte UTXO assetID. Hex-encoded in JSON.
CanonicalRef Bytes `json:"canonicalRef"`
// Decimals is the asset's on-chain decimal precision (ERC-20 decimals(),
// native/UTXO denomination). Verified against chain state for ERC-20.
Decimals uint8 `json:"decimals"`
// Symbol/Name are display metadata. They are NOT identity (the AssetID does not
// hash them) and they are NOT a ticker-id — an asset is keyed by AssetID, never
// by Symbol. They exist for the UI only.
Symbol string `json:"symbol"`
Name string `json:"name"`
// Enabled gates whether this asset (and markets over it) may trade. A disabled
// asset stays registered (auditable) but admits no markets.
Enabled bool `json:"enabled"`
// RiskTier is the operator risk classification (caps input, not admissibility).
RiskTier RiskTier `json:"riskTier"`
}
Asset is a single registered, real, on-chain asset. Its AssetID is DERIVED from the canonical fields (networkID, chainID, assetKind, canonicalRef) — never supplied independently — so the identity and the description can never disagree.
This is the AssetRegistry record the task specifies:
AssetRegistry{networkID, chainID, assetKind, canonicalRef, decimals, symbol, name, enabled, riskTier}
func (Asset) VerifyOnChain ¶
func (a Asset) VerifyOnChain(v ChainVerifier) error
VerifyOnChain proves the asset is real against live chain state via v, and that its declared decimals match what the chain reports. This is the gate that makes "synthetic asset" unrepresentable: a synthetic asset has nothing for the verifier to find, so VerifyOnChain returns an error and the asset is never admitted.
type AssetKind ¶
type AssetKind uint8
AssetKind is the CLOSED set of asset classes the DEX admits. There are exactly three. There is NO synthetic / D-native / declared class — adding one is a breaking change to the wire identity and is intentionally hard.
const ( // AssetKindInvalid is the zero value and is never admissible. Keeping it at 0 // means a zero-initialised struct fails closed. AssetKindInvalid AssetKind = 0 // AssetKindEVMNative is the C-Chain native coin (e.g. LUX on the primary // network's C-Chain). Its on-chain reference is the fixed native marker. AssetKindEVMNative AssetKind = 1 // AssetKindERC20 is an ERC-20 token deployed on the C-Chain. Its on-chain // reference is the 20-byte token contract address. AssetKindERC20 AssetKind = 2 // AssetKindUTXO is a UTXO-model asset native to the X-Chain (or another // UTXO source chain). Its on-chain reference is the source-chain assetID. AssetKindUTXO AssetKind = 3 )
func ParseAssetKind ¶
ParseAssetKind is the imperative form of UnmarshalText for callers that hold a plain string (manifest loaders, the allowed-kinds policy parser).
func (AssetKind) MarshalText ¶
MarshalText/UnmarshalText make AssetKind round-trip through JSON as its canonical token (EVM_NATIVE / ERC20 / UTXO), never as a bare integer. An unknown token — including any ASCII-ticker masquerading as a kind — fails closed.
func (AssetKind) String ¶
String renders the kind as its canonical wire/JSON token. These exact strings appear in manifests and in the dexAllowedAssetKinds policy; they are part of the contract, not cosmetic.
func (*AssetKind) UnmarshalText ¶
type Bytes ¶
type Bytes []byte
Bytes is a []byte that marshals to/from hex in JSON, used for canonicalRef so a manifest carries token addresses and assetIDs as 0x-hex rather than base64.
func (Bytes) MarshalText ¶
func (*Bytes) UnmarshalText ¶
type CChainConfirmer ¶
type CChainConfirmer interface {
ConfirmCChain(networkID uint32, evmChainID uint64, cChainID ids.ID) error
}
CChainConfirmer is the optional manifest-level check a verifier may implement to confirm, before any asset lookup, that the C-Chain it is talking to is the one the manifest declares: the live eth_chainId equals EVMChainID and the live C-Chain consensus id equals CChainID. The RPC validator implements it (so a manifest is never validated against the wrong chain); a local in-process verifier may not need to and can omit it. ApplyTo runs it first when present.
type ChainVerifier ¶
type ChainVerifier interface {
// VerifyERC20 confirms a contract exists at addr on the given C-Chain of the
// given network (code length > 0) and returns its on-chain decimals(). An error
// means the token is not real there (no code, wrong chain, RPC failure) and the
// asset MUST be refused.
VerifyERC20(networkID uint32, cChainID ids.ID, addr []byte) (decimals uint8, err error)
// VerifyEVMNative confirms the C-Chain itself is the expected native chain for
// the network (chainID matches) and returns the native decimals.
VerifyEVMNative(networkID uint32, cChainID ids.ID) (decimals uint8, err error)
// VerifyUTXOAsset confirms a UTXO assetID exists on the given source chain of
// the given network and returns its denomination (decimals). An error means the
// asset does not exist there and MUST be refused.
VerifyUTXOAsset(networkID uint32, sourceChainID ids.ID, assetID ids.ID) (decimals uint8, err error)
}
ChainVerifier proves an asset is REAL on its target network by reading live chain state. It is injected so the registry's admission logic is identical whether it runs offline in CI (a verifier backed by JSON-RPC against the target net) or at node startup (a verifier backed by the local chain state). Tests inject a verifier backed by an in-memory chain snapshot — the rejection paths are exercised for real, never stubbed to always-true.
type ConsensusMode ¶
type ConsensusMode uint8
ConsensusMode is the CLOSED set of consensus postures under which the DEX may activate NATIVE VALUE (real-money trading). There are exactly two legal value modes plus the zero value; the guard is exhaustive and any unmodelled value falls through to refusal. There is NEVER a silent third state.
const ( // ConsensusModeUnset is the zero value: no value mode declared. Value activation // under it is always refused (fail-closed). ConsensusModeUnset ConsensusMode = 0 // ConsensusModeQuorumFinality is post-quantum BFT with quorum finality (the // consensus round-2 work). It provides Byzantine fault tolerance, so a value // activation under it may legitimately claim Byzantine-finality safety. ConsensusModeQuorumFinality ConsensusMode = 1 // ConsensusModeHonestValidatorLabeled is a DELIBERATE, LABELED crash-fault-tolerant // (CFT) parity mode: the validator set is assumed honest-but-crash-prone, NOT // Byzantine. It is a legitimate launch posture, but it MUST NOT be presented as // Byzantine-finality. Activating value under it is permitted ONLY when it asserts // the launch safety bundle (caps-on + real-assets-only + halt-ready) and surfaces // an explicit "no Byzantine-finality claim" status string. It is the only other // legal value mode. ConsensusModeHonestValidatorLabeled ConsensusMode = 2 )
func ParseConsensusMode ¶
func ParseConsensusMode(s string) (ConsensusMode, error)
ParseConsensusMode parses the canonical token. An unknown token is refused (it must not silently become a third state).
func (ConsensusMode) String ¶
func (m ConsensusMode) String() string
String renders the mode as its canonical token.
type DexAssetPolicy ¶
type DexAssetPolicy struct {
// AllowSyntheticAssets, AllowSyntheticMarkets, AllowMockLiquidity default false.
// On a value-bearing network (mainnet/testnet) any true value fails startup. On
// a dev network a true value is permitted (developer opt-in) but is still subject
// to the forbidden-reference scan (Liquidity is never allowed, anywhere).
AllowSyntheticAssets bool `json:"dexAllowSyntheticAssets"`
AllowSyntheticMarkets bool `json:"dexAllowSyntheticMarkets"`
AllowMockLiquidity bool `json:"dexAllowMockLiquidity"`
// AllowedAssetKinds is the active dexAllowedAssetKinds set. Empty is treated as
// the canonical default {EVM_NATIVE, ERC20, UTXO}; an explicit set may only ever
// be a SUBSET of those three — any other token is rejected by ParseAssetKind.
AllowedAssetKinds []AssetKind `json:"dexAllowedAssetKinds"`
}
DexAssetPolicy is the backend-enforced, fail-closed configuration for the DEX's real-assets-only posture. Every field's SAFE value is the zero value, so a zero-initialised policy is the locked-down policy. These are the exact flags the task pins:
dexAllowSyntheticAssets = false dexAllowSyntheticMarkets = false dexAllowMockLiquidity = false dexAllowedAssetKinds = [EVM_NATIVE, ERC20, UTXO]
They are NOT front-end toggles: they live in the VM config and are read once at Initialize. A front end cannot relax them.
func DefaultDexAssetPolicy ¶
func DefaultDexAssetPolicy() DexAssetPolicy
DefaultDexAssetPolicy returns the canonical locked-down policy: no synthetic anything, all three real kinds allowed.
func (DexAssetPolicy) AllowedKindsOrDefault ¶
func (p DexAssetPolicy) AllowedKindsOrDefault() []AssetKind
AllowedKindsOrDefault is the exported effective allowed-kind set (the canonical three when unset, else the configured subset), used by the node to seed a Registry. It returns a fresh slice the caller may not mutate the policy through.
func (DexAssetPolicy) AnySyntheticFlag ¶
func (p DexAssetPolicy) AnySyntheticFlag() bool
AnySyntheticFlag is the exported predicate: true iff any synthetic/mock flag is set. The node uses it to MACHINE-DERIVE the HONEST_VALIDATOR_LABELED "real-assets-only" assertion rather than trusting an operator-supplied claim.
type LaunchAssertions ¶
type LaunchAssertions struct {
// CapsOn asserts per-asset / per-market notional caps are enforced (bounding the
// blast radius of a crash-fault or operator error during the CFT launch window).
CapsOn bool
// RealAssetsOnly asserts the asset registry admits only EVM_NATIVE|ERC20|UTXO and
// no synthetic asset/market/liquidity is enabled (the property this whole package
// enforces).
RealAssetsOnly bool
// HaltReady asserts the halt control is wired and reachable, so the chain can be
// stopped fast if the honest-validator assumption is violated.
HaltReady bool
}
LaunchAssertions is the safety bundle a HONEST_VALIDATOR_LABELED activation MUST satisfy. It is the explicit, auditable record that the CFT-parity launch is running with the compensating controls that justify it. Every field MUST be true for value to activate under that mode; a false field is a refusal.
type Manifest ¶
type Manifest struct {
// Network is the canonical network name this manifest applies to. It must match
// the deploy target; a mismatch is a hard error (you cannot ship the testnet
// manifest to mainnet).
Network string `json:"network"`
// NetworkID is the Lux networkID (1 mainnet, 2 testnet, ...) every asset/market
// in this manifest must declare. A per-entry networkID that disagrees is rejected.
NetworkID uint32 `json:"networkID"`
// EVMChainID is the C-Chain's EVM chainID (eth_chainId): 96369 mainnet, 96368
// testnet, 96370 devnet, 1337 localnet. It is the AUTHORITATIVE, RPC-checkable
// identity of the C-Chain — the CI validator confirms the target RPC's
// eth_chainId equals this before admitting any ERC-20/native entry, so a manifest
// can never be validated against the wrong chain.
EVMChainID uint64 `json:"evmChainID"`
// CChainID is the canonical C-Chain CONSENSUS id (the P-Chain blockchain id, an
// ids.ID) used in the AssetID preimage so a derived AssetID lives in the same
// identity space as the on-chain atomic objects. It is network-specific and is
// confirmed by the CI validator against the live P-Chain (platform.getBlockchains)
// — the validator REFUSES to proceed if the manifest's CChainID is not the C-Chain
// the target net actually runs. EVM_NATIVE/ERC20 entries are rooted here; an entry
// whose chainID disagrees is rejected (so a manifest cannot point an "ERC20" at a
// non-C chain).
CChainID ids.ID `json:"cChainID"`
// ChainLabels maps a source chain id (hex) to its human label, consumed by the
// forbidden-reference deny-scan (so the off-network-universe check has labels to
// test). Optional; an unlabeled chain simply has no white-label name to match.
ChainLabels map[string]string `json:"chainLabels,omitempty"`
// Assets and Markets are the declared real entries.
Assets []Asset `json:"assets"`
Markets []Market `json:"markets"`
}
Manifest is the on-disk, per-network declaration of the REAL assets and markets the DEX admits on that network. There is exactly one manifest per network (assets.devnet.json, assets.testnet.json, assets.mainnet.json). Every entry must be real on the named network; CI proves this against the network's RPC before any deploy, and the node re-proves it (or trusts the CI-validated artifact and re-runs the deny-scan) at startup.
The manifest is the SINGLE source of truth for what trades. It does not carry the derived AssetIDs/MarketIDs — those are computed from the canonical fields so the file cannot disagree with the identity.
func EmbeddedManifestFor ¶
EmbeddedManifestFor loads, content-hashes, and shape-validates the committed manifest for an EVM chainID, returning the parsed manifest and the manifest bytes' SHA-256 (lowercase hex). It performs the SAME shape validation LoadManifest does. It is the node-side entry point that replaces a filesystem LoadManifest: the bytes are the ones compiled into the binary, so there is no on-disk file to tamper with.
A chainID with no committed manifest returns ErrNoEmbeddedManifest (the localnet / unknown-chain case the caller handles explicitly).
func LoadManifest ¶
LoadManifest reads and JSON-decodes a manifest file. It does NOT verify against chain state (that is ApplyTo, which needs a verifier) — it only parses and structurally validates the shape. A malformed kind/ref/tier fails here.
func LoadManifestPinned ¶
LoadManifestPinned reads a manifest and REFUSES it unless its content SHA-256 equals expectedSHA256 (lowercase hex, with or without a "0x"/"sha256:" prefix). This is the M1 fix: a node verifies the manifest it loads is BYTE-IDENTICAL to the artifact CI approved and pinned in genesis/config — the dexvm proxy holds NO EVM state, so it cannot eth_getCode the tokens itself; the content-hash binding is what stops a locally edited manifest (a fabricated token address) from being loaded.
An empty expectedSHA256 means "no pin configured" and falls back to LoadManifest (shape validation only) — pinning is opt-in per deployment, but once a hash is set the file must match it exactly. A malformed expected hash is itself an error (fail-closed).
func LocalnetNativeManifest ¶
LocalnetNativeManifest synthesises the localnet (chainID 1337) manifest IN MEMORY, containing ONLY the C-Chain native coin, rooted at the node's LIVE runtime ids (networkID, cChainID). It exists because localnet's C-Chain consensus id is not fixed across genesis runs, so no committed manifest can pin it — but the native coin is ALWAYS a real, known asset on any localnet C-Chain (it is the chain's own coin), so admitting exactly it (and nothing else) keeps localnet swaps live out-of-the-box while every ERC-20 must still be registered explicitly (its address is unknown until it is deployed). The cChainID comes from the runtime, NEVER a constant — so the resulting resolver is identity-bound exactly like the committed-manifest path.
networkID must be the localnet convention id (1337); cChainID must be the node's live C-Chain consensus id (non-empty). The returned manifest passes validateShape.
func (*Manifest) AdmitInto ¶
func (m *Manifest) AdmitInto(reg *Registry, v ChainVerifier) error
AdmitInto registers every manifest asset (each proven real against v) and creates every manifest market (each pinned to two registered assets) into reg, WITHOUT running the fail-closed startup gate. It is the admission half of ApplyTo, separated so a caller that owns the gate (the node, which runs the gate once with its own network class + policy) does not run it twice. ApplyTo == AdmitInto + RefuseUnderSyntheticConfig.
func (*Manifest) ApplyTo ¶
func (m *Manifest) ApplyTo(reg *Registry, v ChainVerifier, policy DexAssetPolicy) error
ApplyTo registers every manifest asset and creates every manifest market into reg, proving each asset real against v, then runs the fail-closed startup gate for the manifest's network class and the given policy. It is the ONE routine that turns a manifest into a live, gated registry — used identically by CI (with an RPC verifier) and by node startup (with the local-chain verifier).
The order is: confirm the C-Chain identity (if v can), register assets (each VerifyOnChain), create markets (each pinned to two registered assets), then RefuseUnderSyntheticConfig (the residual deny-scan + enabled-market audit). Any failure aborts and is returned; reg is left partially populated only on error (callers discard it).
func (*Manifest) ChainLabelFor ¶
ChainLabelFor is the exported deny-scan label function for this manifest, used by the node startup gate to run the off-network-universe / forbidden-reference scan with the manifest's declared chain labels.
func (*Manifest) Validate ¶
func (m *Manifest) Validate(v ChainVerifier) (*Registry, error)
Validate is the full CI check for one manifest against one verifier: load is done by the caller (LoadManifest); this proves every entry real and gate-clean using a fresh registry under the canonical locked-down policy. It returns the populated registry so a caller can report what was admitted.
type Market ¶
type Market struct {
// NetworkID must match both assets' networks (a market does not span networks).
NetworkID uint32 `json:"networkID"`
// BaseAssetID / QuoteAssetID are canonical AssetIDs of registered assets.
BaseAssetID ids.ID `json:"baseAssetID"`
QuoteAssetID ids.ID `json:"quoteAssetID"`
// VenueConfig is the canonical serialization of the venue parameters (tick, lot,
// fee tier) that distinguish two venues on the same pair. Hex in JSON.
VenueConfig Bytes `json:"venueConfig"`
// Enabled gates whether the market trades. A disabled market is still pinned to
// real assets; it simply admits no orders.
Enabled bool `json:"enabled"`
}
Market is an admitted trading pair. Both sides are pinned to registered, real, enabled assets by construction: a Market cannot be created (CreateMarket) unless both BaseAssetID and QuoteAssetID resolve in the registry. The MarketID is DERIVED from the two AssetIDs and the venue config, never supplied — so a market's identity is structurally bound to its real assets.
type NetworkClass ¶
type NetworkClass uint8
NetworkClass distinguishes the value-bearing networks (mainnet, testnet — where synthetic anything is forbidden) from dev networks (devnet/local — where a developer may opt into synthetic assets for testing, but ONLY there).
const ( NetworkClassDev NetworkClass = 0 // devnet / localnet — synthetic flags MAY be set NetworkClassTestnet NetworkClass = 1 // testnet — synthetic flags FORBIDDEN NetworkClassMainnet NetworkClass = 2 // mainnet — synthetic flags FORBIDDEN )
func NetworkClassFor ¶
func NetworkClassFor(networkID uint32) NetworkClass
NetworkClassFor maps a Lux networkID to its class using the convention-fixed ids (1 mainnet, 2 testnet, 3 local, 1337 localnet) and treats every other id as a sovereign/dev network. Mainnet and testnet are the only value-bearing classes.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is the in-memory set of admitted real assets, keyed by canonical AssetID. It is the authority every admission decision consults. It is concurrency-safe; the hot path (Resolve) is a read under RLock.
func New ¶
New constructs an empty Registry permitting the given asset kinds. With no kinds it admits nothing (fail-closed). The canonical production policy is all three: {EVM_NATIVE, ERC20, UTXO}.
func (*Registry) AllowsKind ¶
AllowsKind reports whether the active policy admits k.
func (*Registry) CreateMarket ¶
CreateMarket admits a market ONLY if BOTH sides resolve to a registered, enabled, real asset on the SAME network as the market. This is the structural enforcement of "no synthetic market": there is no AssetID for a synthetic asset, so a market over one cannot resolve, so it cannot be created. The market is stored in the registry and its derived MarketID returned.
The check order is deliberate and fail-closed: resolve base, resolve quote, reject self-pair, reject network mismatch, reject duplicate. Any failure leaves the registry unchanged.
func (*Registry) Each ¶
Each iterates registered assets (id, asset) in unspecified order. Used by the startup gate to audit every registered asset and by the manifest exporter.
func (*Registry) EachMarket ¶
EachMarket iterates registered markets. Used by the startup gate to audit that every enabled market references only real, registered assets.
func (*Registry) MustResolveEnabled ¶
MustResolveEnabled returns the asset for id, erroring if it is unknown (synthetic) or disabled. It is the strict resolver the market gate uses.
func (*Registry) Register ¶
Register admits a single asset after proving it is (a) well-formed, (b) of an allowed kind, and (c) REAL on its target network via v. It is the ONLY way an asset enters the registry — there is no path that admits an unverified asset. The derived AssetID is returned so callers can pin markets to it.
type RiskTier ¶
type RiskTier uint8
RiskTier is an operator-assigned risk classification for an asset. It is metadata (it does not gate admissibility — only REALITY gates admissibility), used by the venue to set conservative caps on newer/lower-tier assets. Tier0 is the safest (the primary-network native coin and blue-chip stables); higher numbers are riskier.
type RuntimeVerifier ¶
type RuntimeVerifier struct {
// NetworkID is the node's running network id (runtime.Runtime.NetworkID).
NetworkID uint32
// CChainID is the node's running C-Chain consensus id (runtime.Runtime.CChainID).
// EVM_NATIVE / ERC20 assets must be rooted here.
CChainID ids.ID
// XChainID is the node's running X-Chain id (runtime.Runtime.XChainID). UTXO assets
// are accepted only from a UTXO source chain the node actually runs; when XChainID
// is set, a UTXO asset rooted off it is refused.
XChainID ids.ID
// contains filtered or unexported fields
}
RuntimeVerifier is the node-side ChainVerifier used at VM Initialize. It is a REAL check, not a stub: it binds a manifest's DECLARED chain identities to the node's ACTUAL running chain ids (the consensus-supplied C-Chain and X-Chain ids), so a manifest built for the wrong network — or one that points an "ERC20" at a chain the node is not running — is REFUSED at startup. It returns the manifest's shape-validated decimals only AFTER that identity binding holds.
Division of proof (deliberate, documented):
- The NODE (this verifier) proves chain-IDENTITY binding + structure + policy at boot, with NO external RPC dependency (so a validator can start even if a remote RPC is briefly unreachable). It catches a wrong-net / wrong-chain manifest.
- CI (the rpcverify.Verifier + the validate-asset-manifests workflow) proves each token EXISTS on the live target net (eth_getCode length > 0, decimals(), UTXO avm.getAssetDescription) BEFORE the manifest artifact ships. It catches a fabricated/typo'd token address.
Both are real, neither is "always true". A manifest that passes CI (reality) and the node's RuntimeVerifier (identity + policy) is admissible; either failing refuses it.
func NewRuntimeVerifier ¶
func NewRuntimeVerifier(networkID uint32, cChainID, xChainID ids.ID, m *Manifest) (*RuntimeVerifier, error)
NewRuntimeVerifier builds a RuntimeVerifier bound to the node's running chain ids and pre-loaded with the manifest's shape-validated decimals (so Register's decimals cross-check compares the manifest against itself consistently, and the identity bind is what gates admission). m must already have passed validateShape.
func (*RuntimeVerifier) ConfirmCChain ¶
ConfirmCChain implements CChainConfirmer: the manifest's network + C-Chain id must equal the node's running ids. (EVMChainID is RPC-checked by CI; at boot we bind the consensus C-Chain id, which is the authoritative cross-chain identity.)
func (*RuntimeVerifier) VerifyERC20 ¶
func (rv *RuntimeVerifier) VerifyERC20(networkID uint32, cChainID ids.ID, addr []byte) (uint8, error)
VerifyERC20 binds the ERC-20 to the node's running C-Chain. Per-token code existence is the CI gate; here the asset must be on the chain the node actually runs.
func (*RuntimeVerifier) VerifyEVMNative ¶
VerifyEVMNative binds the native coin to the node's running C-Chain.
func (*RuntimeVerifier) VerifyUTXOAsset ¶
func (rv *RuntimeVerifier) VerifyUTXOAsset(networkID uint32, sourceChainID ids.ID, assetID ids.ID) (uint8, error)
VerifyUTXOAsset binds the UTXO asset to a UTXO source chain the node runs. When the node's XChainID is known, a UTXO asset rooted off it is refused (you cannot import a UTXO asset from a chain this node does not run).
type ValueModeStatus ¶
type ValueModeStatus struct {
Mode ConsensusMode
Status string // NoByzantineFinalityClaim for HONEST_VALIDATOR_LABELED, "" for QUORUM_FINALITY
}
ValueModeStatus is the outcome of a successful value-activation guard check: the mode that authorised it and, for the labeled CFT-parity mode, the explicit "no Byzantine-finality claim" status string to surface. For QUORUM_FINALITY the status is empty (Byzantine finality is genuine, so no disclaimer is required).
func GuardValueActivation ¶
func GuardValueActivation(dexNativeValueEnabled bool, mode ConsensusMode, assertions LaunchAssertions) (ValueModeStatus, error)
GuardValueActivation is THE consensus-mode value guard. It decides whether the DEX may activate native value under the given consensus mode, and returns the status the activation must surface.
Semantics (exactly as required):
if !dexNativeValueEnabled -> no value to gate; returns the unset status, nil.
if mode == QUORUM_FINALITY -> permitted (PQ BFT); status "".
if mode == HONEST_VALIDATOR_LABELED -> permitted ONLY if assertions.ok();
status = NoByzantineFinalityClaim.
otherwise (UNSET or any other value) -> REFUSED. Never a silent third state.
The default arm refuses, so an unmodelled or zero mode can never accidentally authorise value.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package rpcverify is the REAL, network-backed ChainVerifier used by CI (and any out-of-process validator) to prove a manifest's assets exist on the TARGET net before a deploy.
|
Package rpcverify is the REAL, network-backed ChainVerifier used by CI (and any out-of-process validator) to prove a manifest's assets exist on the TARGET net before a deploy. |