staticaddr: cmd listdeposits and listswaps

This commit is contained in:
Slyghtning 2024-11-05 10:15:10 +01:00
parent a3f7fe44af
commit 439d178b96
No known key found for this signature in database
GPG key ID: F82D456EA023C9BF
11 changed files with 1717 additions and 183 deletions

View file

@ -94,6 +94,20 @@ var RequiredPermissions = map[string][]bakery.Op{
Entity: "loop",
Action: "in",
}},
"/looprpc.SwapClient/ListStaticAddressDeposits": {{
Entity: "swap",
Action: "read",
}, {
Entity: "loop",
Action: "in",
}},
"/looprpc.SwapClient/ListStaticAddressSwaps": {{
Entity: "swap",
Action: "read",
}, {
Entity: "loop",
Action: "in",
}},
"/looprpc.SwapClient/GetStaticAddressSummary": {{
Entity: "swap",
Action: "read",

View file

@ -763,11 +763,11 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
}
// Retrieve deposits to calculate their total value.
var summary *looprpc.StaticAddressSummaryResponse
var depositList *looprpc.ListStaticAddressDepositsResponse
amount := btcutil.Amount(req.Amt)
if len(req.DepositOutpoints) > 0 {
summary, err = s.GetStaticAddressSummary(
ctx, &looprpc.StaticAddressSummaryRequest{
depositList, err = s.ListStaticAddressDeposits(
ctx, &looprpc.ListStaticAddressDepositsRequest{
Outpoints: req.DepositOutpoints,
},
)
@ -775,14 +775,14 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
return nil, err
}
if summary == nil {
if depositList == nil {
return nil, fmt.Errorf("no summary returned for " +
"deposit outpoints")
}
// The requested amount should be 0 here if the request
// contained deposit outpoints.
if amount != 0 && len(summary.FilteredDeposits) > 0 {
if amount != 0 && len(depositList.FilteredDeposits) > 0 {
return nil, fmt.Errorf("amount should be 0 for " +
"deposit quotes")
}
@ -790,8 +790,8 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
// In case we quote for deposits we send the server both the
// total value and the number of deposits. This is so the server
// can probe the total amount and calculate the per input fee.
if amount == 0 && len(summary.FilteredDeposits) > 0 {
for _, deposit := range summary.FilteredDeposits {
if amount == 0 && len(depositList.FilteredDeposits) > 0 {
for _, deposit := range depositList.FilteredDeposits {
amount += btcutil.Amount(deposit.Value)
}
}
@ -1459,15 +1459,16 @@ func (s *swapClientServer) WithdrawDeposits(ctx context.Context,
}, err
}
// GetStaticAddressSummary returns a summary static address related information.
// Amongst deposits and withdrawals and their total values it also includes a
// list of detailed deposit information filtered by their state.
func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context,
req *looprpc.StaticAddressSummaryRequest) (
*looprpc.StaticAddressSummaryResponse, error) {
// ListStaticAddressDeposits returns a list of all sufficiently confirmed
// deposits behind the static address and displays properties like value,
// state or blocks til expiry.
func (s *swapClientServer) ListStaticAddressDeposits(ctx context.Context,
req *looprpc.ListStaticAddressDepositsRequest) (
*looprpc.ListStaticAddressDepositsResponse, error) {
outpoints := req.Outpoints
if req.StateFilter != looprpc.DepositState_UNKNOWN_STATE &&
len(req.Outpoints) > 0 {
len(outpoints) > 0 {
return nil, fmt.Errorf("can either filter by state or " +
"outpoints")
@ -1478,9 +1479,181 @@ func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context,
return nil, err
}
return s.depositSummary(
ctx, allDeposits, req.StateFilter, req.Outpoints,
// Deposits filtered by state or outpoints.
var filteredDeposits []*looprpc.Deposit
if len(outpoints) > 0 {
f := func(d *deposit.Deposit) bool {
for _, outpoint := range outpoints {
if outpoint == d.OutPoint.String() {
return true
}
}
return false
}
filteredDeposits = filter(allDeposits, f)
if len(outpoints) != len(filteredDeposits) {
return nil, fmt.Errorf("not all outpoints found in " +
"deposits")
}
} else {
f := func(d *deposit.Deposit) bool {
if req.StateFilter == looprpc.DepositState_UNKNOWN_STATE {
// Per default, we return deposits in all
// states.
return true
}
return d.IsInState(toServerState(req.StateFilter))
}
filteredDeposits = filter(allDeposits, f)
}
// Calculate the blocks until expiry for each deposit.
lndInfo, err := s.lnd.Client.GetInfo(ctx)
if err != nil {
return nil, err
}
bestBlockHeight := int64(lndInfo.BlockHeight)
params, err := s.staticAddressManager.GetStaticAddressParameters(ctx)
if err != nil {
return nil, err
}
for i := 0; i < len(filteredDeposits); i++ {
filteredDeposits[i].BlocksUntilExpiry =
filteredDeposits[i].ConfirmationHeight +
int64(params.Expiry) - bestBlockHeight
}
return &looprpc.ListStaticAddressDepositsResponse{
FilteredDeposits: filteredDeposits,
}, nil
}
// ListStaticAddressSwaps returns a list of all swaps that are currently pending
// or previously succeeded.
func (s *swapClientServer) ListStaticAddressSwaps(ctx context.Context,
_ *looprpc.ListStaticAddressSwapsRequest) (
*looprpc.ListStaticAddressSwapsResponse, error) {
swaps, err := s.staticLoopInManager.GetAllSwaps(ctx)
if err != nil {
return nil, err
}
if len(swaps) == 0 {
return &looprpc.ListStaticAddressSwapsResponse{}, nil
}
var clientSwaps []*looprpc.StaticAddressLoopInSwap
for _, swp := range swaps {
chainParams, err := s.network.ChainParams()
if err != nil {
return nil, fmt.Errorf("error getting chain params")
}
swapPayReq, err := zpay32.Decode(swp.SwapInvoice, chainParams)
if err != nil {
return nil, fmt.Errorf("error decoding swap invoice: "+
"%v", err)
}
swap := &looprpc.StaticAddressLoopInSwap{
SwapHash: swp.SwapHash[:],
DepositOutpoints: swp.DepositOutpoints,
State: toClientStaticAddressLoopInState(
swp.GetState(),
),
SwapAmountSatoshis: int64(swp.TotalDepositAmount()),
PaymentRequestAmountSatoshis: int64(
swapPayReq.MilliSat.ToSatoshis(),
),
}
clientSwaps = append(clientSwaps, swap)
}
return &looprpc.ListStaticAddressSwapsResponse{
Swaps: clientSwaps,
}, nil
}
// GetStaticAddressSummary returns a summary static address related information.
// Amongst deposits and withdrawals and their total values it also includes a
// list of detailed deposit information filtered by their state.
func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context,
_ *looprpc.StaticAddressSummaryRequest) (
*looprpc.StaticAddressSummaryResponse, error) {
allDeposits, err := s.depositManager.GetAllDeposits(ctx)
if err != nil {
return nil, err
}
var (
totalNumDeposits = len(allDeposits)
valueUnconfirmed int64
valueDeposited int64
valueExpired int64
valueWithdrawn int64
valueLoopedIn int64
htlcTimeoutSwept int64
)
// Value unconfirmed.
utxos, err := s.staticAddressManager.ListUnspent(
ctx, 0, deposit.MinConfs-1,
)
if err != nil {
return nil, err
}
for _, u := range utxos {
valueUnconfirmed += int64(u.Value)
}
// Confirmed total values by category.
for _, d := range allDeposits {
value := int64(d.Value)
switch d.GetState() {
case deposit.Deposited:
valueDeposited += value
case deposit.Expired:
valueExpired += value
case deposit.Withdrawn:
valueWithdrawn += value
case deposit.LoopedIn:
valueLoopedIn += value
case deposit.HtlcTimeoutSwept:
htlcTimeoutSwept += value
}
}
params, err := s.staticAddressManager.GetStaticAddressParameters(ctx)
if err != nil {
return nil, err
}
address, err := s.staticAddressManager.GetTaprootAddress(
params.ClientPubkey, params.ServerPubkey, int64(params.Expiry),
)
if err != nil {
return nil, err
}
return &looprpc.StaticAddressSummaryResponse{
StaticAddress: address.String(),
RelativeExpiryBlocks: uint64(params.Expiry),
TotalNumDeposits: uint32(totalNumDeposits),
ValueUnconfirmedSatoshis: valueUnconfirmed,
ValueDepositedSatoshis: valueDeposited,
ValueExpiredSatoshis: valueExpired,
ValueWithdrawnSatoshis: valueWithdrawn,
ValueLoopedInSatoshis: valueLoopedIn,
ValueHtlcTimeoutSweepsSatoshis: htlcTimeoutSwept,
}, nil
}
// StaticAddressLoopIn initiates a loop-in request using static address
@ -1534,108 +1707,6 @@ func (s *swapClientServer) StaticAddressLoopIn(ctx context.Context,
}, nil
}
func (s *swapClientServer) depositSummary(ctx context.Context,
deposits []*deposit.Deposit, stateFilter looprpc.DepositState,
outpointsFilter []string) (*looprpc.StaticAddressSummaryResponse,
error) {
var (
totalNumDeposits = len(deposits)
valueUnconfirmed int64
valueDeposited int64
valueExpired int64
valueWithdrawn int64
valueLoopedIn int64
htlcTimeoutSwept int64
)
// Value unconfirmed.
utxos, err := s.staticAddressManager.ListUnspent(
ctx, 0, deposit.MinConfs-1,
)
if err != nil {
return nil, err
}
for _, u := range utxos {
valueUnconfirmed += int64(u.Value)
}
// Confirmed total values by category.
for _, d := range deposits {
value := int64(d.Value)
switch d.GetState() {
case deposit.Deposited:
valueDeposited += value
case deposit.Expired:
valueExpired += value
case deposit.Withdrawn:
valueWithdrawn += value
case deposit.LoopedIn:
valueLoopedIn += value
case deposit.HtlcTimeoutSwept:
htlcTimeoutSwept += value
}
}
// Deposits filtered by state or outpoints.
var clientDeposits []*looprpc.Deposit
if len(outpointsFilter) > 0 {
f := func(d *deposit.Deposit) bool {
for _, outpoint := range outpointsFilter {
if outpoint == d.OutPoint.String() {
return true
}
}
return false
}
clientDeposits = filter(deposits, f)
if len(outpointsFilter) != len(clientDeposits) {
return nil, fmt.Errorf("not all outpoints found in " +
"deposits")
}
} else {
f := func(d *deposit.Deposit) bool {
if stateFilter == looprpc.DepositState_UNKNOWN_STATE {
// Per default, we return deposits in all
// states.
return true
}
return d.IsInState(toServerState(stateFilter))
}
clientDeposits = filter(deposits, f)
}
params, err := s.staticAddressManager.GetStaticAddressParameters(ctx)
if err != nil {
return nil, err
}
address, err := s.staticAddressManager.GetTaprootAddress(
params.ClientPubkey, params.ServerPubkey, int64(params.Expiry),
)
if err != nil {
return nil, err
}
return &looprpc.StaticAddressSummaryResponse{
StaticAddress: address.String(),
TotalNumDeposits: uint32(totalNumDeposits),
ValueUnconfirmedSatoshis: valueUnconfirmed,
ValueDepositedSatoshis: valueDeposited,
ValueExpiredSatoshis: valueExpired,
ValueWithdrawnSatoshis: valueWithdrawn,
ValueLoopedInSatoshis: valueLoopedIn,
ValueHtlcTimeoutSweepsSatoshis: htlcTimeoutSwept,
FilteredDeposits: clientDeposits,
}, nil
}
type filterFunc func(deposits *deposit.Deposit) bool
func filter(deposits []*deposit.Deposit, f filterFunc) []*looprpc.Deposit {
@ -1648,8 +1719,10 @@ func filter(deposits []*deposit.Deposit, f filterFunc) []*looprpc.Deposit {
hash := d.Hash
outpoint := wire.NewOutPoint(&hash, d.Index).String()
deposit := &looprpc.Deposit{
Id: d.ID[:],
State: toClientState(d.GetState()),
Id: d.ID[:],
State: toClientDepositState(
d.GetState(),
),
Outpoint: outpoint,
Value: int64(d.Value),
ConfirmationHeight: d.ConfirmationHeight,
@ -1661,7 +1734,7 @@ func filter(deposits []*deposit.Deposit, f filterFunc) []*looprpc.Deposit {
return clientDeposits
}
func toClientState(state fsm.StateType) looprpc.DepositState {
func toClientDepositState(state fsm.StateType) looprpc.DepositState {
switch state {
case deposit.Deposited:
return looprpc.DepositState_DEPOSITED
@ -1698,6 +1771,51 @@ func toClientState(state fsm.StateType) looprpc.DepositState {
}
}
func toClientStaticAddressLoopInState(
state fsm.StateType) looprpc.StaticAddressLoopInSwapState {
switch state {
case loopin.InitHtlcTx:
return looprpc.StaticAddressLoopInSwapState_INIT_HTLC
case loopin.SignHtlcTx:
return looprpc.StaticAddressLoopInSwapState_SIGN_HTLC_TX
case loopin.MonitorInvoiceAndHtlcTx:
return looprpc.StaticAddressLoopInSwapState_MONITOR_INVOICE_HTLC_TX
case loopin.PaymentReceived:
return looprpc.StaticAddressLoopInSwapState_PAYMENT_RECEIVED
case loopin.SweepHtlcTimeout:
return looprpc.StaticAddressLoopInSwapState_SWEEP_STATIC_ADDRESS_HTLC_TIMEOUT
case loopin.MonitorHtlcTimeoutSweep:
return looprpc.StaticAddressLoopInSwapState_MONITOR_HTLC_TIMEOUT_SWEEP
case loopin.HtlcTimeoutSwept:
return looprpc.StaticAddressLoopInSwapState_HTLC_STATIC_ADDRESS_TIMEOUT_SWEPT
case loopin.FetchSignPushSweeplessSweepTx:
return looprpc.StaticAddressLoopInSwapState_FETCH_SIGN_PUSH_SWEEPLESS_SWEEP_TX
case loopin.Succeeded:
return looprpc.StaticAddressLoopInSwapState_SUCCEEDED
case loopin.SucceededSweeplessSigFailed:
return looprpc.StaticAddressLoopInSwapState_SUCCEEDED_SWEEPLESS_SIG_FAILED
case loopin.UnlockDeposits:
return looprpc.StaticAddressLoopInSwapState_UNLOCK_DEPOSITS
case loopin.Failed:
return looprpc.StaticAddressLoopInSwapState_FAILED_STATIC_ADDRESS_SWAP
default:
return looprpc.StaticAddressLoopInSwapState_UNKNOWN_STATIC_ADDRESS_SWAP_STATE
}
}
func toServerState(state looprpc.DepositState) fsm.StateType {
switch state {
case looprpc.DepositState_DEPOSITED: