Skip to content

Commit 1e5911c

Browse files
committed
looprpc: populate static swap timing and costs
1 parent e0e1da5 commit 1e5911c

5 files changed

Lines changed: 207 additions & 3 deletions

File tree

loopd/swapclient_server.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,6 +1966,10 @@ func (s *swapClientServer) ListStaticAddressSwaps(ctx context.Context,
19661966

19671967
var clientSwaps []*looprpc.StaticAddressLoopInSwap
19681968
for _, swp := range swaps {
1969+
if swp == nil {
1970+
continue
1971+
}
1972+
19691973
chainParams, err := s.network.ChainParams()
19701974
if err != nil {
19711975
return nil, fmt.Errorf("error getting chain params")
@@ -2005,13 +2009,19 @@ func (s *swapClientServer) ListStaticAddressSwaps(ctx context.Context,
20052009
if swp.SelectedAmount > 0 {
20062010
swapAmount = swp.SelectedAmount
20072011
}
2012+
costServer := staticAddressLoopInSwapServerCost(swp)
2013+
initiationTime := staticAddressLoopInTimestamp(swp.InitiationTime)
2014+
lastUpdateTime := staticAddressLoopInTimestamp(swp.LastUpdateTime)
20082015
swap := &looprpc.StaticAddressLoopInSwap{
20092016
SwapHash: swp.SwapHash[:],
20102017
DepositOutpoints: swp.DepositOutpoints,
20112018
State: state,
20122019
SwapAmountSatoshis: int64(swapAmount),
20132020
PaymentRequestAmountSatoshis: payReqAmount,
20142021
Deposits: protoDeposits,
2022+
InitiationTime: initiationTime,
2023+
LastUpdateTime: lastUpdateTime,
2024+
CostServer: costServer,
20152025
}
20162026

20172027
clientSwaps = append(clientSwaps, swap)
@@ -2022,6 +2032,31 @@ func (s *swapClientServer) ListStaticAddressSwaps(ctx context.Context,
20222032
}, nil
20232033
}
20242034

2035+
func staticAddressLoopInTimestamp(t time.Time) int64 {
2036+
if t.IsZero() {
2037+
return 0
2038+
}
2039+
2040+
return t.UnixNano()
2041+
}
2042+
2043+
// staticAddressLoopInSwapServerCost returns the paid server cost using the
2044+
// legacy ListSwaps cost semantics. Static loop-ins currently only persist the
2045+
// accepted quote fee, and that fee is paid once the swap invoice settles.
2046+
// Timeout-path miner fees are not persisted, so cost_onchain and cost_offchain
2047+
// remain zero instead of returning an estimate as an actual cost.
2048+
func staticAddressLoopInSwapServerCost(swp *loopin.StaticAddressLoopIn) int64 {
2049+
switch swp.GetState() {
2050+
case loopin.PaymentReceived, loopin.Succeeded,
2051+
loopin.SucceededTransitioningFailed:
2052+
2053+
return int64(swp.QuotedSwapFee)
2054+
2055+
default:
2056+
return 0
2057+
}
2058+
}
2059+
20252060
// GetStaticAddressSummary returns a summary of static address-related
20262061
// information. Amongst deposits and withdrawals and their total values, it also
20272062
// includes a list of detailed deposit information filtered by their state.

loopd/swapclient_server_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/lightninglabs/loop/looprpc"
2121
"github.com/lightninglabs/loop/staticaddr/address"
2222
"github.com/lightninglabs/loop/staticaddr/deposit"
23+
"github.com/lightninglabs/loop/staticaddr/loopin"
2324
"github.com/lightninglabs/loop/staticaddr/script"
2425
"github.com/lightninglabs/loop/swap"
2526
mock_lnd "github.com/lightninglabs/loop/test"
@@ -306,6 +307,72 @@ func TestSetLiquidityParamsRejectsStaticAutoloopWithoutExperimental(
306307
require.ErrorContains(t, err, "--experimental")
307308
}
308309

310+
// TestStaticAddressLoopInTimestamp verifies that zero timestamps are omitted
311+
// from static loop-in responses instead of passing a zero time to UnixNano.
312+
func TestStaticAddressLoopInTimestamp(t *testing.T) {
313+
require.Zero(t, staticAddressLoopInTimestamp(time.Time{}))
314+
315+
timestamp := time.Unix(1_234, 567).UTC()
316+
require.Equal(
317+
t, timestamp.UnixNano(),
318+
staticAddressLoopInTimestamp(timestamp),
319+
)
320+
}
321+
322+
// TestStaticAddressLoopInSwapServerCost verifies that static loop-in server
323+
// costs are only reported once the invoice payment was received. Timeout path
324+
// costs are not persisted today, so they are intentionally not estimated here.
325+
func TestStaticAddressLoopInSwapServerCost(t *testing.T) {
326+
const quoteFee = btcutil.Amount(1_234)
327+
328+
tests := []struct {
329+
name string
330+
state fsm.StateType
331+
wantServer int64
332+
}{
333+
{
334+
name: "pending before payment",
335+
state: loopin.SignHtlcTx,
336+
},
337+
{
338+
name: "payment received",
339+
state: loopin.PaymentReceived,
340+
wantServer: int64(quoteFee),
341+
},
342+
{
343+
name: "succeeded",
344+
state: loopin.Succeeded,
345+
wantServer: int64(quoteFee),
346+
},
347+
{
348+
name: "succeeded transition failed",
349+
state: loopin.SucceededTransitioningFailed,
350+
wantServer: int64(quoteFee),
351+
},
352+
{
353+
name: "timeout swept",
354+
state: loopin.HtlcTimeoutSwept,
355+
},
356+
{
357+
name: "failed",
358+
state: loopin.Failed,
359+
},
360+
}
361+
362+
for _, test := range tests {
363+
t.Run(test.name, func(t *testing.T) {
364+
swap := &loopin.StaticAddressLoopIn{
365+
QuotedSwapFee: quoteFee,
366+
}
367+
swap.SetState(test.state)
368+
369+
costServer := staticAddressLoopInSwapServerCost(swap)
370+
371+
require.Equal(t, test.wantServer, costServer)
372+
})
373+
}
374+
}
375+
309376
// TestRPCAutoloopReasonStaticLoopInNoCandidate verifies that the new planner
310377
// reason is exposed over rpc.
311378
func TestRPCAutoloopReasonStaticLoopInNoCandidate(t *testing.T) {

looprpc/client.pb.go

Lines changed: 55 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

looprpc/client.proto

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,6 +2143,31 @@ message StaticAddressLoopInSwap {
21432143
The deposits that were used for this swap.
21442144
*/
21452145
repeated Deposit deposits = 6;
2146+
2147+
/*
2148+
Initiation time of the swap.
2149+
*/
2150+
int64 initiation_time = 7;
2151+
2152+
/*
2153+
Last update time of the swap.
2154+
*/
2155+
int64 last_update_time = 8;
2156+
2157+
/*
2158+
Swap server cost.
2159+
*/
2160+
int64 cost_server = 9;
2161+
2162+
/*
2163+
On-chain transaction cost.
2164+
*/
2165+
int64 cost_onchain = 10;
2166+
2167+
/*
2168+
Off-chain routing fees.
2169+
*/
2170+
int64 cost_offchain = 11;
21462171
}
21472172

21482173
enum StaticAddressLoopInSwapState {

looprpc/client.swagger.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2807,6 +2807,31 @@
28072807
"$ref": "#/definitions/looprpcDeposit"
28082808
},
28092809
"description": "The deposits that were used for this swap."
2810+
},
2811+
"initiation_time": {
2812+
"type": "string",
2813+
"format": "int64",
2814+
"description": "Initiation time of the swap."
2815+
},
2816+
"last_update_time": {
2817+
"type": "string",
2818+
"format": "int64",
2819+
"description": "Last update time of the swap."
2820+
},
2821+
"cost_server": {
2822+
"type": "string",
2823+
"format": "int64",
2824+
"description": "Swap server cost."
2825+
},
2826+
"cost_onchain": {
2827+
"type": "string",
2828+
"format": "int64",
2829+
"description": "On-chain transaction cost."
2830+
},
2831+
"cost_offchain": {
2832+
"type": "string",
2833+
"format": "int64",
2834+
"description": "Off-chain routing fees."
28102835
}
28112836
}
28122837
},

0 commit comments

Comments
 (0)