Files
proxmox/hybx_routing_graph_data_model.md
defiQUG 6c5fdcfd62 chore: pnpm lockfile, info-defi-oracle-138 app, token-lists, OMNL discovery output
- Refresh pnpm-lock.yaml / workspace after prior merge
- Add Chain 138 info hub SPA (info-defi-oracle-138)
- Token list and validation script tweaks; path_b report; Hyperledger proxmox install notes
- HYBX implementation roadmap and routing graph data model

Note: transaction-composer is a nested git repo — convert to submodule before tracking.
Made-with: Cursor
2026-03-31 22:32:15 -07:00

18 KiB
Raw Blame History

HYBX Routing Graph Data Model

Purpose: Define the canonical routing graph used by the Compliance & Routing Sidecar (see hybx_compliance_routing_sidecar_technical_plan.md) for graph-based pathfinding, liquidity resolution, fee path construction, and jurisdiction-aware routing. This is the mathematical backbone for nostro pathfinding, multi-bank routing, liquidity selection, and failover as alternate paths on the same graph.

Audience: Engineers implementing the Routing Engine, orchestration adapters, and registry services.

Non-goals: Policy DSL grammar, liquidity registry service APIs, explanation-engine templates, and failover algorithms are specified elsewhere.


1. Purpose and scope

The routing graph models the operational payment network relevant to a transaction: institutions, account corridors, liquidity pools, FX venues, settlement rails, fee agents, and beneficiary anchors, connected by directed, weighted relationships.

  • In scope: Vertex types, edge types, cost vectors, liquidity and fee metadata, jurisdiction overlays, serialization, versioning, and mapping from the Transaction Composer compile output.
  • Out of scope: Specific shortest-path or MOCO (multi-objective) solver implementations; this document defines inputs those solvers consume.

The Transaction Composer UI produces a design-time pipeline graph (user intent). The sidecar may project that into one or more routing subgraphs and enrich them with edges and weights that are not drawn in the UI (e.g. alternate correspondents, backup rails).


2. Conceptual model

Let G = (V, E) be a directed graph with:

  • V: typed vertices (routing nodes).
  • E: typed directed edges with metadata and costs.

2.1 Two layers

Layer Meaning Typical source of truth
Topology Durable relationships: who may route to whom, which rails exist, static eligibility. Reference data, contracts, registry
Snapshot Time-bound overlays: available liquidity, current fee quotes, latency estimates, risk adjustments for this evaluation. Pool registry, market data, sidecar snapshot builder

At evaluation time, the engine consumes a materialized view: topology snapshot overlays. The JSON envelope below supports both.

2.2 Relationship to sidecar API

The sidecar plan describes POST /evaluate-transaction with transactionGraph and responses including routingPlan. This document defines the shape of the network graph (and fragments thereof) that backs routingPlan generation—not the full HTTP schema.


3. Vertex (node) types

Vertices are discriminated by vertexKind. All vertices share a common base; extensions are kind-specific.

3.1 Base fields (all kinds)

Field Type Required Description
id string yes Stable unique id in this graph (UUID or registry key).
vertexKind enum yes One of the kinds below.
displayName string no Human label.
jurisdiction string yes ISO-3166 alpha-2, or internal jurisdiction code (e.g. ID-JK).
identifiers object no bic, lei, internalOrgId, etc.
capabilities object no See below.
riskTier string | number no Opaque tier for risk engine (e.g. T1T3).
metadata object no Opaque extensibility.

Capabilities object (optional, common pattern):

{
  "currenciesAllowed": ["USD", "IDR"],
  "fxPermitted": true,
  "settlementTypes": ["RTGS", "ACH"],
  "maxSingleTransfer": { "amount": "1000000000", "currency": "USD" }
}

3.2 Vertex kind: Institution

Legal or operational entity (bank, CB, PSP). Maps from composer participants and some operational nodes.

3.3 Vertex kind: AccountCorridor

Abstract nostro/vostro or nostro-like relationship endpoint—not necessarily one ledger row. Used for pathfinding between institutions.

  • Typical use: attach liquidity and correspondent edges to corridors.

3.4 Vertex kind: LiquidityPool

A source of fungible liquidity in a currency (or synthetic pool id).

  • Should align with sidecar liquidity sketch: currency, amount, provider, expiry (carried in snapshot overlay on the pool or on incident edges).

3.5 Vertex kind: FxVenue

FX conversion capability (desk, LP, internal book).

3.6 Vertex kind: SettlementRail

Logical settlement channel (RTGS system, chain leg, internal settlement batch).

3.7 Vertex kind: FeeAgent

Optional dedicated vertex when fees are not folded into Institution (e.g. third-party fee collector).

3.8 Vertex kind: BeneficiaryAnchor

Terminal or near-terminal node representing beneficiary credit location (could be institution + product, or a logical “credit to PT Parak at Bank Kanaya”).


4. Edge types

Edges are directed: (sourceId, targetId). Each edge has:

Field Type Required Description
id string yes Unique edge id.
sourceId string yes Vertex id.
targetId string yes Vertex id.
edgeKind enum yes See below.
costVector object yes Normalized costs (section 5).
jurisdictions string[] no Tags for crossing rules; default may inherit from endpoints.
validFrom / validTo string (ISO-8601) no Validity window for this edge.
policyRefs string[] no Opaque ids for future Policy DSL bindings.
liquidityRef string no Pool or line id when edge represents funding.
feeRef string no Link to fee schedule id.
metadata object no Extensibility.

4.1 Edge kind: correspondent

Bank-to-bank (or institution-to-institution) routing leg; may attach to AccountCorridor vertices or directly to Institution depending on model granularity.

Connects a pool to a corridor, venue, or institution consumption point.

4.3 Edge kind: fx_quote

Connects currency/state A to B through an FxVenue (often modeled as two edges via the venue, or one bundled edge with pair metadata in metadata).

4.4 Edge kind: fee_hop

Explicit fee accrual or pass-through segment (supports building a fee propagation tree as a subgraph).

4.5 Edge kind: settlement_path

Connects to or from a SettlementRail or BeneficiaryAnchor.


5. Weights and multi-criteria cost

The sidecar Routing Engine (see technical plan) uses a weighted directed graph with dimensions including fee cost, latency, and liquidity availability.

5.1 costVector (required on every edge)

Recommended normalized fields (all optional numbers except at least one should be present for pathfinding):

Key Meaning Units / notes
feeCost Expected monetary cost of traversing this edge Normalized to a reference currency in snapshot builder, or raw with feeCurrency in metadata
latencyMs Expected processing time Milliseconds or representative score
liquidityAvailability How “easy” it is to fund this hop 01 score, or available notional on this hop
regulatoryPenalty Additive penalty from policy Non-negative; 0 if none
reliability Historical success / health 01, can be inverted by solver

Example:

"costVector": {
  "feeCost": 1250.5,
  "latencyMs": 800,
  "liquidityAvailability": 0.92,
  "regulatoryPenalty": 0,
  "reliability": 0.995
}

5.2 Aggregation strategy (normative intent, not algorithm)

Path cost is a multi-criteria problem:

  1. Hard constraints: e.g. minimum liquidity availability, blocked jurisdictions, expired validTo.
  2. Scalarization: weighted sum w1*feeCost + w2*latencyMs + w3*(1-liquidityAvailability) + w4*regulatoryPenalty + w5*(1-reliability) with configurable weights per product lane.
  3. Pareto / k-shortest: optional second phase to present alternates for failover UX.

Exact solver choice is implementation-defined; this document standardizes what is measured on each edge.


6. Liquidity metadata

Aligned with the sidecar liquidity model (currency, amount, provider, expiry):

On LiquidityPool vertex or liquidity_link edge (snapshot):

Field Description
poolId Registry identifier
currency ISO-4217
availableAmount Decimal string recommended
providerId Institution or LP id
expiresAt ISO-8601
refreshTtlSeconds Optional hint for cache

7. Fee metadata

Fees may be attached to fee_hop edges or embedded in correspondent / settlement_path via feeRef.

Suggested fields (snapshot or static):

Field Description
feeModel percent, flat, tiered, conditional
bps Basis points if percent
flatAmount If flat
currency Fee currency
conditionRef Opaque id for conditional rules (Policy DSL later)

Fee propagation tree: Derived by taking the subgraph induced by fee_hop edges (and optionally fee-bearing segments), orienting edges in flow direction, and interpreting parent/child as payer → collector → onward. The routing graph remains the single source of truth; the tree is a view, not a second graph.


8. Jurisdiction overlays

  • Node default: Each vertex has a primary jurisdiction.
  • Edge override: jurisdictions[] on an edge marks crossing or rule buckets (e.g. US-OFAC, EU-PII).
  • Transaction-level filter: Evaluation request may supply transactionJurisdictions or denyJurisdictionTags; the pathfinder prunes edges violating hard policy (details in Policy DSL doc).

Compliance outcomes (PASS / WARN / FAIL) are produced by the Compliance Engine; this model only supplies tags and penalties (regulatoryPenalty) consumed by routing.


9. Mapping from Transaction Composer

The Transaction Composer (transaction-composer/) compiles UI graphs into CompiledTransaction with buckets: participants, nostroAccounts, liquidity, fx, fees, settlement, plus topology.

Composer is a pipeline; routing graph is a network. The table below is a projection guide, not a 1:1 id equality (routing vertices may be created per registry lookup).

Composer source Compiler bucket / NodeKind Typical routing vertex kind(s) Notes
Central / commercial / remittance bank participants (centralBank, commercialBank, remittanceInstitution) Institution Map institution string to registry id; participantRole informs source vs beneficiary anchor.
Nostro nostroAccounts AccountCorridor, Institution Often one corridor per nostro relationship.
Liquidity liquidity (liquidityProvider) LiquidityPool, Institution, liquidity_link Pool may be resolved via Liquidity Pool Registry.
FX fx (fxConversion) FxVenue, fx_quote edges May expand to venue + pair legs.
Fees fees (feeRouter) FeeAgent or Institution, fee_hop Multiple fee nodes become multiple hops or a small fee subgraph.
Settlement settlement SettlementRail, BeneficiaryAnchor Beneficiary text may map to anchor + rail.
Topology edges topology.edges Mixed edgeKind Composer edges imply ordering; routing edges add weights and alternates.

Important: The composer topology.orderedNodeIds defines design order. The routing engine may introduce parallel paths (e.g. two correspondent edges) not present in the UI graph.


10. Serialization and versioning

10.1 JSON envelope

{
  "schemaVersion": "1.0.0",
  "graphId": "rg-2026-03-29-indonesia-demo",
  "effectiveAt": "2026-03-29T12:00:00Z",
  "vertices": [],
  "edges": [],
  "overlays": {
    "liquiditySnapshotId": "optional-registry-pointer",
    "feeScheduleSnapshotId": "optional",
    "notes": "optional"
  }
}

10.2 Stability rules

  • Patch (1.0.x): Add optional fields only; do not remove or rename required fields.
  • Minor (1.x.0): Add new vertexKind / edgeKind values; old consumers ignore unknown kinds if possible.
  • Major (x.0.0): Breaking renames or semantic changes.

11. Worked example (minimal)

Scenario aligned with composer demo intent: OMNL → BNI nostro/liquidity → USD/IDR FX → fees → settlement at Bank Kanaya; beneficiary PT Parak International. Includes one alternate correspondent edge as a failover hint (not expanded into full failover logic).

{
  "schemaVersion": "1.0.0",
  "graphId": "example-omnl-bni-kanaya",
  "effectiveAt": "2026-03-29T12:00:00Z",
  "vertices": [
    {
      "id": "v-omnl",
      "vertexKind": "Institution",
      "displayName": "OMNL",
      "jurisdiction": "ID",
      "identifiers": { "internalOrgId": "OMNL" },
      "capabilities": { "currenciesAllowed": ["USD"], "fxPermitted": false }
    },
    {
      "id": "v-bni",
      "vertexKind": "Institution",
      "displayName": "BNI",
      "jurisdiction": "ID",
      "identifiers": { "bic": "BNINIDJA" }
    },
    {
      "id": "v-nostro-bni-usd",
      "vertexKind": "AccountCorridor",
      "displayName": "BNI USD Nostro corridor",
      "jurisdiction": "ID",
      "identifiers": { "internalOrgId": "BNI", "currency": "USD" }
    },
    {
      "id": "v-pool-bni-usd",
      "vertexKind": "LiquidityPool",
      "displayName": "BNI USD pool",
      "jurisdiction": "ID",
      "metadata": {
        "currency": "USD",
        "availableAmount": "70000000000",
        "providerId": "v-bni",
        "expiresAt": "2026-03-29T18:00:00Z"
      }
    },
    {
      "id": "v-fx-bni",
      "vertexKind": "FxVenue",
      "displayName": "BNI FX",
      "jurisdiction": "ID",
      "capabilities": { "currenciesAllowed": ["USD", "IDR"], "fxPermitted": true }
    },
    {
      "id": "v-rail-id",
      "vertexKind": "SettlementRail",
      "displayName": "ID domestic settlement",
      "jurisdiction": "ID",
      "capabilities": { "settlementTypes": ["RTGS"] }
    },
    {
      "id": "v-kanaya",
      "vertexKind": "Institution",
      "displayName": "Bank Kanaya",
      "jurisdiction": "ID"
    },
    {
      "id": "v-parak",
      "vertexKind": "BeneficiaryAnchor",
      "displayName": "PT Parak International",
      "jurisdiction": "ID",
      "metadata": { "creditInstitutionId": "v-kanaya" }
    },
    {
      "id": "v-alt-correspondent",
      "vertexKind": "Institution",
      "displayName": "Alternate correspondent (failover candidate)",
      "jurisdiction": "ID"
    }
  ],
  "edges": [
    {
      "id": "e-omnl-nostro",
      "sourceId": "v-omnl",
      "targetId": "v-nostro-bni-usd",
      "edgeKind": "correspondent",
      "costVector": { "feeCost": 0, "latencyMs": 200, "liquidityAvailability": 1, "regulatoryPenalty": 0, "reliability": 0.999 }
    },
    {
      "id": "e-nostro-pool",
      "sourceId": "v-nostro-bni-usd",
      "targetId": "v-pool-bni-usd",
      "edgeKind": "liquidity_link",
      "liquidityRef": "pool-bni-usd-001",
      "costVector": { "feeCost": 0, "latencyMs": 50, "liquidityAvailability": 0.95, "regulatoryPenalty": 0, "reliability": 0.998 }
    },
    {
      "id": "e-pool-fx",
      "sourceId": "v-pool-bni-usd",
      "targetId": "v-fx-bni",
      "edgeKind": "liquidity_link",
      "costVector": { "feeCost": 0, "latencyMs": 100, "liquidityAvailability": 0.93, "regulatoryPenalty": 0, "reliability": 0.997 }
    },
    {
      "id": "e-fx-rail",
      "sourceId": "v-fx-bni",
      "targetId": "v-rail-id",
      "edgeKind": "fx_quote",
      "metadata": { "pair": "USD/IDR", "rateRef": "DEMO-15000" },
      "costVector": { "feeCost": 500, "latencyMs": 400, "liquidityAvailability": 0.9, "regulatoryPenalty": 0, "reliability": 0.996 }
    },
    {
      "id": "e-fee-compliance",
      "sourceId": "v-rail-id",
      "targetId": "v-kanaya",
      "edgeKind": "fee_hop",
      "feeRef": "fee-reg-omnl-bni",
      "costVector": { "feeCost": 200, "latencyMs": 50, "liquidityAvailability": 1, "regulatoryPenalty": 0, "reliability": 0.999 }
    },
    {
      "id": "e-settle-parak",
      "sourceId": "v-kanaya",
      "targetId": "v-parak",
      "edgeKind": "settlement_path",
      "costVector": { "feeCost": 0, "latencyMs": 300, "liquidityAvailability": 1, "regulatoryPenalty": 0, "reliability": 0.998 }
    },
    {
      "id": "e-omnl-alt-nostro",
      "sourceId": "v-omnl",
      "targetId": "v-alt-correspondent",
      "edgeKind": "correspondent",
      "costVector": { "feeCost": 800, "latencyMs": 350, "liquidityAvailability": 0.7, "regulatoryPenalty": 0, "reliability": 0.99 },
      "metadata": { "role": "failover_candidate" }
    }
  ],
  "overlays": {
    "liquiditySnapshotId": "demo-snapshot-001",
    "notes": "Demonstration only; ids and costs are illustrative."
  }
}

Next artifact What this routing graph doc provides
Policy DSL specification policyRefs on edges, regulatoryPenalty, jurisdiction tags, and constraint hooks for hard rejects.
Liquidity pool registry model Canonical poolId, refresh TTL, and binding to LiquidityPool vertices / liquidity_link edges.
Decision explanation engine Path trace over vertices/edges with human-readable labels and cost breakdowns from costVector.
Failover routing strategy model k-shortest paths, edge_disjoint alternates, and scoring on top of this graph without redefining V/E types.

References