Smart Product Framework: Interest Rate Swap
DemoInterestRateSwap is a deliberately small second product example for the
Smart Product Framework. It deploys a fixed-versus-floating EUR interest-rate
swap, stores its product terms and documentation templates as immutable
TextResource contracts, and walks one trade through request, amendment,
inception, and confirmation.
The implementation uses FpML's confirmation vocabulary for the represented economic terms. It is a focused example rather than a complete swap engine: it does not generate cash flows, perform fixing or valuation, or settle payments.
Product Specification
The product-specific factory accepts one ABI tuple:
v1:InterestRateSwapDeploymentPayload(
uint256 notional,
string currency,
uint256 maturity,
int256 swapRate,
uint8 clientFixedRateRole,
string forwardCurveSymbol,
string discountCurveSymbol
)
| Payload field | Encoding convention | Rendered meaning |
|---|---|---|
notional |
Unsigned integer, scale 2 | The same notionalStepSchedule/initialValue on both FpML swap streams |
currency |
Three uppercase ASCII letters | The FpML notional currency; the demo uses EUR |
maturity |
Unix timestamp in seconds | The unadjusted termination date on both legs |
swapRate |
Signed integer, scale 4 | FpML decimal fixed rate: 250 renders as 0.0250, or 2.50% |
clientFixedRateRole |
0 = Payer, 1 = Receiver |
Selects the payer and receiver party references on both legs, from the client's perspective |
forwardCurveSymbol |
Non-empty string | Symbolic projection-curve assignment |
discountCurveSymbol |
Non-empty string | Symbolic discount-curve assignment |
The trade date and effective date are fixed to the product-deployment time to
avoid adding two more payload fields. The immutable terms template supplies the
remaining conventions for this example: annual fixed payments with 30E/360,
quarterly EUR-EURIBOR floating periods with ACT/360, and EUTA business-day
adjustments.
FpML Representation
The included XML template uses the FpML confirmation namespace and its normal
dataDocument / trade / swap / swapStream structure. It represents two
streams, opposite payer/receiver references, calculation and payment dates,
notional schedules, a fixed-rate schedule, and a floating-rate calculation.
The client and product provider appear as FpML parties whose identifiers are
their EVM addresses.
The two curve symbols are valuation/model inputs rather than contractual FpML economics. They therefore remain explicit siblings in the Smart Product Framework extension namespace instead of being presented as standard FpML elements. This keeps the distinction visible while allowing the renderer to resolve all seven requested fields from contract state.
The document is an intentionally small FpML-shaped confirmation subset. It uses the corresponding FpML terms and nesting, but does not claim validation as a complete standalone FpML message. See the FpML confirmation product architecture for the wider model.
ERC-6123-Inspired Agreement
The shared Smart Product Framework lifecycle preserves the important
incept/confirm agreement pattern while adapting it to an already deployed,
self-rendering product. It is not ABI-compatible with ISDCTrade and does not
claim full ERC-6123 conformance.
| ERC-6123 concept | Lightweight adaptation in this example |
|---|---|
withParty is supplied to inception and confirmation |
productProvider and client are fixed in the product's authenticated deployment state |
Both parties repeat matching tradeData |
Canonical structured terms live on-chain; both calls submit the same instance-bound currentTermsHash() |
Signed position expresses direction |
clientFixedRateRole states whether the client pays or receives the fixed leg; the floating-leg roles are the opposite |
paymentAmount and initialSettlementData accompany inception |
Upfront payment and initial settlement are intentionally outside this terms-and-agreement example |
The provider calls inceptTrade(currentTermsHash) while the trade is
Requested; the client then calls confirmTrade with that same hash. A
mismatch reverts. Successful calls emit the lifecycle and status events and
move the product through Requested -> Incepted -> Active. This is the part of
the ERC-6123 lifecycle the example is
intended to demonstrate.
Run the Demo
You need Java 21, Maven, solc, Node.js/npm, and a local Cancun-capable JSON-RPC
node. The renderer is only required to open the XML URLs printed at the end.
From the repository root:
npm ci --prefix representable-contract-state-web/src/main/solidity
anvil --chain-id 1337 --hardfork cancun
Leave Anvil running. In another terminal, build the project:
mvn -pl representable-contract-state-web -am -DskipTests package
Then run
DemoInterestRateSwap
from the IDE with representable-contract-state-web as its working directory.
The Solidity source and compiler output paths are relative to that module.
The equivalent command-line launch for the current snapshot is:
cd representable-contract-state-web
java \
-Dloader.main=net.finmath.smartcontracts.representablestate.demo.SmartProductFramework.DemoInterestRateSwap \
-cp target/representable-contract-state-web-2.5.0.jar \
org.springframework.boot.loader.launch.PropertiesLauncher
The demo deploys the client registry, swap product registry, generic and product-specific factories, and both template resources. It registers and funds the client, publishes the product definition, ABI-encodes the seven fields, creates a request, and performs inception and confirmation. Finally it amends the requested economic terms before inception and prints block-pinned renderer URLs grouped by contract.
Historical Contract Views
Every checkpoint uses the block number from the transaction receipt that caused the state change. The product-definition registry is rendered as a state part, while the swap exposes its complete state:
http://localhost:8080/xml/part?contract=<registry>&partid=<definition-id>&block=<receipt-block>
http://localhost:8080/xml?contract=<swap>&block=<receipt-block>
The registry group contains one checkpoint:
| Checkpoint | Block label | Status | Version | Visible state |
|---|---|---|---|---|
| Definition published | R0 |
1 — Active |
1 | Terms and documentation resources are present; ProductIndicationAssignment is assigned="false" |
There is deliberately no indication-assignment checkpoint. The forward and discount curve symbols belong to the swap's requested terms in this minimal example, rather than referencing a separate indication contract.
The product group contains four checkpoints:
| Checkpoint | Block label | Trade status | Notional | Maturity | Fixed rate | Client fixed-leg role |
|---|---|---|---|---|---|---|
| Initial request | P0 |
0 — Requested |
1000000.00 |
now + 5 years |
0.0250 |
Payer |
| Amended request | P1 |
0 — Requested |
1250000.00 |
now + 6 years |
0.0275 |
Receiver |
| Inception | P2 |
1 — Incepted |
1250000.00 |
Amended date | 0.0275 |
Receiver |
| Confirmation | P3 |
2 — Active |
1250000.00 |
Amended date | 0.0275 |
Receiver |
The demo checks both the expected values and strict checkpoint ordering. Open
the grouped URLs printed at the end to compare the historical XML directly.
The client registry and factories do not currently expose renderer-compatible
XML state; finalized template resources remain available through their
immutable web3Url() values.
