Layer 2: capacity engine (future design)
Not built. This document fixes how backing from many sources will become issuance capacity without changing Layer 1 (the Stellar asset, accounts, ledger, orders and trading).
1. The boundary that already exists
Layer 1 learns about backing only through reserve.CapacityProvider:
type CapacityProvider interface {
GetCapacity(ctx context.Context, q db.Querier, assetID uuid.UUID) (Capacity, error)
}Today ManualReserveProvider returns the four-eyes-approved snapshot. Issuance approval, the shortfall check (BUY
pause) and reconciliation (ledger_supply_within_unexpired_backing) all read capacity this way. A
DynamicReserveCapacityProvider will implement the same interface; app.Options.CapacityProvider already selects
the provider. Layer 1 consumes only approved capacity: Layer 2 proposes, people approve.
2. Modules
| Module | Responsibility |
|---|---|
ProviderRegistry | The sources of backing (vaults, brokers, custodians, guarantors, credit lines) with their contracts, contacts, limits and status |
BackingLot | One identifiable quantity of the asset at one provider: quantity, unit, state (settled, pending, pledged, guaranteed, credit), as-of, evidence reference |
PhysicalAssetAdapter | Vault and assay records → settled lots |
BrokerAdapter | Broker statements → settled and pending lots (with settlement date T+n) |
CustodianAdapter | Custodian holdings → settled lots |
GuaranteeAdapter | Guarantees → contingent lots with conditions and expiry |
CreditFacilityAdapter | Committed credit lines → contingent lots |
SettlementTracker | Moves pending lots to settled (or failed) as settlement completes |
HaircutEngine | Applies the approved eligibility and haircut policy per lot type and provider (policy values are a business decision; none are assumed here) |
ExpiryEngine | Removes lots whose evidence or validity expired (the manual model's 35-day rule generalised) |
CapacityCalculator | Sums eligible lots after haircuts and expiry into a CapacitySnapshot |
ForecastEngine | Capacity at T+1, T+2, T+7 from pending settlements and expiries |
ReconciliationEngine | Compares lots with provider statements; a mismatch blocks the provider's lots |
3. Output
CapacitySnapshot {
asset
eligibleBacking // Σ eligible lots after haircuts and expiry, now
issuedSupply // from Layer 1 (ledger TOKEN_SUPPLY, reconciled with the chain)
availableIssuanceCapacity // eligibleBacking − issuedSupply − pending issuance
instantSellCapacity // what can be delivered now (hot float + issuable)
instantBuybackCapacity // what can be bought back now (cash and limits)
futureCapacityT1, T2, T7 // forecasts from pending settlements and expiries
timestamp
}A snapshot is computed by Layer 2, approved four-eyes as today, and only then becomes what
DynamicReserveCapacityProvider.GetCapacity returns (Eligible = eligibleBacking, ValidUntil = the earliest
expiry among contributing lots). Forecasts are shown to operators; they never count as backing.
4. Worked example (structure only)
The brief's example: physical GOLD 500 kg; Broker A 200 kg settled; Broker B 100 kg pending T+2; Provider C 50 kg
guarantee; a 20 kg credit facility. Eligibility and haircuts are placeholders (hᵢ, eᵢ); the real values are
the business's to set and approve.
| Lot | Quantity | State | Eligible now? | Contribution now | Contribution at T+2 |
|---|---|---|---|---|---|
| Vault | 500 kg | settled | yes | 500 × (1 − h_vault) | same |
| Broker A | 200 kg | settled | yes | 200 × (1 − h_A) | same |
| Broker B | 100 kg | pending T+2 | no (not settled) | 0 | 100 × (1 − h_B) once SettlementTracker marks it settled |
| Provider C | 50 kg | guarantee | per policy e_C ∈ {0, 1} | 50 × e_C × (1 − h_C) | same, until its expiry |
| Credit facility | 20 kg | credit | per policy e_F ∈ {0, 1} | 20 × e_F × (1 − h_F) | same |
eligibleBacking(now) is the sum of the "now" column; futureCapacityT2 adds Broker B. That number, once approved,
enters through DynamicReserveCapacityProvider exactly as a manual snapshot does today: the Stellar asset, its
issuer, its supply and every Layer 1 rule are unchanged.
5. Rules carried over from Layer 1
- Supply never exceeds approved capacity (INV-01): issuance approval reads the provider.
- A capacity drop below supply is a shortfall: issuance and BUY pause, SELL and TRANSFER continue.
- Every capacity change is audited and four-eyes approved; the computation is reproducible from its lots.