You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(cch): clarify SwapProposal btc_amount_msat and add ReceiveBTC fee example
Cross-review against the implementation surfaced two documentation
gaps in the multi-asset swap spec.
* Section 5.6 implied the SwapProposal's btc_amount_msat for SendBTC
was the raw Bolt11 amount, but the actor sends the total payout
(Bolt11 amount + configured fee). Clarify the field semantics and
note that the raw Bolt11 amount can be recovered as
btc_amount_msat - fee_on_btc_side_msat.
* Section 6.2 left ReceiveBTC proposal-path operators to infer how
to combine the configured fee with their chosen rate. Add a worked
formula and numeric example matching the fast-path computation, so
operators have a reference implementation for the BTC-leg amount
they submit.
Copy file name to clipboardExpand all lines: docs/specs/cch-multi-asset-swap.md
+26-2Lines changed: 26 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -180,9 +180,11 @@ A `SwapProposalResponse` carries either a rejection or an acceptance that includ
180
180
181
181
-`proposal_id` (must match a pending proposal previously notified to this client),
182
182
-`accept` (boolean),
183
-
-`counterparty_leg_amount` (REQUIRED when `accept` is true; smallest-unit integer in the counterparty leg’s asset),
183
+
-`counterparty_leg_amount` (REQUIRED and **must be > 0**when `accept` is true; smallest-unit integer in the counterparty leg’s asset),
184
184
-`reject_reason` (optional string; logged by the hub and returned to the swap client as the failure reason when `accept` is false).
185
185
186
+
A response is **valid** when it parses, references a pending `proposal_id`, and \u2014 if `accept` is true \u2014 carries a positive `counterparty_leg_amount`. The first valid response resolves the proposal; later responses for the same `proposal_id` return `SwapProposalUnknown`. A malformed accept (missing or zero `counterparty_leg_amount`) is rejected with `SwapProposalResponseMissingAmount` / `SwapProposalResponseInvalidAmount` but **leaves the proposal pending** so the operator may correct and resubmit before the timeout elapses.
187
+
186
188
### 5.4 Timeout
187
189
188
190
- If no operator submits a valid `SwapProposalResponse` for a given `proposal_id` within `swap_proposal_timeout_seconds` (CCH config), the proposal is treated as **rejected** (same outcome as `accept: false`) with reason `acceptor_timeout`.
@@ -227,7 +229,7 @@ Fields delivered to subscribers (see `SwapProposal` in `fiber-types`):
227
229
|`payment_hash`| Links both legs (derived from the client-submitted invoice). |
228
230
|`fiber_asset`| UDT type script when the Fiber leg is a UDT; absent (or null) when the Fiber leg is native CKB. |
229
231
|`fiber_amount_smallest_unit`| Fiber-leg amount in smallest units when known up-front (parsed from the submitted invoice on `ReceiveBTC`); absent on `SendBTC` because the operator supplies it in their response. |
230
-
|`btc_amount_msat`| Lightning amount in millisatoshis when known up-front (parsed from the submitted Bolt11 on `SendBTC`); absent on `ReceiveBTC` because the operator supplies it in their response. |
232
+
|`btc_amount_msat`|**Total**Lightning amount in millisatoshis the hub will pay out, **inclusive of `fee_on_btc_side_msat`** (i.e. submitted-Bolt11 amount + configured fee), when known up-front on `SendBTC`; absent on `ReceiveBTC` because the operator supplies it in their response. The raw Bolt11 amount can be recovered as `btc_amount_msat - fee_on_btc_side_msat`. |
231
233
|`configured_fee_rate_per_million_sats`| Hub-configured proportional fee in effect for this swap. |
232
234
|`configured_base_fee_sats`| Hub-configured flat base fee in effect for this swap. |
233
235
|`fee_on_btc_side_msat`| Fee attributed to the BTC leg derived from the configured rate, in millisatoshi. For `SendBTC` this is computed from the submitted Bolt11; for `ReceiveBTC` it is reported as `0` because it depends on the operator-set BTC-leg amount — the operator is responsible for accounting for the configured rate/base when choosing the counterparty amount. |
@@ -269,6 +271,28 @@ The swap client submits the **Fiber invoice** they want the hub to pay on the Fi
269
271
5. Continue with the existing order machinery.
270
272
6. Return the order with the Lightning hold invoice attached; the swap client (if the amount is acceptable) forwards it to the user-side payer.
271
273
274
+
#### Worked example: ReceiveBTC proposal-path operator math
275
+
276
+
For a `ReceiveBTC` proposal the hub reports `fee_on_btc_side_msat = 0` because it cannot compute the fee until the operator picks a BTC-leg amount. The operator’s `counterparty_leg_amount` is taken as the **final** BTC-leg amount in millisatoshi (fee included). A reference computation that mirrors the fast path is:
277
+
278
+
1. Choose an effective BTC/asset rate $r$ in **fiber smallest units per satoshi** (the operator’s FX/inventory decision).
279
+
2. Convert the submitted Fiber-leg amount to a fee-exclusive BTC amount:
Operators MAY price more aggressively (larger `r`, larger fee) to cover FX/inventory risk. The hub does not validate the chosen rate — the swap client is the final gate by accepting or refusing to forward the minted Lightning hold invoice.
293
+
294
+
The symmetric `SendBTC` proposal already includes `btc_amount_msat` (Bolt11 amount + configured fee) and `fee_on_btc_side_msat`, so the operator’s task there is purely the BTC→asset conversion at their chosen rate.
295
+
272
296
## 7. Security and operations
273
297
274
298
-**Preimage release**: Preserve ordering guarantees so the hub does not strand funds (same class of concerns as current CCH).
0 commit comments