Pairing

Pair Router

The Pair Router is PairStreet’s execution layer. It turns “this Pair Market holds X of the settlement asset” into an acquisition plan for the market’s Pair Asset, then hands the plan to the executor for its route.

Plan, then execute

The Pair RouterPair RouterThe execution layer that converts a Pair Vault's settlement balance into an acquisition plan for the Pair Asset and hands it to the right executor. has two functions. planAcquisition resolves the market’s Pair Instrument to a provider, asks that provider for a purchase route, and returns an AcquisitionPlan. executeAcquisition takes an executable plan and the vault address and returns a PurchaseExecution: units received, execution price and transaction signature.

Separating the two is deliberate. A plan is cheap, deterministic and safe to compute at any time: it is what the market page shows as the instrument’s route. Execution spends vault funds, so it runs only when the plan says it can and the vault has a signer.

Inputs and route modes

Settlement asset
The mint the vault holds before conversion. USDC by default; recorded on the plan as settlementMint.
Amount
The vault’s settlement balance in raw base units (inputAmountRaw). A settlement converts the full balance.
Pair Instrument
providerReference, providerId, status, reference price, decimals. The instrument names its provider.
Provider adapters
Resolved from the registry by providerId. Each returns a PurchaseRoute for the instrument.
Eligibility context
Instrument status is checked in every plan. Region and KYC rules are enforced at launch and claim by the provider’s checkEligibility.
Execution parameters
Slippage tolerance on the quote request (slippageBps, 50 bps default on onchain routes) and the market’s ledger mode.
Pair Router and its five route modesARCHITECTURE
Input
  • · Settlement asset
  • · Amount
  • · Pair Instrument
  • · Provider adapters
  • · Eligibility context
  • · Execution parameters
PAIR ROUTER
plan · execute
  • ONCHAIN_SWAPSwap the settlement asset into an SPL Pair Asset. Live Jupiter quotes for USDY, CETES, GILTS, XAUt0 and PAXG; execution activates with vault custody.Route ready
  • PROVIDER_APIAcquire through an issuer or platform API. Registry instruments plan against this mode while their route connects.Interface defined
  • RFQRequest quotes from liquidity desks for size or thin markets.Interface defined
  • ISSUER_MINTSubscribe directly with the issuer and receive newly minted Pair Asset.Interface defined
  • BROKER_ROUTEAcquire an offchain instrument through a broker that delivers a tokenized representation.Interface defined
Solid: the mode that plans against live market data today. Dashed: modes whose interface is defined and which activate as providers integrate.

Figure summary: Inputs: settlement asset, amount, Pair Instrument, provider adapters, eligibility context and execution parameters feed the Pair Router, which branches to five route modes. ONCHAIN_SWAP is route ready: planned with live Jupiter quotes for the five SPL instruments, with execution activating with Pair Vault custody. PROVIDER_API, RFQ, ISSUER_MINT and BROKER_ROUTE have their interfaces defined and activate per provider.

A sixth mode, DEV_SIMULATED, exists for the development network. The router refuses it outright for live markets: a live Pair Market can never settle through a simulated route, and a mock execution against a live plan throws.

The acquisition plan

These are the router’s types as they appear in the code. The plan carries everything needed to audit the decision later: which provider, which route, which quote, and whether it is executable.

src/server/pair/router.ts
// src/server/pair/router.ts
export type AcquisitionPlan = {
  pairMarketId: string;
  instrumentRef: string;
  providerId: string;
  settlementMint: string;
  inputAmountRaw: string;
  mode: RouteMode;
  route: PurchaseRoute;
  executable: boolean;
  blockers: string[];
  ledgerMode: LedgerMode;
  plannedAt: string;
};

export async function planAcquisition(input: PlanInput): Promise<AcquisitionPlan>;
export async function executeAcquisition(plan: AcquisitionPlan, vaultAddress: string): Promise<PurchaseExecution>;
src/server/adapters/providers/types.tsexcerpt
// src/server/adapters/providers/types.ts
export type RouteMode = "ONCHAIN_SWAP" | "PROVIDER_API" | "RFQ" | "ISSUER_MINT" | "BROKER_ROUTE" | "DEV_SIMULATED";

export type RouteStep = { kind: "swap" | "mint" | "rfq" | "transfer" | "simulated"; label: string; venue?: string };

export type PurchaseRoute = {
  mode: RouteMode;
  available: boolean;
  steps: RouteStep[];
  quote?: InstrumentQuote;
  /** Reasons the route cannot execute right now (missing signer, no liquidity, provider paused). */
  blockers: string[];
};

export type PurchaseExecution = {
  outputAmountRaw: bigint;
  executionPriceUsd: number;
  txSignature: string | null;
  isMock: boolean;
};
FieldMeaning
instrumentRefThe provider’s reference for the instrument, for example spl:<mint> or registry:<slug>.
settlementMintMint of the settlement asset being spent.
inputAmountRawAmount to convert, in base units, as a string to avoid float drift.
modeThe route mode the provider returned.
routeThe provider’s PurchaseRoute: steps, optional quote and its own blockers.
executableTrue only when the route is available and the plan has no blockers.
blockersReasons this plan is not executable yet, de-duplicated.
ledgerModelive, or dev_simulated for development-network routes. Copied onto every ledger row the plan produces.

Blockers

A plan is always produced, executable or not. Instead of failing, the router collects blockers: plain-language reasons from the provider’s route plus the router’s own checks. A plan is executable exactly when its route is available and the blocker list is empty.

  • ·Provider blockers. Returned in the route, for example “Pair Vault signer not configured (program PDA / multisig custody)”, or for a registry instrument “Settlement route for Tokyo Residential is connecting”.
  • ·Instrument status. Any status other than active adds “Instrument is paused” (or the current status).
  • ·Executor availability. A route mode without an executor in the deployed build adds a blocker naming the mode.
  • ·Ledger separation. Simulated routes outside development, or on a live market, are blocked.

Below is the shape of the plan the router produces today for a $10,000 settlement into UK Government Gilts. The route and quote are live; the blockers state exactly what activation requires. Quote values change with every request and are shown as placeholders.

AcquisitionPlan · uk-giltsshape of a live plan, quote abbreviated
{
  "pairMarketId": "<pair-market-id>",
  "instrumentRef": "spl:GiLTSeSFnNse7xQVYeKdMyckGw66AoRmyggGg1NNd4yr",
  "providerId": "etherfuse",
  "settlementMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "inputAmountRaw": "10000000000",
  "mode": "ONCHAIN_SWAP",
  "route": {
    "mode": "ONCHAIN_SWAP",
    "available": false,
    "steps": [{ "kind": "swap", "label": "Swap via <venue>", "venue": "<venue>" }],
    "quote": {
      "inputAmountRaw": "10000000000",
      "outputAmountRaw": "<quoted units, 6 decimals>",
      "outputDecimals": 6,
      "priceUsd": "<input USD / output units>",
      "priceImpactPct": "<from quote>",
      "source": "jupiter",
      "isMock": false
    },
    "blockers": [
      "Pair Vault signer not configured (program PDA / multisig custody)",
      "Settlement executor not deployed"
    ]
  },
  "executable": false,
  "blockers": [
    "Pair Vault signer not configured (program PDA / multisig custody)",
    "Settlement executor not deployed",
    "Route mode ONCHAIN_SWAP has no executor in this build"
  ],
  "ledgerMode": "live",
  "plannedAt": "<ISO timestamp>"
}

When a settlement runs against a non-executable plan with a positive balance, the engine writes a failed settlement row whose error is the joined blocker list, and the balance stays in the vault. The plan is stored on the row, so every attempt is auditable. See Settlement.

Route selection

Today each Pair Instrument names one provider (providerId), and the router asks that provider for its route. The router’s design extends to instruments that can be reached more than one way: each candidate route is evaluated for availability, eligibility and liquidity, quoted execution is compared, and one route is selected for the plan.

Selecting a route for a $10,000 acquisitionILLUSTRATIVE
Request
Acquire $10,000 Tokyo Residential exposure
Provider Aselected
PROVIDER_API
exec $9,968.40
fees $31.60
Available. Best quoted execution. Selected route.
Provider Brestricted
ISSUER_MINT
Eligibility rules exclude this market’s context.
Provider Cno liquidity
ONCHAIN_SWAP
No route deep enough for the requested size.
Providers are generic placeholders. Estimated execution plus fees equals the $10,000 request: $9,968.40 + $31.60.

Figure summary: Request: acquire $10,000 of Tokyo Residential exposure. Provider A is available through a provider API with estimated execution of $9,968.40 and fees of $31.60, and is selected. Provider B is restricted for the market’s eligibility context. Provider C has no liquidity for the requested size. The selected route is Provider A.

Selection order for multi-route instruments

  1. 01Drop candidates whose instrument status or eligibility rules exclude the market.
  2. 02Drop candidates that return no route or no liquidity for the amount.
  3. 03Compare remaining quotes on Pair Asset delivered per unit of settlement asset, net of fees and price impact.
  4. 04Write the selected route and its quote into the AcquisitionPlan, where it is stored with the settlement row.

Execution

executeAcquisition re-checks that the plan is executable, calls the provider’s purchase with the route, the vault address and the input amount, and returns the execution. For ONCHAIN_SWAP that is a Jupiter swap signed by the vault’s custody signer, which is why execution activates with Pair Vault custody.

Route modePlanningExecution
ONCHAIN_SWAPLive quotesActivates per route
PROVIDER_APIInterface definedActivates per route
RFQInterface definedActivates per route
ISSUER_MINTInterface definedActivates per route
BROKER_ROUTEInterface definedActivates per route

Each execution becomes a pair_purchases row with input, output, execution price and transaction signature. When the quote came from Jupiter, the execution price is also written back as the instrument’s reference price, so Pair Value tracks prices the vault actually traded at.