Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple Asset Loop out #872

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions assets/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package assets

import (
"os"

"github.com/lightninglabs/taproot-assets/taprpc"
"github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
"github.com/lightningnetwork/lnd/macaroons"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"gopkg.in/macaroon.v2"
)

var (
maxMsgRecvSize = grpc.MaxCallRecvMsgSize(400 * 1024 * 1024)
)

// TapdConfig is a struct that holds the configuration options to connect to a
// taproot assets daemon.
type TapdConfig struct {
Host string `long:"host" description:"The host of the Tap daemon"`
MacaroonPath string `long:"macaroonpath" description:"Path to the admin macaroon"`
TLSPath string `long:"tlspath" description:"Path to the TLS certificate"`
}

// DefaultTapdConfig returns a default configuration to connect to a taproot
// assets daemon.
func DefaultTapdConfig() *TapdConfig {
return &TapdConfig{
Host: "",
MacaroonPath: "",
TLSPath: "",
}
}

// NewTapdClient retusn a new taproot assets client.
func NewTapdClient(config *TapdConfig) (*TapdClient, error) {
// Create the client connection to the server.
conn, err := getClientConn(config)
if err != nil {
return nil, err
}

// Create the TapdClient.
client := &TapdClient{
cc: conn,
TaprootAssetsClient: taprpc.NewTaprootAssetsClient(conn),
TaprootAssetChannelsClient: tapchannelrpc.NewTaprootAssetChannelsClient(conn),
}

return client, nil
}

// Close closes the client connection to the server.
func (c *TapdClient) Close() {
c.cc.Close()
}

// TapdClient is a client for the Tap daemon.
type TapdClient struct {
cc *grpc.ClientConn
taprpc.TaprootAssetsClient
tapchannelrpc.TaprootAssetChannelsClient
}

func getClientConn(config *TapdConfig) (*grpc.ClientConn, error) {
// Load the specified TLS certificate and build transport credentials.
creds, err := credentials.NewClientTLSFromFile(config.TLSPath, "")
if err != nil {
return nil, err
}

// Load the specified macaroon file.
macBytes, err := os.ReadFile(config.MacaroonPath)
if err != nil {
return nil, err
}
mac := &macaroon.Macaroon{}
if err := mac.UnmarshalBinary(macBytes); err != nil {
return nil, err
}

macaroon, err := macaroons.NewMacaroonCredential(mac)
if err != nil {
return nil, err
}
// Create the DialOptions with the macaroon credentials.
opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithPerRPCCredentials(macaroon),
grpc.WithDefaultCallOptions(maxMsgRecvSize),
}

// Dial the gRPC server.
conn, err := grpc.Dial(config.Host, opts...)
if err != nil {
return nil, err
}

return conn, nil
}
19 changes: 16 additions & 3 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/btcsuite/btcd/btcutil"
"github.com/lightninglabs/aperture/l402"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop/assets"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/loop/sweep"
Expand Down Expand Up @@ -94,6 +95,7 @@ type Client struct {
lndServices *lndclient.LndServices
sweeper *sweep.Sweeper
executor *executor
assetClient *assets.TapdClient

resumeReady chan struct{}
wg sync.WaitGroup
Expand Down Expand Up @@ -121,6 +123,9 @@ type ClientConfig struct {
// Lnd is an instance of the lnd proxy.
Lnd *lndclient.LndServices

// AssetClient is an instance of the assets client.
AssetClient *assets.TapdClient

// MaxL402Cost is the maximum price we are willing to pay to the server
// for the token.
MaxL402Cost btcutil.Amount
Expand Down Expand Up @@ -273,6 +278,7 @@ func NewClient(dbDir string, loopDB loopdb.SwapStore,
errChan: make(chan error),
clientConfig: *config,
lndServices: cfg.Lnd,
assetClient: cfg.AssetClient,
sweeper: sweeper,
executor: executor,
resumeReady: make(chan struct{}),
Expand Down Expand Up @@ -453,7 +459,7 @@ func (s *Client) Run(ctx context.Context, statusChan chan<- SwapInfo) error {
func (s *Client) resumeSwaps(ctx context.Context,
loopOutSwaps []*loopdb.LoopOut, loopInSwaps []*loopdb.LoopIn) {

swapCfg := newSwapConfig(s.lndServices, s.Store, s.Server)
swapCfg := newSwapConfig(s.lndServices, s.Store, s.Server, s.assetClient)

for _, pend := range loopOutSwaps {
if pend.State().State.Type() != loopdb.StateTypePending {
Expand Down Expand Up @@ -523,7 +529,14 @@ func (s *Client) LoopOut(globalCtx context.Context,
}

// Create a new swap object for this swap.
swapCfg := newSwapConfig(s.lndServices, s.Store, s.Server)
swapCfg := newSwapConfig(s.lndServices, s.Store, s.Server, s.assetClient)

// Verify that if we have an asset id set, we have a valid asset client
// to use.
if request.AssetId != nil && s.assetClient == nil {
return nil, errors.New("asset id set but no asset client provided")
}

initResult, err := newLoopOutSwap(
globalCtx, swapCfg, initiationHeight, request,
)
Expand Down Expand Up @@ -682,7 +695,7 @@ func (s *Client) LoopIn(globalCtx context.Context,

// Create a new swap object for this swap.
initiationHeight := s.executor.height()
swapCfg := newSwapConfig(s.lndServices, s.Store, s.Server)
swapCfg := newSwapConfig(s.lndServices, s.Store, s.Server, s.assetClient)
initResult, err := newLoopInSwap(
globalCtx, swapCfg, initiationHeight, request,
)
Expand Down
31 changes: 31 additions & 0 deletions cmd/loop/loopout.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"encoding/hex"
"fmt"
"math"
"strconv"
Expand Down Expand Up @@ -101,6 +102,18 @@ var loopOutCommand = cli.Command{
"payment might be retried, the actual total " +
"time may be longer",
},
cli.StringFlag{
Name: "asset_id",
Usage: "the asset ID of the asset to loop out, " +
"if this is set, the loop daemon will require a connection " +
"to a taproot assets daemon",
},
cli.StringFlag{
Name: "asset_edge_node",
Usage: "the pubkey of the edge node of the asset to loop out, " +
"this is required if the taproot assets daemon has multiple " +
"channels of the given asset id with different edge nodes",
},
forceFlag,
labelFlag,
verboseFlag,
Expand Down Expand Up @@ -186,6 +199,22 @@ func loopOut(ctx *cli.Context) error {
}
}

var assetId []byte
if ctx.IsSet("asset_id") {
assetId, err = hex.DecodeString(ctx.String("asset_id"))
if err != nil {
return err
}
}

var assetEdgeNode []byte
if ctx.IsSet("asset_edge_node") {
assetEdgeNode, err = hex.DecodeString(ctx.String("asset_edge_node"))
if err != nil {
return err
}
}

client, cleanup, err := getClient(ctx)
if err != nil {
return err
Expand Down Expand Up @@ -281,6 +310,8 @@ func loopOut(ctx *cli.Context) error {
Label: label,
Initiator: defaultInitiator,
PaymentTimeout: uint32(paymentTimeout),
AssetId: assetId,
AssetEdgeNode: assetEdgeNode,
})
if err != nil {
return err
Expand Down
Loading
Loading