Operator Role
The Operator is a first-class party on every IRSForge deployment, distinct from the trader counterparties. It models the platform operator — the entity running the IRSForge service that two trading firms have both onboarded with.
In TradFi terms, this is the role a clearing venue, a tri-party agent, or a DLT platform operator plays: a third party that doesn't take economic risk on the trade but mediates issuance, lifecycle, and reference data on behalf of the bilateral counterparties.
If you're looking for the operator UI reference (queue, disputes, health), see ui/operator. This page covers why the operator exists and what authority it carries on-chain.
Why a third party at all
Two firms can do bilateral Daml between themselves with no operator involved. IRSForge needs an operator because:
- Daml Finance factories require operator authority. The
Factory.Createchoice that mints anInstrumentis signed by aproviderparty — not by the two trade counterparties. Without a stable third-party signer, every trade would need its own ad-hoc factory deployment. - Reference data is platform-wide. Currencies, rate indices (SOFR, ESTR, …), holiday calendars, oracle observations, and curve snapshots are shared across every counterparty pair. A single operator-owned authority publishes them and every trader observes.
- Compliance gating wants a non-trader actor. Optional manual co-sign on trade acceptance (Stage 2) requires an authority that's structurally separate from both economic counterparties.
- Regulator hand-off has a defined source. The operator includes configured regulator parties as observers on every contract it provisions, so audit visibility flows from one place.
The org.role: operator field is required and schema-enforced as exactly one per deployment (shared-config/src/schema-orgs.ts). Regulator orgs are also role-declared; the schema requires at least one and supports more than one.
On-chain footprint
The operator appears on-chain as either a signatory (its authority is required for the contract to exist) or an observer (it can read the contract). The shape:
| Contract | Operator role | Why |
|---|---|---|
Setup.RoleSetup | signatory | Bootstrap marker — proves the deployment was provisioned |
IRS / CDS / CCY / FX / Asset / FpML Factory | signatory (provider) | Required by Daml Finance for Factory.Create |
LifecycleRule, EventFactory | signatory | Authority chain for Lifecycle.Evolve |
HolidayCalendar, Currency, FloatingRateIndex | signatory | Shared reference data |
Observation, Curve, CurveSnapshot | signatory (or co-signed with scheduler) | Oracle authority — see Canton Oracle Model |
<Family>Proposal (IRS, OIS, Basis, Xccy, CDS, Ccy, Fx, Asset, FpML) | signatory with proposer | Pre-co-signs so Accept body inherits factory auth |
<Family>AcceptAck | signatory with proposer + counterparty | Manual-policy co-sign holding pen |
Csa | signatory with partyA + partyB | Operator co-owns the bilateral CSA (Bloomberg MARS convention) |
CsaProposal | signatory with proposer | Same proposal pattern as swaps |
MarginCallOutstanding, MarkDisputed | observer | Operator monitors and adjudicates disputes |
SwapWorkflow (the live trade) | observer | Once minted, the bilateral trade has signatory partyA, partyB only |
| Cash holdings | not present | Operator never holds positions |
The headline: operator authority is everywhere at provision-time, but the operator is not on the bilateral instrument body once the trade is live. It mints the trade and gates its lifecycle, but doesn't own the trade.
What the operator does
1. Co-sign trade proposals
Every <Family>Proposal template declares signatory proposer, operator. Creating a proposal therefore requires submitMulti [proposer, operator] [] — the operator's authority is consumed inline so that the eventual <Family>Accept choice has enough authority to invoke Factory.Create.
template CcySwapProposal
with operator : Party; proposer : Party; counterparty : Party; ...
where
signatory proposer, operator
observer counterparty
2. Optionally gate acceptance (auto vs manual)
operator.policy.<FAMILY>: auto | manual in irsforge.yaml selects the acceptance flow:
auto— counterparty exercises<Family>Acceptdirectly. The operator's standing co-signature on the proposal carries through; the liveSwapWorkflowlands in one transaction. Operator queue stays empty.manual— counterparty exercises<Family>ProposeAccept→ creates<Family>AcceptAck→ operator reviews on/org/<id>/operator→ exercises<Family>ConfirmAccept→SwapWorkflowlands. Either side can cancel before the operator acts.
This is a compliance choice, not a technical one. Same on-chain end state; the manual path inserts a human review gate. See Operator UI — compliance policy for the per-family configuration.
3. Resolve CSA disputes
The operator is signatory on every Csa contract alongside the two traders. When a counterparty exercises MarkDispute, the CSA enters MarkDisputed and is pinned out of the margin-call cycle until the operator exercises AcknowledgeDispute. See CSA Model — lifecycle states.
4. Maintain platform reference data
Currencies, rate indices, holiday calendars, oracle observations, curve snapshots — all submit operator (or co-signed with the scheduler service account, see Scheduler Authority). Traders observe; only the operator can publish.
5. Run scheduler-fallback lifecycle
When the autonomous scheduler is stalled, the operator can manually drive TriggerLifecycle on CCY / FX / FpML swaps via the operator UI. The dual LifecycleRule accepts either signer — operator authority works as a break-glass without redeploying anything.
What the operator structurally cannot do
| Cannot | Reason |
|---|---|
Be partyA or partyB on a swap | SwapWorkflow declares signatory partyA, partyB — operator isn't in that set |
| Propose a trade | Proposal controllers are trader parties; operator UI hides the "New Swap" button (ui/operator.md:108) |
| Accept / Reject / Withdraw a trade | Choice controllers are trader parties |
| Unwind a live swap | terminateProposal controller is trader-side |
| Hold cash or instruments | Operator never appears as owner on Daml Finance holdings |
Unilaterally cancel a live SwapWorkflow | Workflow body has only the two traders as signatories |
The full bidirectional gating audit is in ui/operator — what the operator can't do.
Demo vs production
Same on-chain shape, different participant topology and trust model.
| Demo | Production | |
|---|---|---|
| Hosted on | The single Canton sandbox alongside every other party | The platform-operator's own Canton participant node, under separate org |
| Auth | auth.provider: demo — party-selector mints a JWT for Operator on click | auth.provider: oidc — the IdP proves operator identity; IRSForge auth service mints the operator-scoped Canton ledger JWT |
| Operator service credential | Browser-minted, ephemeral | mark-publisher service-account secret in a secrets manager; auth service exchanges it for short-lived ledger JWTs |
operator.policy.<FAMILY> | All 9 families on auto (zero-friction demo) | Mixed auto / manual per compliance regime; manual queue is staffed and paged |
| Compliance reviewer | Whoever is clicking the demo | A human at the platform operator (with PagerDuty / Slack hook on new queue items — roadmap) |
| Trust model | Operator is just another persona on a single ledger | Operator is the platform's commitment to the two firms — they trust the platform-operator the way they'd trust a CCP or tri-party agent |
In demo the operator looks invisible because everything is on one sandbox and auto policy short-circuits the queue. In production the operator is what makes a bilateral trade a platform trade rather than two firms doing arbitrary Daml on their own ledgers — same code, different operating model.
For the production cutover checklist (OIDC wiring, secrets, manual buttons off) see Deploying to Production.
Mental model
┌────────────────────┐
│ Operator │ ← platform authority
│ (provision + │ (factory provider, lifecycle,
│ gate + publish) │ reference data, dispute resolver)
└─────────┬──────────┘
│ co-signs
┌─────────┴──────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ PartyA │ ◀────▶ │ PartyB │ ← the live bilateral trade
└──────────┘ └──────────┘ (signatory partyA, partyB)
▲ ▲
└────────┬───────────┘
│ observes
┌────────▼─────────┐
│ Regulator │ ← read-only audit
└──────────────────┘
PartyA ↔ PartyB own the economic relationship. The operator sits above them as the platform / factory / oracle authority. The regulator sits below with read-only audit visibility. None of these can swap roles — cardinality and signatory shape enforce it on-chain.