-
Notifications
You must be signed in to change notification settings - Fork 0
ADR 003 Featured App Markers
Coupon policy and CouponMinter live in fairmint/daml. This repo ships Splice featured-app helpers only; it does not implement coupon minting.
Implemented | 2026-01-13
Featured app reward coupons (Canton Network app rewards) are created for financial transactions based on transaction value. Each $100 of value creates 1 coupon, with rounding applied per individual issuance or transfer (not aggregated). A backend CouponMinter service handles rate-limited coupon creation to manage throughput on large issuances or transfers.
The Canton Network provides a mechanism for rewarding apps that drive network activity through "Featured App Markers." Each marker earns a reward with a value that varies based on the total number of markers created network-wide in a given round. Since each marker has variable value, we create multiple markers per transaction to weight rewards proportionally to the transaction's economic significance.
Rather than creating a flat 1 marker per transaction regardless of size, we want rewards to be proportional to the economic value. This ensures that large transactions (e.g., $1M stock issuance) generate appropriately more rewards than small ones (e.g., $100 stock issuance).
Canton Network has transaction throughput limits. A single large transaction (e.g., $1M issuance = 10,000 coupons) cannot mint all coupons atomically.
Additionally, the value per coupon depends on total coupons issued network-wide in a round. Slowly dripping out coupons prevents us from flooding the network with markers—which would crash the value per coupon, negatively impacting us and other network participants.
Create 1 coupon per $100 of transaction value, rounded up per individual transaction.
| Transaction Value | Coupons Created |
|---|---|
| $1 - $100 | 1 |
| $101 - $200 | 2 |
| $250 | 3 |
| $1,000 | 10 |
| $10,000 | 100 |
| $1,000,000 | 10,000 |
Formula: coupons = ceiling(transactionValue / 100)
Important: Rounding is applied per individual issuance or transfer. For example, a single batch containing 3 separate $150 transfers produces 6 coupons (2 each), not 5 coupons based on the $450 total.
Coupon minting is decoupled from the main OCP system contracts into a dedicated backend CouponMinter service (implemented in fairmint/daml; this repo only ships Splice helpers for featured-app integration). This provides:
- Rate limiting: Configurable TPS limit to avoid overwhelming the network
- Audit trail: Contract ID attribution for each coupon batch
- Flexibility: Can adjust minting parameters without modifying core OCP contracts
| Parameter | Default | Description |
|---|---|---|
COUPON_VALUE_UNIT |
$100 | USD value per coupon |
TPS_LIMIT |
1.0 | Coupons per second (adjustable per Canton guidance) |
MIN_COUPONS |
1 | Minimum coupons per transaction |
Only financial transactions (issuances and transfers) create coupons.
| Category | OCF Types | Coupons |
|---|---|---|
| Objects (Setup) | Issuer, Stakeholder, StockClass, StockPlan, StockLegendTemplate, VestingTerms, Valuation, Document | ❌ None |
| Issuances | StockIssuance, ConvertibleIssuance, EquityCompensationIssuance, WarrantIssuance | ✅ Value-based |
| Transfers | StockTransfer, ConvertibleTransfer, EquityCompensationTransfer, WarrantTransfer | ✅ Value-based |
| Acceptances | StockAcceptance, ConvertibleAcceptance, EquityCompensationAcceptance, WarrantAcceptance | ❌ None |
| Cancellations | StockCancellation, ConvertibleCancellation, EquityCompensationCancellation, WarrantCancellation | ❌ None |
| Retractions | StockRetraction, ConvertibleRetraction, EquityCompensationRetraction, WarrantRetraction | ❌ None |
| Conversions/Exercises | StockConversion, ConvertibleConversion, EquityCompensationExercise, WarrantExercise | ❌ None |
| Corporate Actions | All adjustments, splits, consolidations, pool changes | ❌ None |
| Other Transactions | Repurchase, Reissuance, Release, Repricing, Vesting events, Status changes | ❌ None |
Total coupon-creating types: 8 (4 issuances + 4 transfers)
| Transaction Type | Value Field | Notes |
|---|---|---|
| StockIssuance | quantity × share_price.amount |
Uses share price at issuance |
| ConvertibleIssuance | investment_amount.amount |
Principal investment amount |
| EquityCompensationIssuance | quantity × exercise_price.amount |
Strike price × shares |
| WarrantIssuance | quantity × purchase_price.amount |
Purchase price × warrants |
| StockTransfer | quantity × FMV |
See fallback logic below |
| ConvertibleTransfer | From original issuance | Transferred principal |
| EquityCompensationTransfer | quantity × exercise_price |
Strike price × shares transferred |
| WarrantTransfer | quantity × purchase_price |
Purchase price × warrants transferred |
The StockTransfer OCF schema does not include a price field. When price is not available, we look up the fair market value from the most recent Valuation object.
Fallback logic:
- Look up the
stock_class_idfrom the originalStockIssuance(viasecurity_id) - Find the most recent
Valuationwherevaluation.stock_class_idmatches andvaluation.effective_date <= transfer.date - Use
valuation.price_per_share.amount × transfer.quantity - If no Valuation exists, default to 1 coupon minimum
- Transaction: 1,000 shares at $5/share = $5,000
- Coupons: ceiling($5,000 / $100) = 50 coupons
- Transaction: $1,000,000 SAFE investment
- Coupons: ceiling($1,000,000 / $100) = 10,000 coupons
- Transaction: 10,000 options at $2 strike = $20,000
- Coupons: ceiling($20,000 / $100) = 200 coupons
- Transaction batch: 3 separate stock transfers of $150 each
- Coupons: 3 × ceiling($150 / $100) = 3 × 2 = 6 coupons
- Note: Not ceiling($450 / $100) = 5 coupons
- ADR-002-Stateful-Issuer - Stateful Cap Table
-
CouponMinter implementation and docs:
fairmint/daml(not maintained in this open repo) - Splice Featured App API
| Date | Change | PR |
|---|---|---|
| 2026-01-13 | Status updated to Implemented (CouponMinter shipped in Fairmint DAML monorepo) | — |
| 2026-01-12 | Changed to value-based coupons, added CouponMinter service | — |
| 2026-01-09 | Created proposal | — |
Last updated: 2026-01-13
Develop
Decisions
Releases
- Releases (index)
- Package tag release process
- 2026-06-22 — OCP v35 conversion mechanism validation
- 2026-06-22 — OCP v35 SDK scaffold
- 2026-05-04 — OCP v34 major upgrade
- 2026-05-04 — DAML extraction / fairmint-daml
- 2026-03-05 — OCP v32 PPS-based conversion rename
- 2026-02-17 — OCP v31 ArchiveCapTable
- 2026-02-12 — OCP v31 vesting zero portion
Other Fairmint DAML
Documentation for CantonPayments, NFT, Reports, CouponMinter, equity certificate, proof-of-ownership, and related deployment playbooks lives with fairmint/daml and @fairmint/daml-js — not in this wiki.