lightninglabs / lightninglabs/loop

staticaddr: populate static Loop-In on-chain costs from deposit fees

Open
#1,174 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
595
Forks
135
Avg merge
1d 8h
Merged PRs (30d)
12

Description

## Problem

Static Loop-In responses expose `cost_onchain`, but the value is currently zero for every swap.

The current implementation only derives `cost_server` from the accepted quote after the invoice is paid. It does not populate an on-chain cost in either:

- `ListStaticAddressSwaps`
- the generic `ListSwaps` / monitor representation

This is also reflected in `TestListStaticAddressSwapsPopulatesTimingAndCosts`, which currently asserts that `CostOnchain` is zero.

For cost accounting equivalent to a legacy Loop-In, the fee paid by the transaction that funds the static-address deposit is the client-side on-chain cost. It is analogous to the legacy Loop-In HTLC funding transaction fee, even though the static-address funding transaction happens before the swap is initiated.

## Expected behavior

When a static Loop-In consumes one or more deposits:

- report the funding transaction fee as `cost_onchain`;
- aggregate the fees for all selected deposits;
- deduplicate by funding transaction ID, so two selected outputs from the same transaction do not count the full transaction fee twice;
- populate the value consistently in `ListStaticAddressSwaps`, generic `ListSwaps`, and monitor updates;
- persist the actual cost so terminal autoloop budget accounting can use it instead of estimates.

For deposits funded by an external wallet, Loop may not know the sender's fee. Those should be treated explicitly as unavailable/client-external rather than being confused with a known zero-fee transaction.

## Straightforward implementation

The existing lnd client already provides the required data:

```go
txs, err := lndClient.ListTransactions(ctx, startHeight, -1)
```

Each `lndclient.Transaction` includes `TxHash` and `Fee`.

An initial implementation can:

1. Parse the selected deposit outpoints and collect their unique funding transaction hashes.
2. Fetch wallet transactions once and build a `txid -> fee` map.
3. Sum each unique funding transaction fee once.
4. Store the result in the existing base `swaps.onchain_cost` column. Static Loop-Ins already have a row in `swaps`, so a new cost column should not be necessary.
5. Add the persisted cost to `StaticAddressLoopIn` when reconstructing it from the joined SQL row.
6. Use that cost in both static-specific and generic RPC representations.

The common `loop static new --sendcoins` flow normally creates one static deposit output, so attributing the full wallet transaction fee is straightforward. If a single transaction creates multiple static deposits that can be consumed by different swaps, the implementation should use a deterministic per-deposit allocation or a transaction-level accounting record so the fee is not charged in full to multiple swaps.

The cost should be attached when the deposits are definitively consumed (successful Loop-In or a confirmed HTLC timeout path). A failed attempt that unlocks and reuses the same deposits should not cause the original funding fee to be counted again on a later swap.

## Acceptance criteria

- A single-deposit static Loop-In reports its known wallet funding fee in `cost_onchain`.
- A swap using deposits from different funding transactions reports the sum of their fees.
- Multiple selected deposits from the same funding transaction count that transaction fee only once.
- Failed attempts that release reusable deposits do not cause duplicate accounting.
- Static-specific and generic swap APIs return the same persisted on-chain cost.
- Tests cover single-deposit, multiple-transaction, same-transaction/multiple-output, unknown external funding, and restart behavior.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the static deposit consumption flow, the lndClient.ListTransactions call, and TestListStaticAddressSwapsPopulatesTimingAndCosts. Trace how swaps.onchain_cost is persisted and how StaticAddressLoopIn is reconstructed, then verify the static-specific, generic, and monitor representations. Done means known funding fees are persisted, deduplicated, safely handled for external funding and reusable deposits, and covered by the listed acceptance tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, backend, databases
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.