mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
loopout: add asset accounting
This commit is contained in:
parent
dfa58d4906
commit
3e3c863819
6 changed files with 920 additions and 682 deletions
|
|
@ -349,6 +349,10 @@ func (s *Client) FetchSwaps(ctx context.Context) ([]*SwapInfo, error) {
|
|||
return nil, swap.ErrInvalidOutputType
|
||||
}
|
||||
|
||||
if swp.Contract.AssetSwapInfo != nil {
|
||||
swapInfo.AssetSwapInfo = swp.Contract.AssetSwapInfo
|
||||
}
|
||||
|
||||
swaps = append(swaps, swapInfo)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -309,8 +309,8 @@ func toWalletAddrType(addrType looprpc.AddressType) (walletrpc.AddressType,
|
|||
}
|
||||
}
|
||||
|
||||
func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
|
||||
*looprpc.SwapStatus, error) {
|
||||
func (s *swapClientServer) marshallSwap(ctx context.Context,
|
||||
loopSwap *loop.SwapInfo) (*looprpc.SwapStatus, error) {
|
||||
|
||||
var (
|
||||
state looprpc.SwapState
|
||||
|
|
@ -383,6 +383,7 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
|
|||
)
|
||||
var outGoingChanSet []uint64
|
||||
var lastHop []byte
|
||||
var assetInfo *looprpc.AssetLoopOutInfo
|
||||
|
||||
switch loopSwap.SwapType {
|
||||
case swap.TypeIn:
|
||||
|
|
@ -413,6 +414,22 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
|
|||
|
||||
outGoingChanSet = loopSwap.OutgoingChanSet
|
||||
|
||||
if loopSwap.AssetSwapInfo != nil {
|
||||
assetName, err := s.assetClient.GetAssetName(
|
||||
ctx, loopSwap.AssetSwapInfo.AssetId,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
assetInfo = &looprpc.AssetLoopOutInfo{
|
||||
AssetId: hex.EncodeToString(loopSwap.AssetSwapInfo.AssetId), // nolint:lll
|
||||
AssetCostOffchain: loopSwap.AssetSwapInfo.PrepayPaidAmt +
|
||||
loopSwap.AssetSwapInfo.SwapPaidAmt, // nolint:lll
|
||||
AssetName: assetName,
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, errors.New("unknown swap type")
|
||||
}
|
||||
|
|
@ -435,6 +452,7 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
|
|||
Label: loopSwap.Label,
|
||||
LastHop: lastHop,
|
||||
OutgoingChanSet: outGoingChanSet,
|
||||
AssetInfo: assetInfo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -445,7 +463,7 @@ func (s *swapClientServer) Monitor(in *looprpc.MonitorRequest,
|
|||
log.Infof("Monitor request received")
|
||||
|
||||
send := func(info loop.SwapInfo) error {
|
||||
rpcSwap, err := s.marshallSwap(&info)
|
||||
rpcSwap, err := s.marshallSwap(server.Context(), &info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -540,7 +558,7 @@ func (s *swapClientServer) Monitor(in *looprpc.MonitorRequest,
|
|||
|
||||
// ListSwaps returns a list of all currently known swaps and their current
|
||||
// status.
|
||||
func (s *swapClientServer) ListSwaps(_ context.Context,
|
||||
func (s *swapClientServer) ListSwaps(ctx context.Context,
|
||||
req *looprpc.ListSwapsRequest) (*looprpc.ListSwapsResponse, error) {
|
||||
|
||||
var (
|
||||
|
|
@ -563,7 +581,7 @@ func (s *swapClientServer) ListSwaps(_ context.Context,
|
|||
continue
|
||||
}
|
||||
|
||||
rpcSwap, err := s.marshallSwap(&swp)
|
||||
rpcSwap, err := s.marshallSwap(ctx, &swp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -641,11 +659,17 @@ func filterSwap(swapInfo *loop.SwapInfo, filter *looprpc.ListSwapsFilter) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// If we only want to return asset swaps, we only return swaps that have
|
||||
// an asset id set.
|
||||
if filter.AssetSwapOnly && swapInfo.AssetSwapInfo == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// SwapInfo returns all known details about a single swap.
|
||||
func (s *swapClientServer) SwapInfo(_ context.Context,
|
||||
func (s *swapClientServer) SwapInfo(ctx context.Context,
|
||||
req *looprpc.SwapInfoRequest) (*looprpc.SwapStatus, error) {
|
||||
|
||||
swapHash, err := lntypes.MakeHash(req.Id)
|
||||
|
|
@ -659,7 +683,7 @@ func (s *swapClientServer) SwapInfo(_ context.Context,
|
|||
if !ok {
|
||||
return nil, fmt.Errorf("swap with hash %s not found", req.Id)
|
||||
}
|
||||
return s.marshallSwap(&swp)
|
||||
return s.marshallSwap(ctx, &swp)
|
||||
}
|
||||
|
||||
// AbandonSwap requests the server to abandon a swap with the given hash.
|
||||
|
|
|
|||
56
loopout.go
56
loopout.go
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
|
@ -355,6 +356,10 @@ func (s *loopOutSwap) sendUpdate(ctx context.Context) error {
|
|||
info.OutgoingChanSet = outgoingChanSet
|
||||
}
|
||||
|
||||
if s.isAssetSwap() {
|
||||
info.AssetSwapInfo = s.AssetSwapInfo
|
||||
}
|
||||
|
||||
select {
|
||||
case s.statusChan <- *info:
|
||||
case <-ctx.Done():
|
||||
|
|
@ -436,7 +441,7 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
|
|||
case result := <-s.swapPaymentChan:
|
||||
s.swapPaymentChan = nil
|
||||
|
||||
err := s.handlePaymentResult(result, true)
|
||||
err := s.handlePaymentResult(globalCtx, result, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -452,7 +457,7 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
|
|||
case result := <-s.prePaymentChan:
|
||||
s.prePaymentChan = nil
|
||||
|
||||
err := s.handlePaymentResult(result, false)
|
||||
err := s.handlePaymentResult(globalCtx, result, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -485,8 +490,8 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
|
|||
// handlePaymentResult processes the result of a payment attempt. If the
|
||||
// payment was successful and this is the main swap payment, the cost of the
|
||||
// swap is updated.
|
||||
func (s *loopOutSwap) handlePaymentResult(result paymentResult,
|
||||
swapPayment bool) error {
|
||||
func (s *loopOutSwap) handlePaymentResult(ctx context.Context,
|
||||
result paymentResult, swapPayment bool) error {
|
||||
|
||||
switch {
|
||||
// If our result has a non-nil error, our status will be nil. In this
|
||||
|
|
@ -513,6 +518,17 @@ func (s *loopOutSwap) handlePaymentResult(result paymentResult,
|
|||
// the swap payment and the prepay.
|
||||
s.cost.Offchain += result.status.Fee.ToSatoshis()
|
||||
|
||||
// If this is an asset payment, we'll write the asset amounts
|
||||
// to the swap.
|
||||
if s.isAssetSwap() {
|
||||
err := s.fillAssetOffchainPaymentResult(
|
||||
ctx, result, swapPayment,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
case result.status.State == lnrpc.Payment_FAILED:
|
||||
|
|
@ -1035,7 +1051,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
|
|||
case result := <-s.swapPaymentChan:
|
||||
s.swapPaymentChan = nil
|
||||
|
||||
err := s.handlePaymentResult(result, true)
|
||||
err := s.handlePaymentResult(ctx, result, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1057,7 +1073,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
|
|||
case result := <-s.prePaymentChan:
|
||||
s.prePaymentChan = nil
|
||||
|
||||
err := s.handlePaymentResult(result, false)
|
||||
err := s.handlePaymentResult(ctx, result, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1458,6 +1474,34 @@ func (s *loopOutSwap) canSweep() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (s *loopOutSwap) fillAssetOffchainPaymentResult(ctx context.Context,
|
||||
result paymentResult, isSwapPayment bool) error {
|
||||
|
||||
if len(result.status.Htlcs) == 0 {
|
||||
return fmt.Errorf("no htlcs in payment result")
|
||||
}
|
||||
|
||||
// We only expect one htlc in the result.
|
||||
htlc := result.status.Htlcs[0]
|
||||
|
||||
var assetData rfqmsg.JsonHtlc
|
||||
|
||||
err := json.Unmarshal(htlc.Route.CustomChannelData, &assetData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
assetSendAmt := assetData.Balances[0].Amount
|
||||
if isSwapPayment {
|
||||
s.AssetSwapInfo.SwapPaidAmt = assetSendAmt
|
||||
log.Debugf("Asset off-chain payment success: %v", assetSendAmt)
|
||||
} else {
|
||||
s.AssetSwapInfo.PrepayPaidAmt = assetSendAmt
|
||||
}
|
||||
|
||||
return s.store.UpdateLoopOutAssetInfo(ctx, s.hash, s.AssetSwapInfo)
|
||||
}
|
||||
|
||||
// isAssetSwap returns true if the swap is an asset swap.
|
||||
func (s *loopOutSwap) isAssetSwap() bool {
|
||||
return s.AssetSwapInfo != nil
|
||||
|
|
|
|||
1450
looprpc/client.pb.go
1450
looprpc/client.pb.go
File diff suppressed because it is too large
Load diff
|
|
@ -552,6 +552,9 @@ message SwapStatus {
|
|||
|
||||
// An optional label given to the swap on creation.
|
||||
string label = 15;
|
||||
|
||||
// If the swap was an asset swap, the asset information will be returned.
|
||||
AssetLoopOutInfo asset_info = 19;
|
||||
}
|
||||
|
||||
enum SwapType {
|
||||
|
|
@ -698,6 +701,9 @@ message ListSwapsFilter {
|
|||
|
||||
// If specified on creation, the last hop of the swap.
|
||||
bytes loop_in_last_hop = 5;
|
||||
|
||||
// If specified, only returns asset swaps.
|
||||
bool asset_swap_only = 6;
|
||||
}
|
||||
|
||||
message ListSwapsResponse {
|
||||
|
|
@ -2079,3 +2085,18 @@ message AssetRfqInfo {
|
|||
*/
|
||||
string asset_name = 5;
|
||||
}
|
||||
|
||||
message AssetLoopOutInfo {
|
||||
/*
|
||||
The asset id that was used to pay for the swap invoice.
|
||||
*/
|
||||
string asset_id = 1;
|
||||
/*
|
||||
The human readable name of the asset.
|
||||
*/
|
||||
string asset_name = 2;
|
||||
/*
|
||||
The total asset offchain cost of the swap.
|
||||
*/
|
||||
uint64 asset_cost_offchain = 3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -618,6 +618,13 @@
|
|||
"required": false,
|
||||
"type": "string",
|
||||
"format": "byte"
|
||||
},
|
||||
{
|
||||
"name": "list_swap_filter.asset_swap_only",
|
||||
"description": "If specified, only returns asset swaps.",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
|
|
@ -673,6 +680,24 @@
|
|||
"description": "- `unknown`: Unknown address type\n- `p2tr`: Pay to taproot pubkey (`TAPROOT_PUBKEY` = 1)",
|
||||
"title": "`AddressType` has to be one of:"
|
||||
},
|
||||
"looprpcAssetLoopOutInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"asset_id": {
|
||||
"type": "string",
|
||||
"description": "The asset id that was used to pay for the swap invoice."
|
||||
},
|
||||
"asset_name": {
|
||||
"type": "string",
|
||||
"description": "The human readable name of the asset."
|
||||
},
|
||||
"asset_cost_offchain": {
|
||||
"type": "string",
|
||||
"format": "uint64",
|
||||
"description": "The total asset offchain cost of the swap."
|
||||
}
|
||||
}
|
||||
},
|
||||
"looprpcAssetLoopOutRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -1326,6 +1351,10 @@
|
|||
"type": "string",
|
||||
"format": "byte",
|
||||
"description": "If specified on creation, the last hop of the swap."
|
||||
},
|
||||
"asset_swap_only": {
|
||||
"type": "boolean",
|
||||
"description": "If specified, only returns asset swaps."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -1971,6 +2000,10 @@
|
|||
"label": {
|
||||
"type": "string",
|
||||
"description": "An optional label given to the swap on creation."
|
||||
},
|
||||
"asset_info": {
|
||||
"$ref": "#/definitions/looprpcAssetLoopOutInfo",
|
||||
"description": "If the swap was an asset swap, the asset information will be returned."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue