ChainSafe / ChainSafe/canton-middleware

Fee module: bundled CC fee for no-loss traffic cost recovery

Open
#366 0 comments 0 reactions 0 assignees View on GitHub
Type: Epic
Dominant language
Go
Stars
1
Forks
1
Avg merge
40m
Merged PRs (30d)
1

Description

**Type: Epic**

Add a reusable fee layer to the middleware that recovers the Canton node's traffic cost from the users who cause it, by bundling a **Canton Coin (CC)** fee leg into the same Daml transaction as the user's transfer — one transaction, one signature, atomic, and **no-loss** for the operator.

Design doc: [`docs/fee-module-design.md`](../blob/main/docs/fee-module-design.md).

## Problem

Today the middleware charges no network fee, but the Canton node still burns CC to pay the synchronizer for **Layer A traffic** on every submission — so the operator absorbs 100% of that cost. The middleware's own tokens (DEMO, PROMPT, USDCx) are **not** Canton Coin, so their transfers only trigger Layer A traffic (a node cost), never an automatic user charge. Making the user pay is a middleware construct we have to build.

## Two Canton fee layers (background)

| Charge | Layer | Paid by | When |
|---|---|---|---|
| Extra traffic (per byte sequenced, burned in CC) | A | **Node operator** | every tx over the free base rate |
| Base-rate traffic | A | — | free burst allowance |
| Create / transfer / holding fees | B | CC sender/holder | only on CC transfers |

## Core idea — no-loss guarantee

Bundle a CC fee leg (user → operator fee party) into the user's transfer transaction:

```
fee = trafficCC + amuletFeeOnFee + buffer
```

- **trafficCC** — the node's real burn: `bytes × traffic price ÷ CC price`
- **amuletFeeOnFee** — the Layer-B fee the CC leg itself incurs, so the operator nets the full `trafficCC`
- **buffer** — small over-collect, always rounded up ⇒ operator never underwater

A reconciler compares real burn vs. collected CC and exposes `fee_coverage_ratio` (below 1.0 ⇒ raise the buffer).

## Architecture — one engine, two front-ends

The fee **engine** (`pkg/cantonsdk/fee`) is transport-free and reusable. Two things use it:

- **Phase 1 — in-process library:** the middleware imports the engine and wraps its ledger client so the CC fee leg is injected on submit. No token/bridge/relayer logic changes.
- **Phase 2 — deployable proxy (`pkg/feegate`):** the same engine fronted by a gRPC service speaking the Canton Ledger API. Write submissions get a fee leg; everything else passes through. Any service in any language points its endpoint at the proxy.

**Boundary rule:** the engine depends only on Canton API types + stdlib — never HTTP, DB, config, or a server runtime. Anything with external I/O lives in the service. **Invariant:** the engine never learns *how* forwarding happens (`Gate.Process(cmds) → augmented cmds + quote`) — which is exactly why Phase 2 reuses it unchanged.

## Prerequisites (operator-provided)

- A fee party holding CC with a live `TransferPreapproval` (enables single-signature CC receipt).
- A Scan API URL for live CC prices.
- Validator auto-topup enabled.

## Out of scope

- Topology traffic (party allocation / package vetting) — operator-driven, operator pays.
- Users with no CC — the transaction fails fast rather than being subsidized. (This is *why* CC balance visibility is the first deliverable.)

## Deliverables

- [ ] **#367** — Canton Coin (CC) read-only balance support (foundation — the engine must read CC balances; users must see CC to fund fees)
- [ ] **#368** — Phase 1: in-process fee engine (`pkg/cantonsdk/fee`) + gated ledger wiring (Observe → Quote-only → Collect)
- [ ] **#369** — Phase 2: fee gate gRPC proxy (`pkg/feegate`) fronting the same engine

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with docs/fee-module-design.md, then review the prerequisite and child issues #367, #368, and #369. The epic is done when CC balance support, the staged in-process fee engine, and the reusable gRPC fee gate are implemented with the described atomic fee collection and coverage reconciliation.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, grpc
Domain
api, backend, payments
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.