Overview
CIP-0104
introduces traffic-based app rewards, replacing the on-ledger
Splice.Amulet.FeaturedAppActivityMarker mechanism with an off-ledger reward
computation based on actual network traffic. This provides more accurate and
scalable reward accounting for featured app providers.
Why Traffic-Based Rewards
The previous reward mechanism relied on Splice.Amulet.FeaturedAppActivityMarker
contracts created on-ledger during transactions. This approach had several
limitations:
- Misalignment with actual costs: activity markers did not correlate
directly with the traffic burned by an application, leading to discrepancies
between claimed and actual network usage.
- Governance burden: assessing and governing activity markers was complex
and time-consuming, creating pressure to centralize governance decisions.
- Performance impact: creating markers involved the DSO party in every
transaction, increasing transaction size and reducing throughput available
for economically useful activity.
Traffic-based rewards address these by measuring actual traffic costs from
the sequencer. This creates a level playing field among applications, removes
the need for app builders to create markers in the right places, and improves
network throughput by eliminating per-transaction DSO party involvement in
activity recording.
Comparison with Featured App Activity Markers
Splice.Amulet.RewardCouponV2
Splice.Amulet.RewardCouponV2 contracts represent traffic-based app rewards
for a specific party and round. They differ from
Splice.Amulet.AppRewardCoupon in several ways:
- Time-based expiry: coupons expire after a configurable TTL
(
rewardCouponTimeToLive), rather than being tied to round
lifecycle. This allows beneficiaries to batch minting to save traffic
costs.
- One per party per round: instead of one coupon per transaction, there
is one coupon per eligible party per round.
- Beneficiary assignment: coupons support an optional
beneficiary field
for reward sharing.
The provider can assign beneficiaries to share rewards before minting.
Fields
Minting
Splice.Amulet.RewardCouponV2 coupons can be minted in two ways:
-
Automated minting via the Splice Wallet backend that is part of the
validator app. For onboarded internal parties, the
CollectRewardsAndMergeAmuletsTrigger polls for eligible coupons and
submits the consuming transfer. For external parties with an active
minting delegation,
MintingDelegationCollectRewardsTrigger does the same, acting as the
delegate on the external party’s behalf. To confirm a coupon was minted, check
the party’s transaction history, where it is counted as app rewards. See
Wallet Automation.
-
Direct minting by constructing calls to
AmuletRules_Transfer that
use the coupon as a transfer input. These calls can be made directly
against the Ledger API, or indirectly via custom Daml code deployed to
the validator node.
How It Works
The reward computation is split across two components on each SV node:
-
The Scan app ingests traffic summaries from the sequencer alongside
mediator verdicts. For each transaction, it computes per-party app activity
weights — the sum of traffic costs for all transactions where a party was a
featured app provider in a given round. When a round closes, the Scan app
aggregates activity weights into per-party reward totals, applies the
minting allowance threshold defined in
RewardConfig, and builds
a Merkle tree commitment of this round’s app reward minting allowances.
-
The SV app drives the on-ledger creation of
Splice.Amulet.RewardCouponV2 contracts based on the data computed by
Scan. The CalculateRewardsTrigger reads the Merkle tree root hash from
Scan and confirms it on-ledger via the action-requiring-confirmation
workflow. Once a supermajority of SVs agree on the root hash, a
Splice.Amulet.RewardAccountingV2.ProcessRewardsV2 contract is created.
The ProcessRewardsTrigger then expands the tree by reading batches from
Scan, creating Splice.Amulet.RewardCouponV2 contracts for each eligible
party at the leaf nodes.
Scan computes each party’s app reward for a round as follows (see
CIP-0104):
specifies the exact computation Scan performs each round:
total_app_traffic is the sum of a party’s activity record weights for the round (in bytes) — see Splitting Total User Burn for how traffic is attributed across apps when multiple app confirmers share a confirmation request.
traffic_price_in_CC_per_MB is extraTrafficPrice (see Synchronizer Traffic) converted to CC at the round’s amuletPrice.
issuance_per_featured_app_weight is the CC minted per CC of featured app burn in the round: the round’s app reward tranche divided by total_featured_app_burn_CC, capped at featuredAppRewardCap (see Issuance Curve and Minting Schedule).
app_reward_coupon_threshold_CC is appRewardCouponThreshold (from RewardConfig below) converted to CC at the round’s conversion rate. A party whose allowance falls below it gets no coupon for that round; the reward is burned, not carried forward.
A party’s activityWeight on its FeaturedAppRight (default 1.0) multiplies its share of total_app_traffic before this computation, so featured apps with a higher weight earn proportionally more per byte of traffic their users burn.
Activation
Traffic-based app rewards are controlled by the rewardConfig field in the
network’s AmuletConfig. SVs enable the feature by voting to set
rewardConfigMintingVersion to RewardVersion_TrafficBasedAppRewards. A
dry-run mode is also available for verification before switching. See
SV Operations
for the governance procedure.
RewardConfig
The on-ledger RewardConfig type (defined in Splice.AmuletConfig) controls
the traffic-based reward mechanism. SVs configure these fields via governance
votes.
Further Reading