From 49978a4ca46b581816d2289a0109d8fc1cb74ad8 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Mon, 2 Feb 2026 19:22:41 -0500 Subject: [PATCH 01/15] cmd/loop: print homedir in help messages as ~ Make the output homedir-independent to facilitate tests. --- cmd/loop/default_path_text_test.go | 82 ++++++++++++++++++++++++++++++ cmd/loop/main.go | 59 +++++++++++++++++---- 2 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 cmd/loop/default_path_text_test.go diff --git a/cmd/loop/default_path_text_test.go b/cmd/loop/default_path_text_test.go new file mode 100644 index 000000000..1785966b1 --- /dev/null +++ b/cmd/loop/default_path_text_test.go @@ -0,0 +1,82 @@ +package main + +import ( + "errors" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +// TestDefaultPathText verifies HOME-based path elision behavior used for help +// defaults without relying on the real environment. +func TestDefaultPathText(t *testing.T) { + sep := string(filepath.Separator) + home := filepath.Clean(sep + "home" + sep + "alice") + + homeDir := func() (string, error) { return home, nil } + + tests := []struct { + name string + value string + homeFn func() (string, error) + want string + }{ + { + name: "empty value", + value: "", + homeFn: func() (string, error) { + return home, nil + }, + want: "", + }, + { + name: "nil homedir func", + value: home + sep + "data", + homeFn: nil, + want: home + sep + "data", + }, + { + name: "homedir error", + value: home + sep + "data", + homeFn: func() (string, error) { + return "", errors.New("homedir error") + }, + want: home + sep + "data", + }, + { + name: "exact home", + value: home, + homeFn: homeDir, + want: "~", + }, + { + name: "home prefix", + value: home + sep + "dir" + sep + "file", + homeFn: homeDir, + want: "~" + sep + "dir" + sep + "file", + }, + { + name: "non-home path", + value: filepath.Clean(sep + "var" + sep + "tmp"), + homeFn: homeDir, + want: filepath.Clean(sep + "var" + sep + "tmp"), + }, + { + name: "prefix but not path segment", + value: home + "x" + sep + "dir", + homeFn: homeDir, + want: home + "x" + sep + "dir", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := defaultPathText(test.value, test.homeFn) + require.Equalf( + t, test.want, got, + "defaultPathText(%q)", test.value, + ) + }) + } +} diff --git a/cmd/loop/main.go b/cmd/loop/main.go index 14db1c583..a28feca51 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -52,10 +52,11 @@ var ( defaultInitiator = "loop-cli" loopDirFlag = &cli.StringFlag{ - Name: "loopdir", - Value: loopd.LoopDirBase, - Usage: "path to loop's base directory", - Sources: cli.EnvVars(envVarLoopDir), + Name: "loopdir", + Value: loopd.LoopDirBase, + DefaultText: defaultPathText(loopd.LoopDirBase, os.UserHomeDir), + Usage: "path to loop's base directory", + Sources: cli.EnvVars(envVarLoopDir), } networkFlag = &cli.StringFlag{ Name: "network", @@ -66,15 +67,21 @@ var ( } tlsCertFlag = &cli.StringFlag{ - Name: "tlscertpath", - Usage: "path to loop's TLS certificate", - Value: loopd.DefaultTLSCertPath, + Name: "tlscertpath", + Usage: "path to loop's TLS certificate", + Value: loopd.DefaultTLSCertPath, + DefaultText: defaultPathText( + loopd.DefaultTLSCertPath, os.UserHomeDir, + ), Sources: cli.EnvVars(envVarTLSCertPath), } macaroonPathFlag = &cli.StringFlag{ - Name: "macaroonpath", - Usage: "path to macaroon file", - Value: loopd.DefaultMacaroonPath, + Name: "macaroonpath", + Usage: "path to macaroon file", + Value: loopd.DefaultMacaroonPath, + DefaultText: defaultPathText( + loopd.DefaultMacaroonPath, os.UserHomeDir, + ), Sources: cli.EnvVars(envVarMacaroonPath), } verboseFlag = &cli.BoolFlag{ @@ -132,6 +139,38 @@ const ( envVarMacaroonPath = "LOOPCLI_MACAROONPATH" ) +// defaultPathText returns a help-friendly path string that replaces the user's +// home directory with "~". The homeDir function is injected so callers can +// control environment-dependent behavior in tests. +func defaultPathText(value string, homeDir func() (string, error)) string { + if value == "" { + return value + } + + if homeDir == nil { + return value + } + + home, err := homeDir() + if err != nil || home == "" { + return value + } + + cleanHome := filepath.Clean(home) + cleanValue := filepath.Clean(value) + if cleanValue == cleanHome { + return "~" + } + + prefix := cleanHome + string(filepath.Separator) + if strings.HasPrefix(cleanValue, prefix) { + return "~" + string(filepath.Separator) + + strings.TrimPrefix(cleanValue, prefix) + } + + return value +} + func printJSON(resp interface{}) { b, err := json.Marshal(resp) if err != nil { From 1ff52ffce42c37b689355056049dd483d5d53692 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 00:07:41 -0500 Subject: [PATCH 02/15] cmd/loop: remove orphan flag access abandonSwap used to access flag --id which does not exist. --- cmd/loop/swaps.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/loop/swaps.go b/cmd/loop/swaps.go index fae25c3cf..9d60d98e8 100644 --- a/cmd/loop/swaps.go +++ b/cmd/loop/swaps.go @@ -207,9 +207,6 @@ func abandonSwap(ctx context.Context, cmd *cli.Command) error { var id string switch { - case cmd.IsSet("id"): - id = cmd.String("id") - case cmd.NArg() > 0: id = args.First() From 6f7c4c3f3130f9313ec6f2e387cf68cfe566ab34 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 01:54:28 -0500 Subject: [PATCH 03/15] cmd/loop: add client conn cleanup --- cmd/loop/debug.go | 3 +-- cmd/loop/main.go | 17 ++++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cmd/loop/debug.go b/cmd/loop/debug.go index 9bb17106c..e2f7318c0 100644 --- a/cmd/loop/debug.go +++ b/cmd/loop/debug.go @@ -48,11 +48,10 @@ func getDebugClient(ctx context.Context, cmd *cli.Command) (looprpc.DebugClient, if err != nil { return nil, nil, err } - conn, err := getClientConn(rpcServer, tlsCertPath, macaroonPath) + conn, cleanup, err := getClientConn(rpcServer, tlsCertPath, macaroonPath) if err != nil { return nil, nil, err } - cleanup := func() { conn.Close() } debugClient := looprpc.NewDebugClient(conn) return debugClient, cleanup, nil diff --git a/cmd/loop/main.go b/cmd/loop/main.go index a28feca51..174b2d54f 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -252,11 +252,10 @@ func getClientWithConn(cmd *cli.Command) (looprpc.SwapClientClient, if err != nil { return nil, nil, nil, err } - conn, err := getClientConn(rpcServer, tlsCertPath, macaroonPath) + conn, cleanup, err := getClientConn(rpcServer, tlsCertPath, macaroonPath) if err != nil { return nil, nil, nil, err } - cleanup := func() { conn.Close() } loopClient := looprpc.NewSwapClientClient(conn) return loopClient, conn, cleanup, nil @@ -472,12 +471,12 @@ func logSwap(swap *looprpc.SwapStatus) { } func getClientConn(address, tlsCertPath, macaroonPath string) (*grpc.ClientConn, - error) { + func(), error) { // We always need to send a macaroon. macOption, err := readMacaroon(macaroonPath) if err != nil { - return nil, err + return nil, nil, err } opts := []grpc.DialOption{ @@ -488,18 +487,22 @@ func getClientConn(address, tlsCertPath, macaroonPath string) (*grpc.ClientConn, // Since TLS cannot be disabled, we'll always have a cert file to read. creds, err := credentials.NewClientTLSFromFile(tlsCertPath, "") if err != nil { - return nil, err + return nil, nil, err } opts = append(opts, grpc.WithTransportCredentials(creds)) conn, err := grpc.NewClient(address, opts...) if err != nil { - return nil, fmt.Errorf("unable to create RPC client: %v", + return nil, nil, fmt.Errorf("unable to create RPC client: %v", err) } - return conn, nil + cleanup := func() { + _ = conn.Close() + } + + return conn, cleanup, nil } // readMacaroon tries to read the macaroon file at the specified path and create From eda7b0ee135dee2f5ff973cfff0b8b3d1d7cd389 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Wed, 4 Feb 2026 16:29:24 -0500 Subject: [PATCH 04/15] cmd/loop: factor newRootCommand --- cmd/loop/main.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cmd/loop/main.go b/cmd/loop/main.go index 174b2d54f..465af8a0d 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -202,7 +202,15 @@ func fatal(err error) { } func main() { - rootCmd := &cli.Command{ + rootCmd := newRootCommand() + if err := rootCmd.Run(context.Background(), os.Args); err != nil { + fatal(err) + } +} + +// newRootCommand constructs the CLI root command for loop. +func newRootCommand() *cli.Command { + return &cli.Command{ Name: "loop", Usage: "control plane for your loopd", Version: loop.RichVersion(), @@ -223,10 +231,6 @@ func main() { return cli.ShowRootCommandHelp(cmd) }, } - - if err := rootCmd.Run(context.Background(), os.Args); err != nil { - fatal(err) - } } // getClient establishes a SwapClient RPC connection and returns the client and From 939ee48db451e37c50285b3ff943cea3b8aaf7bd Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Wed, 4 Feb 2026 16:30:10 -0500 Subject: [PATCH 05/15] cmd/loop: add cli clock and hook --- cmd/loop/loopout.go | 4 ++-- cmd/loop/main.go | 14 ++++++++++++++ cmd/loop/quote.go | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/cmd/loop/loopout.go b/cmd/loop/loopout.go index 2fe3c6e23..a3ed65bd5 100644 --- a/cmd/loop/loopout.go +++ b/cmd/loop/loopout.go @@ -249,9 +249,9 @@ func loopOut(ctx context.Context, cmd *cli.Command) error { // Set our maximum swap wait time. If a fast swap is requested we set // it to now, otherwise to 30 minutes in the future. fast := cmd.Bool("fast") - swapDeadline := time.Now() + swapDeadline := cliClock.Now() if !fast { - swapDeadline = time.Now().Add(defaultSwapWaitTime) + swapDeadline = cliClock.Now().Add(defaultSwapWaitTime) } sweepConfTarget := int32(cmd.Uint64("conf_target")) diff --git a/cmd/loop/main.go b/cmd/loop/main.go index 465af8a0d..8c5893e03 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -19,6 +19,7 @@ import ( "github.com/lightninglabs/loop/loopd" "github.com/lightninglabs/loop/looprpc" "github.com/lightninglabs/loop/swap" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/macaroons" @@ -99,6 +100,9 @@ var ( instantOutCommand, listInstantOutsCommand, stopCommand, printManCommand, printMarkdownCommand, } + + // cliClock provides the time source used by CLI commands. + cliClock clock.Clock = clock.NewDefaultClock() ) const ( @@ -265,6 +269,16 @@ func getClientWithConn(cmd *cli.Command) (looprpc.SwapClientClient, return loopClient, conn, cleanup, nil } +// hookClock overrides cliClock until the returned callback is called. +func hookClock(c clock.Clock) func() { + prev := cliClock + cliClock = c + + return func() { + cliClock = prev + } +} + func getMaxRoutingFee(amt btcutil.Amount) btcutil.Amount { return swap.CalcFee(amt, maxRoutingFeeBase, maxRoutingFeeRate) } diff --git a/cmd/loop/quote.go b/cmd/loop/quote.go index d6e7b6c26..46826eaef 100644 --- a/cmd/loop/quote.go +++ b/cmd/loop/quote.go @@ -206,9 +206,9 @@ func quoteOut(ctx context.Context, cmd *cli.Command) error { defer cleanup() fast := cmd.Bool("fast") - swapDeadline := time.Now() + swapDeadline := cliClock.Now() if !fast { - swapDeadline = time.Now().Add(defaultSwapWaitTime) + swapDeadline = cliClock.Now().Add(defaultSwapWaitTime) } quoteReq := &looprpc.QuoteRequest{ From 7ecbb3fc09f0658178c624551d24c9091cbb1cf2 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Wed, 4 Feb 2026 16:32:10 -0500 Subject: [PATCH 06/15] cmd/loop: add stdio hooks --- cmd/loop/session_stdio.go | 138 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 cmd/loop/session_stdio.go diff --git a/cmd/loop/session_stdio.go b/cmd/loop/session_stdio.go new file mode 100644 index 000000000..582017ce7 --- /dev/null +++ b/cmd/loop/session_stdio.go @@ -0,0 +1,138 @@ +package main + +import ( + "io" + "os" + "sync" +) + +// hookStdout redirects stdout and returns a function to restore it. +func hookStdout(orig *os.File, forward io.Writer, + onChunk func([]byte)) (func() error, error) { + + return hookOutput( + func(f *os.File) { os.Stdout = f }, + orig, + forward, + onChunk, + ) +} + +// hookStderr redirects stderr and returns a function to restore it. +func hookStderr(orig *os.File, forward io.Writer, + onChunk func([]byte)) (func() error, error) { + + return hookOutput( + func(f *os.File) { os.Stderr = f }, + orig, + forward, + onChunk, + ) +} + +// hookOutput redirects an output stream and returns a restore function. +func hookOutput(setDest func(*os.File), orig *os.File, forward io.Writer, + onChunk func([]byte)) (func() error, error) { + + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + + setDest(w) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + defer r.Close() + + writer := composeWriter(forward, onChunk) + _, _ = io.Copy(writer, r) + }() + + return func() error { + setDest(orig) + _ = w.Close() + wg.Wait() + + return nil + }, nil +} + +// hookStdin redirects stdin and returns a function to restore it. +func hookStdin(orig *os.File, source io.Reader, + onChunk func([]byte)) (func() error, error) { + + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + + useOrig := false + if source == nil { + source = orig + useOrig = true + } else if source == orig { + useOrig = true + } + + if onChunk != nil { + source = io.TeeReader(source, chunkWriter(onChunk)) + } + + os.Stdin = r + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + defer w.Close() + + _, _ = io.Copy(w, source) + }() + + return func() error { + os.Stdin = orig + _ = r.Close() + _ = w.Close() + if !useOrig { + wg.Wait() + } + + return nil + }, nil +} + +// composeWriter builds a writer that forwards to the provided sinks. +func composeWriter(forward io.Writer, onChunk func([]byte)) io.Writer { + switch { + case forward != nil && onChunk != nil: + return io.MultiWriter(forward, chunkWriter(onChunk)) + + case forward != nil: + return forward + + case onChunk != nil: + return chunkWriter(onChunk) + + default: + return io.Discard + } +} + +// chunkWriter writes copy-safe chunks to a callback. +type chunkWriter func([]byte) + +// Write copies p before forwarding to the callback. +func (w chunkWriter) Write(p []byte) (int, error) { + if len(p) == 0 { + return 0, nil + } + + copyBuf := make([]byte, len(p)) + copy(copyBuf, p) + w(copyBuf) + + return len(p), nil +} From 21387bfc4d5186756acb7d1f719f8de31434c4d2 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Wed, 4 Feb 2026 16:31:27 -0500 Subject: [PATCH 07/15] cmd/loop: add session gRPC transport hook --- cmd/loop/debug.go | 7 +-- cmd/loop/main.go | 20 +++++---- cmd/loop/session_transport.go | 83 +++++++++++++++++++++++++++++++++++ cmd/loop/stop.go | 3 +- 4 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 cmd/loop/session_transport.go diff --git a/cmd/loop/debug.go b/cmd/loop/debug.go index e2f7318c0..84b24dae6 100644 --- a/cmd/loop/debug.go +++ b/cmd/loop/debug.go @@ -43,12 +43,7 @@ func forceAutoloop(ctx context.Context, cmd *cli.Command) error { } func getDebugClient(ctx context.Context, cmd *cli.Command) (looprpc.DebugClient, func(), error) { - rpcServer := cmd.String("rpcserver") - tlsCertPath, macaroonPath, err := extractPathArgs(cmd) - if err != nil { - return nil, nil, err - } - conn, cleanup, err := getClientConn(rpcServer, tlsCertPath, macaroonPath) + conn, cleanup, err := sessionTransport.Dial(cmd) if err != nil { return nil, nil, err } diff --git a/cmd/loop/main.go b/cmd/loop/main.go index 8c5893e03..11b9cf9f1 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -253,14 +253,9 @@ func getClient(cmd *cli.Command) (looprpc.SwapClientClient, // getClientWithConn returns both the SwapClient RPC client and the underlying // gRPC connection so callers can perform connection-aware actions. func getClientWithConn(cmd *cli.Command) (looprpc.SwapClientClient, - *grpc.ClientConn, func(), error) { + daemonConn, func(), error) { - rpcServer := cmd.String("rpcserver") - tlsCertPath, macaroonPath, err := extractPathArgs(cmd) - if err != nil { - return nil, nil, nil, err - } - conn, cleanup, err := getClientConn(rpcServer, tlsCertPath, macaroonPath) + conn, cleanup, err := sessionTransport.Dial(cmd) if err != nil { return nil, nil, nil, err } @@ -488,7 +483,8 @@ func logSwap(swap *looprpc.SwapStatus) { fmt.Println() } -func getClientConn(address, tlsCertPath, macaroonPath string) (*grpc.ClientConn, +// getClientConn dials the loopd gRPC server with TLS and macaroon auth. +func getClientConn(address, tlsCertPath, macaroonPath string) (daemonConn, func(), error) { // We always need to send a macaroon. @@ -502,6 +498,14 @@ func getClientConn(address, tlsCertPath, macaroonPath string) (*grpc.ClientConn, macOption, } + // Install gRPC interceptors for session recording if needed. + if unary := sessionTransport.UnaryInterceptor(); unary != nil { + opts = append(opts, grpc.WithChainUnaryInterceptor(unary)) + } + if stream := sessionTransport.StreamInterceptor(); stream != nil { + opts = append(opts, grpc.WithChainStreamInterceptor(stream)) + } + // Since TLS cannot be disabled, we'll always have a cert file to read. creds, err := credentials.NewClientTLSFromFile(tlsCertPath, "") if err != nil { diff --git a/cmd/loop/session_transport.go b/cmd/loop/session_transport.go new file mode 100644 index 000000000..5f06d244f --- /dev/null +++ b/cmd/loop/session_transport.go @@ -0,0 +1,83 @@ +package main + +import ( + "context" + + "github.com/urfave/cli/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/connectivity" +) + +// grpcTransport customizes gRPC dialing and interceptors for sessions. +type grpcTransport interface { + // Dial returns a gRPC connection for the CLI. + Dial(cmd *cli.Command) (daemonConn, func(), error) + + // UnaryInterceptor returns the unary interceptor to apply for session + // flows. + UnaryInterceptor() grpc.UnaryClientInterceptor + + // StreamInterceptor returns the stream interceptor to apply for session + // flows. + StreamInterceptor() grpc.StreamClientInterceptor +} + +// daemonConn is the client connection interface required by stop/wait flows. +type daemonConn interface { + grpc.ClientConnInterface + + // GetState reports the current connectivity state of the client + // channel. + GetState() connectivity.State + + // WaitForStateChange blocks until the state changes or the context + // expires. + WaitForStateChange(ctx context.Context, + sourceState connectivity.State) bool + + // Connect forces the channel out of idle mode. + Connect() +} + +// directGrpcTransport establishes real gRPC connections to loopd. +type directGrpcTransport struct{} + +// Dial opens a direct gRPC connection. +func (t *directGrpcTransport) Dial( + cmd *cli.Command) (daemonConn, func(), error) { + + return dialDirectConn(cmd) +} + +// UnaryInterceptor returns nil because direct connections do not need wrapping. +func (t *directGrpcTransport) UnaryInterceptor() grpc.UnaryClientInterceptor { + return nil +} + +// StreamInterceptor returns nil because direct connections do not need +// wrapping. +func (t *directGrpcTransport) StreamInterceptor() grpc.StreamClientInterceptor { + return nil +} + +// sessionTransport defines the active gRPC transport for CLI commands. +var sessionTransport grpcTransport = &directGrpcTransport{} + +// hookGrpc installs the active gRPC session transport hook. +func hookGrpc(transport grpcTransport) func() { + prev := sessionTransport + sessionTransport = transport + + return func() { sessionTransport = prev } +} + +// dialDirectConn returns the standard CLI gRPC connection. +func dialDirectConn(cmd *cli.Command) (daemonConn, func(), error) { + rpcServer := cmd.String("rpcserver") + tlsCertPath, macaroonPath, err := extractPathArgs(cmd) + if err != nil { + return nil, nil, err + } + + return getClientConn(rpcServer, tlsCertPath, macaroonPath) +} diff --git a/cmd/loop/stop.go b/cmd/loop/stop.go index 293c8c6b9..75fbd387a 100644 --- a/cmd/loop/stop.go +++ b/cmd/loop/stop.go @@ -6,7 +6,6 @@ import ( "github.com/lightninglabs/loop/looprpc" "github.com/urfave/cli/v3" - "google.golang.org/grpc" "google.golang.org/grpc/connectivity" ) @@ -63,7 +62,7 @@ func stopDaemon(ctx context.Context, cmd *cli.Command) error { // waitForDaemonShutdown monitors the gRPC connectivity state until the daemon // disappears. To avoid getting stuck in idle mode we nudge the connection to // reconnect when needed. -func waitForDaemonShutdown(ctx context.Context, conn *grpc.ClientConn) error { +func waitForDaemonShutdown(ctx context.Context, conn daemonConn) error { for { state := conn.GetState() From 806a5f80e8b991d8606581020aac7dcf19c88af7 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Wed, 4 Feb 2026 19:01:44 -0500 Subject: [PATCH 08/15] cmd/loop: add session recorder plumbing --- cmd/loop/main.go | 132 ++++++- cmd/loop/session_recorder.go | 625 ++++++++++++++++++++++++++++++ cmd/loop/session_recorder_test.go | 175 +++++++++ 3 files changed, 926 insertions(+), 6 deletions(-) create mode 100644 cmd/loop/session_recorder.go create mode 100644 cmd/loop/session_recorder_test.go diff --git a/cmd/loop/main.go b/cmd/loop/main.go index 11b9cf9f1..af6619ff3 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -8,9 +8,11 @@ import ( "fmt" "io/ioutil" "os" + "os/signal" "path/filepath" "strconv" "strings" + "syscall" "time" "github.com/btcsuite/btcd/btcutil" @@ -103,8 +105,48 @@ var ( // cliClock provides the time source used by CLI commands. cliClock clock.Clock = clock.NewDefaultClock() + + // sessionRec is the active recorder when session capture is enabled. + sessionRec *sessionRecorder + + // forceDeterministicJSON is enabled by tests to obtain stable JSON + // output. + forceDeterministicJSON bool ) +// installSessionSignalHandler records signals and cancels the root context. +func installSessionSignalHandler(cancel context.CancelFunc) func() { + if sessionRec == nil { + return func() {} + } + + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) + + done := make(chan struct{}) + go func() { + defer close(done) + interrupted := false + for sig := range sigCh { + sessionRec.LogSignal(sig) + if !interrupted { + interrupted = true + cancel() + continue + } + + _ = sessionRec.Finalize(fmt.Errorf("signal: %s", sig)) + os.Exit(130) + } + }() + + return func() { + signal.Stop(sigCh) + close(sigCh) + <-done + } +} + const ( // satAmtFmt formats a satoshi value into a one line string, intended to @@ -187,7 +229,8 @@ func printJSON(resp interface{}) { fatal(err) } out.WriteString("\n") - _, _ = out.WriteTo(os.Stdout) + printBytes := maybeNormalizeJSON(out.Bytes()) + _, _ = os.Stdout.Write(printBytes) } func printRespJSON(resp proto.Message) { @@ -197,19 +240,71 @@ func printRespJSON(resp proto.Message) { return } - fmt.Println(string(jsonBytes)) + fmt.Println(string(maybeNormalizeJSON(jsonBytes))) } func fatal(err error) { fmt.Fprintf(os.Stderr, "[loop] %v\n", err) + if sessionRec != nil { + if finalizeErr := sessionRec.Finalize(err); finalizeErr != nil { + fmt.Fprintf(os.Stderr, "[loop] unable to finalize "+ + "session: %v\n", finalizeErr) + } + } os.Exit(1) } func main() { + var err error + sessionRec, err = newSessionRecorder(os.Args) + if err != nil { + fatal(err) + } + + // Intercept clock and stdio if needed. + if sessionRec != nil { + restoreClock := hookClock( + clock.NewTestClock(time.Unix(sessionClockStartUnix, 0)), + ) + defer restoreClock() + + if err := sessionRec.Start(nil, nil, nil); err != nil { + fatal(err) + } + } + + // Intercept clock calls if needed. + var restoreTransport func() + if sessionRec != nil { + restoreTransport = hookGrpc(sessionRec) + defer restoreTransport() + } + rootCmd := newRootCommand() - if err := rootCmd.Run(context.Background(), os.Args); err != nil { + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + if sessionRec != nil { + ctx = sessionRec.InjectContext(ctx) + } + + if sessionRec != nil { + signalStop := installSessionSignalHandler(cancel) + defer signalStop() + } + + if err := rootCmd.Run(ctx, os.Args); err != nil { fatal(err) } + + if sessionRec != nil { + if err := sessionRec.Finalize(nil); err != nil { + fmt.Fprintf(os.Stderr, "[loop] unable to finalize "+ + "session: %v\n", err) + } + } } // newRootCommand constructs the CLI root command for loop. @@ -239,9 +334,7 @@ func newRootCommand() *cli.Command { // getClient establishes a SwapClient RPC connection and returns the client and // a cleanup handler. -func getClient(cmd *cli.Command) (looprpc.SwapClientClient, - func(), error) { - +func getClient(cmd *cli.Command) (looprpc.SwapClientClient, func(), error) { client, _, cleanup, err := getClientWithConn(cmd) if err != nil { return nil, nil, err @@ -274,6 +367,33 @@ func hookClock(c clock.Clock) func() { } } +// maybeNormalizeJSON rewrites JSON output to avoid the build-dependent spacing +// introduced by google.golang.org/protobuf/internal/encoding/json (see +// WriteName in protobuf-go-hex-display/internal/encoding/json/encode.go, which +// uses internal/detrand.Bool). When recording or replaying sessions we ensure +// stable output by re-encoding with the standard library. +func maybeNormalizeJSON(raw []byte) []byte { + if sessionRec == nil && !forceDeterministicJSON { + return raw + } + + var parsed interface{} + if err := json.Unmarshal(raw, &parsed); err != nil { + return raw + } + + normalized, err := json.MarshalIndent(parsed, "", " ") + if err != nil { + return raw + } + + if len(raw) > 0 && raw[len(raw)-1] == '\n' { + normalized = append(normalized, '\n') + } + + return normalized +} + func getMaxRoutingFee(amt btcutil.Amount) btcutil.Amount { return swap.CalcFee(amt, maxRoutingFeeBase, maxRoutingFeeRate) } diff --git a/cmd/loop/session_recorder.go b/cmd/loop/session_recorder.go new file mode 100644 index 000000000..7acecd7e7 --- /dev/null +++ b/cmd/loop/session_recorder.go @@ -0,0 +1,625 @@ +package main + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "time" + + "github.com/lightninglabs/loop" + "github.com/urfave/cli/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" +) + +const ( + sessionEnvVar = "LOOP_SESSION_RECORD" + sessionDefaultDir = "cmd/loop/testdata/sessions" + sessionFileExt = ".json" +) + +// sessionClockStartUnix is the fixed timestamp used for recorded CLI sessions. +const sessionClockStartUnix int64 = 1769407086 + +// Event identifiers in recorded sessions. +const ( + eventStdout = "stdout" + eventStderr = "stderr" + eventStdin = "stdin" + eventGrpc = "grpc" + eventExit = "exit" + eventSignal = "signal" +) + +// grpcMarshalOptions is marshalling options to encode gRPC messages in recorded +// sessions. +var grpcMarshalOptions = protojson.MarshalOptions{ + UseProtoNames: true, + EmitUnpopulated: true, +} + +// sessionRecorder captures CLI IO and gRPC traffic for replay. +type sessionRecorder struct { + mu sync.Mutex + started time.Time + filePath string + slug string + + metadata sessionMetadata + events []sessionEvent + + finalizeOnce sync.Once + + hooksMu sync.Mutex + hooksStarted bool + stdoutUnhook func() error + stderrUnhook func() error + stdinUnhook func() error +} + +// sessionFile is a single recorded CLI session in JSON format. They are +// stored inside sessionDefaultDir. +type sessionFile struct { + Metadata sessionMetadata `json:"metadata"` + Events []sessionEvent `json:"events"` +} + +// sessionMetadata stores static session details and runtime metadata. +type sessionMetadata struct { + Args []string `json:"args"` + Env map[string]string `json:"env"` + Version string `json:"version"` + RunError *string `json:"run_error,omitempty"` + Duration *time.Duration `json:"duration,omitempty"` +} + +// sessionEvent records a single timestamped payload entry. +type sessionEvent struct { + TimeMS int64 `json:"time_ms"` + Kind string `json:"kind"` + Data json.RawMessage `json:"data"` +} + +// textPayload records stdout/stderr text chunks. +type textPayload struct { + Text string `json:"text"` +} + +// stdinPayload records stdin chunks. +type stdinPayload struct { + Text string `json:"text"` +} + +// grpcPayload records a gRPC message or error event. +type grpcPayload struct { + Method string `json:"method"` + Event string `json:"event"` + MessageType string `json:"message_type,omitempty"` + Payload json.RawMessage `json:"payload,omitempty"` + Error string `json:"error,omitempty"` +} + +// exitPayload records the final run error, if any. +type exitPayload struct { + RunError *string `json:"run_error,omitempty"` +} + +// signalPayload records handled signals. +type signalPayload struct { + Signal string `json:"signal"` +} + +// newSessionRecorder creates a recorder when session recording is enabled. +func newSessionRecorder(args []string) (*sessionRecorder, error) { + // Session recording is disabled unless the env var is set. + envValue, ok := os.LookupEnv(sessionEnvVar) + if !ok { + return nil, nil + } + + // Allow explicit disable by setting the env var to false. + enabled, err := strconv.ParseBool(envValue) + if err != nil { + return nil, fmt.Errorf("invalid %s value %q", sessionEnvVar, + envValue) + } + if !enabled { + return nil, nil + } + + // Initialize the recorder before collecting metadata. + recorder := &sessionRecorder{ + started: time.Now(), + } + + // Derive the slug before resolving the output file path. + recorder.slug = deriveSessionSlug(args) + + // Capture metadata that remains stable for the session. + metadata := sessionMetadata{ + Args: append([]string(nil), args...), + Env: collectSessionEnv(), + Version: loop.RichVersion(), + } + recorder.metadata = metadata + + // Resolve the session file location. + baseDir, fileName, err := recorder.resolveFilePath() + if err != nil { + return nil, err + } + recorder.filePath = filepath.Join(baseDir, fileName) + + return recorder, nil +} + +// collectSessionEnv extracts the environment variables recorded in sessions. +func collectSessionEnv() map[string]string { + env := make(map[string]string) + + // Record only LOOPCLI_ variables, excluding the recording toggle. + for _, kv := range os.Environ() { + parts := strings.SplitN(kv, "=", 2) + if len(parts) != 2 { + continue + } + key := parts[0] + value := parts[1] + if key == sessionEnvVar { + continue + } + if strings.HasPrefix(key, "LOOPCLI_") { + env[key] = value + } + } + + return env +} + +// resolveFilePath chooses the output directory and filename. +func (r *sessionRecorder) resolveFilePath() (string, string, error) { + counter, err := nextSessionCounter(sessionDefaultDir) + if err != nil { + return "", "", err + } + + slug := r.slug + if slug == "" { + slug = "session" + } + + name := fmt.Sprintf("%02d_%s%s", counter, slug, sessionFileExt) + + return sessionDefaultDir, name, nil +} + +// logEvent records a new event with the elapsed timestamp. +func (r *sessionRecorder) logEvent(kind string, payload interface{}) { + data, err := json.Marshal(payload) + if err != nil { + return + } + + event := sessionEvent{ + TimeMS: time.Since(r.started).Milliseconds(), + Kind: kind, + Data: data, + } + + r.mu.Lock() + defer r.mu.Unlock() + + r.events = append(r.events, event) +} + +// Start attaches stdin/stdout/stderr hooks for session recording. +func (r *sessionRecorder) Start(stdinSource io.Reader, + stdoutForward, stderrForward io.Writer) error { + + r.hooksMu.Lock() + defer r.hooksMu.Unlock() + + if r.hooksStarted { + return nil + } + + // Capture stdout and stderr first, then stdin. + origStdout := os.Stdout + if stdoutForward == nil { + stdoutForward = origStdout + } + outHook, err := hookStdout(origStdout, stdoutForward, func(p []byte) { + r.logEvent(eventStdout, textPayload{Text: string(p)}) + }) + if err != nil { + return err + } + + origStderr := os.Stderr + if stderrForward == nil { + stderrForward = origStderr + } + errHook, err := hookStderr(origStderr, stderrForward, func(p []byte) { + r.logEvent(eventStderr, textPayload{Text: string(p)}) + }) + if err != nil { + _ = outHook() + + return err + } + + origStdin := os.Stdin + if stdinSource == nil { + stdinSource = origStdin + } + stdinHook, err := hookStdin(origStdin, stdinSource, func(p []byte) { + r.logEvent(eventStdin, stdinPayload{Text: string(p)}) + }) + if err != nil { + _ = errHook() + _ = outHook() + + return err + } + + r.stdoutUnhook = outHook + r.stderrUnhook = errHook + r.stdinUnhook = stdinHook + r.hooksStarted = true + + return nil +} + +// stopHooks detaches any active IO hooks. +func (r *sessionRecorder) stopHooks() error { + r.hooksMu.Lock() + defer r.hooksMu.Unlock() + + var firstErr error + if r.stdoutUnhook != nil { + if err := r.stdoutUnhook(); err != nil && firstErr == nil { + firstErr = err + } + r.stdoutUnhook = nil + } + if r.stderrUnhook != nil { + if err := r.stderrUnhook(); err != nil && firstErr == nil { + firstErr = err + } + r.stderrUnhook = nil + } + if r.stdinUnhook != nil { + if err := r.stdinUnhook(); err != nil && firstErr == nil { + firstErr = err + } + r.stdinUnhook = nil + } + r.hooksStarted = false + + return firstErr +} + +// logExit records the final outcome and duration. +func (r *sessionRecorder) logExit(runErr error) { + var payload exitPayload + if runErr != nil { + msg := runErr.Error() + payload.RunError = &msg + } + + // Store the exit event first for the event stream. + r.logEvent(eventExit, payload) + + // Update metadata with the final run state. + duration := time.Since(r.started) + + r.mu.Lock() + defer r.mu.Unlock() + + if runErr != nil { + msg := runErr.Error() + r.metadata.RunError = &msg + } else { + r.metadata.RunError = nil + } + r.metadata.Duration = &duration +} + +// finalize writes the recorded session to disk once. +func (r *sessionRecorder) finalize(runErr error) error { + var finalizeErr error + r.finalizeOnce.Do(func() { + if err := r.stopHooks(); err != nil { + finalizeErr = err + + return + } + + r.logExit(runErr) + + r.mu.Lock() + metadata := r.metadata + events := append([]sessionEvent(nil), r.events...) + r.mu.Unlock() + + fileContent := sessionFile{ + Metadata: metadata, + Events: events, + } + + err := os.MkdirAll(filepath.Dir(r.filePath), 0o755) + if err != nil { + finalizeErr = err + + return + } + + file, err := os.Create(r.filePath) + if err != nil { + finalizeErr = err + + return + } + defer file.Close() + + encoder := json.NewEncoder(file) + encoder.SetIndent("", " ") + if err := encoder.Encode(fileContent); err != nil { + finalizeErr = err + + return + } + }) + + return finalizeErr +} + +// Finalize records the exit event and flushes the session to disk. +func (r *sessionRecorder) Finalize(runErr error) error { + return r.finalize(runErr) +} + +// Dial uses the direct gRPC connection for recording. +func (r *sessionRecorder) Dial(cmd *cli.Command) (daemonConn, func(), error) { + return dialDirectConn(cmd) +} + +// UnaryInterceptor captures unary RPCs for session playback. +func (r *sessionRecorder) UnaryInterceptor() grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, + cc *grpc.ClientConn, invoker grpc.UnaryInvoker, + opts ...grpc.CallOption) error { + + r.logGRPCMessage(method, "request", req, nil) + + err := invoker(ctx, method, req, reply, cc, opts...) + if err != nil { + r.logGRPCMessage(method, "error", nil, err) + + return err + } + + r.logGRPCMessage(method, "response", reply, nil) + + return nil + } +} + +// StreamInterceptor captures stream RPCs for session playback. +func (r *sessionRecorder) StreamInterceptor() grpc.StreamClientInterceptor { + return func(ctx context.Context, desc *grpc.StreamDesc, + cc *grpc.ClientConn, method string, streamer grpc.Streamer, + opts ...grpc.CallOption) (grpc.ClientStream, error) { + + clientStream, err := streamer(ctx, desc, cc, method, opts...) + if err != nil { + r.logGRPCMessage(method, "error", nil, err) + + return nil, err + } + + return &recordingClientStream{ + ClientStream: clientStream, + recorder: r, + method: method, + }, nil + } +} + +// recordingClientStream wraps a gRPC stream and logs message events. +type recordingClientStream struct { + grpc.ClientStream + + recorder *sessionRecorder + method string +} + +// SendMsg records the outgoing stream message. +func (s *recordingClientStream) SendMsg(m interface{}) error { + s.recorder.logGRPCMessage(s.method, "send", m, nil) + err := s.ClientStream.SendMsg(m) + if err != nil { + s.recorder.logGRPCMessage(s.method, "error", nil, err) + } + + return err +} + +// RecvMsg records the incoming stream message. +func (s *recordingClientStream) RecvMsg(m interface{}) error { + err := s.ClientStream.RecvMsg(m) + if err != nil { + s.recorder.logGRPCMessage(s.method, "error", nil, err) + + return err + } + + s.recorder.logGRPCMessage(s.method, "recv", m, nil) + + return nil +} + +// logGRPCMessage captures gRPC request/response data in the event stream. +func (r *sessionRecorder) logGRPCMessage(method, event string, msg interface{}, + receptionErr error) { + + payload := grpcPayload{Method: method, Event: event} + + if receptionErr != nil { + payload.Error = receptionErr.Error() + r.logEvent(eventGrpc, payload) + + return + } + + if msg != nil { + if protoMsg, ok := msg.(proto.Message); ok { + payload.MessageType = string( + proto.MessageName(protoMsg), + ) + data, err := grpcMarshalOptions.Marshal(protoMsg) + if err == nil { + payload.Payload = data + } + } else { + data, err := json.Marshal(msg) + if err == nil { + payload.Payload = data + } + } + } + + r.logEvent(eventGrpc, payload) +} + +// LogSignal records an incoming signal event. +func (r *sessionRecorder) LogSignal(sig os.Signal) { + r.logEvent(eventSignal, signalPayload{Signal: sig.String()}) +} + +// InjectContext tags the outgoing context with the session name. +func (r *sessionRecorder) InjectContext(ctx context.Context) context.Context { + return metadata.AppendToOutgoingContext( + ctx, "loop-session", filepath.Base(r.filePath), + ) +} + +// deriveSessionSlug builds a stable slug from the command arguments. +func deriveSessionSlug(args []string) string { + if len(args) == 0 { + return "" + } + + base := filepath.Base(args[0]) + tokens := []string{base} + + for _, arg := range args[1:] { + if strings.HasPrefix(arg, "-") { + break + } + if arg == "" { + continue + } + tokens = append(tokens, arg) + } + + return sanitizeSlug(strings.Join(tokens, "-")) +} + +// sanitizeSlug normalizes a session slug to a safe filename. +func sanitizeSlug(value string) string { + value = strings.ToLower(value) + var builder strings.Builder + lastDash := false + for _, r := range value { + if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') { + builder.WriteRune(r) + lastDash = false + + continue + } + + if !lastDash { + builder.WriteRune('-') + lastDash = true + } + } + + slug := strings.Trim(builder.String(), "-") + if slug == "" { + return "session" + } + + return slug +} + +// nextSessionCounter finds the next available session number. +func nextSessionCounter(baseDir string) (int, error) { + maxCounter := 0 + entries, err := os.ReadDir(baseDir) + if errors.Is(err, fs.ErrNotExist) { + return 1, nil + } + if err != nil { + return 0, err + } + + for _, entry := range entries { + if entry.IsDir() { + continue + } + if filepath.Ext(entry.Name()) != sessionFileExt { + continue + } + + counter, ok := parseSessionCounter(entry.Name()) + if !ok { + continue + } + if counter > maxCounter { + maxCounter = counter + } + } + + return maxCounter + 1, nil +} + +// parseSessionCounter extracts the numeric prefix from a session filename. +func parseSessionCounter(name string) (int, bool) { + base := strings.TrimSuffix(name, filepath.Ext(name)) + if base == "" { + return 0, false + } + + parts := strings.SplitN(base, "_", 2) + if parts[0] == "" { + return 0, false + } + + for _, r := range parts[0] { + if r < '0' || r > '9' { + return 0, false + } + } + + value, err := strconv.Atoi(parts[0]) + if err != nil { + return 0, false + } + + if value < 0 { + return 0, false + } + + return value, true +} diff --git a/cmd/loop/session_recorder_test.go b/cmd/loop/session_recorder_test.go new file mode 100644 index 000000000..b6fd0f62e --- /dev/null +++ b/cmd/loop/session_recorder_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// TestDeriveSessionSlug verifies slug derivation from CLI arguments. +func TestDeriveSessionSlug(t *testing.T) { + tests := []struct { + name string + args []string + want string + }{ + { + name: "empty_args", + want: "", + }, + { + name: "binary_only", + args: []string{"/usr/local/bin/loop"}, + want: "loop", + }, + { + name: "with_subcommand", + args: []string{"loop", "out"}, + want: "loop-out", + }, + { + name: "stops_at_flag", + args: []string{"loop", "out", "--network", "regtest"}, + want: "loop-out", + }, + { + name: "skips_empty_args", + args: []string{"loop", "", "quote", "out"}, + want: "loop-quote-out", + }, + { + name: "sanitizes_tokens", + args: []string{"loop", "Quote", "Out"}, + want: "loop-quote-out", + }, + { + name: "sanitizes_path_base", + args: []string{"/tmp/loop-cli", "out"}, + want: "loop-cli-out", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + slug := deriveSessionSlug(test.args) + require.Equal(t, test.want, slug) + }) + } +} + +// TestSanitizeSlug verifies slug normalization behavior. +func TestSanitizeSlug(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "already_clean", + input: "loop-out", + want: "loop-out", + }, + { + name: "upper_and_spaces", + input: "Loop Out", + want: "loop-out", + }, + { + name: "symbols_collapsed", + input: "loop@@@out", + want: "loop-out", + }, + { + name: "trims_dashes", + input: "--loop-out--", + want: "loop-out", + }, + { + name: "empty_to_default", + input: "!!!", + want: "session", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + slug := sanitizeSlug(test.input) + require.Equal(t, test.want, slug) + }) + } +} + +// TestParseSessionCounter verifies session counter parsing. +func TestParseSessionCounter(t *testing.T) { + tests := []struct { + name string + input string + want int + ok bool + }{ + { + name: "with_suffix", + input: "01_loop-out.json", + want: 1, + ok: true, + }, + { + name: "with_extra_underscores", + input: "12_loop_in.json", + want: 12, + ok: true, + }, + { + name: "no_suffix", + input: "99", + want: 99, + ok: true, + }, + { + name: "no_extension", + input: "7_loop-out", + want: 7, + ok: true, + }, + { + name: "empty_name", + input: "", + ok: false, + }, + { + name: "missing_prefix", + input: "_loop.json", + ok: false, + }, + { + name: "non_numeric_prefix", + input: "loop.json", + ok: false, + }, + { + name: "mixed_prefix", + input: "1a_loop.json", + ok: false, + }, + { + name: "negative_prefix", + input: "-1_loop.json", + ok: false, + }, + { + name: "plus_prefix", + input: "+1_loop.json", + ok: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + value, ok := parseSessionCounter(test.input) + require.Equal(t, test.ok, ok) + if test.ok { + require.Equal(t, test.want, value) + } + }) + } +} From 65f27183b94477e5bcceeaacebf9d3b0757d0b4f Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 00:54:32 -0500 Subject: [PATCH 09/15] cmd/loop: add session replay tests --- cmd/loop/session_replay_test.go | 1120 +++++++++++++++++++++++++++++++ go.mod | 1 + 2 files changed, 1121 insertions(+) create mode 100644 cmd/loop/session_replay_test.go diff --git a/cmd/loop/session_replay_test.go b/cmd/loop/session_replay_test.go new file mode 100644 index 000000000..e5a01d5ce --- /dev/null +++ b/cmd/loop/session_replay_test.go @@ -0,0 +1,1120 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path" + "reflect" + "regexp" + "runtime" + "strings" + "sync" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/lightningnetwork/lnd/clock" + "github.com/stretchr/testify/require" + "github.com/urfave/cli/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" +) + +// sessionsFS exposes the recorded session fixtures for replay tests. +var sessionsFS = func() fs.FS { + // Locate this file to anchor the testdata path. + _, filename, _, ok := runtime.Caller(0) + if !ok { + return emptyFS{} + } + + // Derive the cmd/loop directory containing this file. + loopDir := path.Dir(filename) + + // Build a filesystem rooted at the cmd/loop directory. + cmdLoopFS := os.DirFS(loopDir) + + // Restrict the filesystem to the session fixture directory. + sub, err := fs.Sub(cmdLoopFS, "testdata/sessions") + if err != nil { + return emptyFS{} + } + + return sub +}() + +// emptyFS is a filesystem that always reports no such file. +type emptyFS struct{} + +// Open implements fs.FS by always returning a missing file error. +func (emptyFS) Open(string) (fs.File, error) { + return nil, fs.ErrNotExist +} + +// recordedSession holds the captured data required for a replay. +type recordedSession struct { + args []string + env map[string]string + stdin string + stdout string + stderr string + runError *string + conn *recordedClientConn +} + +// loadRecordedSessionFS loads a session from an fs.FS. +func loadRecordedSessionFS(fsys fs.FS, path string) (*recordedSession, error) { + // Read the JSON file from the provided filesystem. + blob, err := fs.ReadFile(fsys, path) + if err != nil { + return nil, err + } + + // Parse the recorded JSON into a replay struct. + return parseRecordedSession(blob) +} + +// parseRecordedSession decodes a session JSON blob into replay data. +func parseRecordedSession(blob []byte) (*recordedSession, error) { + // Decode the JSON file into the sessionFile struct. + var data sessionFile + if err := json.Unmarshal(blob, &data); err != nil { + return nil, err + } + + // Build a gRPC replay connection from recorded events. + conn, err := newRecordedClientConn(data.Events) + if err != nil { + return nil, err + } + + // Build buffers for replay IO streams. + var ( + stdoutBuilder strings.Builder + stderrBuilder strings.Builder + stdinBuilder strings.Builder + ) + + // Collect stdin/stdout/stderr payloads into buffers. + for _, event := range data.Events { + switch event.Kind { + case eventStdout: + var payload textPayload + err := json.Unmarshal(event.Data, &payload) + if err != nil { + return nil, err + } + stdoutBuilder.WriteString(payload.Text) + + case eventStderr: + var payload textPayload + err := json.Unmarshal(event.Data, &payload) + if err != nil { + return nil, err + } + stderrBuilder.WriteString(payload.Text) + + case eventStdin: + var payload stdinPayload + err := json.Unmarshal(event.Data, &payload) + if err != nil { + return nil, err + } + stdinBuilder.WriteString(payload.Text) + } + } + + // Initialize the replay payload with metadata. + return &recordedSession{ + args: append([]string(nil), data.Metadata.Args...), + env: data.Metadata.Env, + runError: data.Metadata.RunError, + conn: conn, + stdin: stdinBuilder.String(), + stdout: stdoutBuilder.String(), + stderr: stderrBuilder.String(), + }, nil +} + +// applyEnv sets environment variables and returns a restore function. +func applyEnv(values map[string]string) func() { + // No environment changes are needed. + if len(values) == 0 { + return func() {} + } + + // Track previous values for restoration. + type previous struct { + value string + set bool + } + + // Capture existing environment and apply recorded values. + prev := make(map[string]previous, len(values)) + for k, v := range values { + curr, set := os.LookupEnv(k) + prev[k] = previous{value: curr, set: set} + _ = os.Setenv(k, v) + } + + // Restore the original environment when done. + return func() { + for k, p := range prev { + if p.set { + _ = os.Setenv(k, p.value) + } else { + _ = os.Unsetenv(k) + } + } + } +} + +// protoMarshal encodes protobufs in a stable JSON form for comparisons. +var protoMarshal = protojson.MarshalOptions{ + UseProtoNames: true, + EmitUnpopulated: true, +} + +// protoUnmarshal decodes protobuf JSON while ignoring unknown fields. +var protoUnmarshal = protojson.UnmarshalOptions{ + DiscardUnknown: true, +} + +// replayTransport provides a recorded gRPC connection for session replays. +type replayTransport struct { + conn *recordedClientConn +} + +// Dial returns the recorded gRPC connection for replay. +func (t *replayTransport) Dial(cmd *cli.Command) (daemonConn, func(), error) { + // Ignore the command; replays always use the recorded connection. + return t.conn, func() {}, nil +} + +// UnaryInterceptor returns nil because replay uses a recorded connection. +func (t *replayTransport) UnaryInterceptor() grpc.UnaryClientInterceptor { + // No wrapping is needed for the recorded connection. + return nil +} + +// StreamInterceptor returns nil because replay uses a recorded connection. +func (t *replayTransport) StreamInterceptor() grpc.StreamClientInterceptor { + // No wrapping is needed for the recorded connection. + return nil +} + +// recordedClientConn replays gRPC events captured during a session run. +type recordedClientConn struct { + events []grpcPayload + idx int + mu sync.Mutex +} + +// GetState reports the connection as shut down for replay. +func (c *recordedClientConn) GetState() connectivity.State { + return connectivity.Shutdown +} + +// WaitForStateChange returns immediately because replay is static. +func (c *recordedClientConn) WaitForStateChange(ctx context.Context, + state connectivity.State) bool { + + return true +} + +// Connect is a no-op for the replay connection. +func (c *recordedClientConn) Connect() {} + +// newRecordedClientConn builds a replay connection from session events. +func newRecordedClientConn(events []sessionEvent) (*recordedClientConn, error) { + var payloads []grpcPayload + for _, event := range events { + if event.Kind != eventGrpc { + continue + } + + var payload grpcPayload + if err := json.Unmarshal(event.Data, &payload); err != nil { + return nil, err + } + payloads = append(payloads, payload) + } + + return &recordedClientConn{events: payloads}, nil +} + +// Invoke replays unary gRPC calls by consuming recorded events. +func (c *recordedClientConn) Invoke(ctx context.Context, method string, + args interface{}, reply interface{}, opts ...grpc.CallOption) error { + + // Guard concurrent access to the event stream. + c.mu.Lock() + defer c.mu.Unlock() + + // Validate the recorded request against the actual request. + req, reqIdx, err := c.consumeLocked(method, "request") + if err != nil { + return err + } + + err = compareMessageWithContext( + method, req.Event, reqIdx, args, req.Payload, + ) + if err != nil { + return err + } + + // Fetch the recorded response or error. + resp, respIdx, err := c.consumeLocked(method, "response", "error") + if err != nil { + return err + } + + // Translate recorded errors into returned errors. + if resp.Event == "error" { + if resp.Error == io.EOF.Error() { + return io.EOF + } + + return errors.New(resp.Error) + } + + // Decode protobuf responses when the reply is a proto message. + if replyMsg, ok := reply.(proto.Message); ok { + if resp.MessageType != "" { + got := string(proto.MessageName(replyMsg)) + if got != resp.MessageType { + return fmt.Errorf("grpc %s response[%d] type "+ + "mismatch: got %s want %s", method, + respIdx, got, resp.MessageType) + } + } + + if len(resp.Payload) > 0 { + err := protoUnmarshal.Unmarshal(resp.Payload, replyMsg) + if err != nil { + return fmt.Errorf("grpc %s response[%d] "+ + "unmarshal: %w", method, respIdx, err) + } + } + + return nil + } + + // Decode JSON responses when the reply is not a proto message. + if len(resp.Payload) > 0 { + if err := json.Unmarshal(resp.Payload, reply); err != nil { + return fmt.Errorf("grpc %s response[%d] unmarshal: "+ + "%w", method, respIdx, err) + } + } + + return nil +} + +// NewStream creates a replay stream backed by recorded events. +func (c *recordedClientConn) NewStream(ctx context.Context, + desc *grpc.StreamDesc, method string, + opts ...grpc.CallOption) (grpc.ClientStream, error) { + + // Create a stream wrapper that consumes events as needed. + return &replayStream{ + conn: c, + method: method, + ctx: ctx, + }, nil +} + +// replayStream is a stream implementation backed by recorded events. +type replayStream struct { + conn *recordedClientConn + method string + ctx context.Context +} + +// Header returns empty metadata for replay. +func (s *replayStream) Header() (metadata.MD, error) { + return nil, nil +} + +// Trailer returns empty metadata for replay. +func (s *replayStream) Trailer() metadata.MD { + return nil +} + +// CloseSend is a no-op for replay streams. +func (s *replayStream) CloseSend() error { + return nil +} + +// Context returns the stream context. +func (s *replayStream) Context() context.Context { + return s.ctx +} + +// SendMsg validates an outgoing stream message against recorded events. +func (s *replayStream) SendMsg(m interface{}) error { + // Protect the event stream with the shared mutex. + s.conn.mu.Lock() + defer s.conn.mu.Unlock() + + // Consume and compare the next recorded send event. + evt, evtIdx, err := s.conn.consumeLocked(s.method, "send") + if err != nil { + return err + } + + return compareMessageWithContext( + s.method, evt.Event, evtIdx, m, evt.Payload, + ) +} + +// RecvMsg replays the next recorded stream response. +func (s *replayStream) RecvMsg(m interface{}) error { + // Protect the event stream with the shared mutex. + s.conn.mu.Lock() + defer s.conn.mu.Unlock() + + // Consume the next recorded receive event. + evt, evtIdx, err := s.conn.consumeLocked(s.method, "recv", "error") + if err != nil { + return err + } + + // Translate a recorded error into a return value. + if evt.Event == "error" { + if evt.Error == io.EOF.Error() { + return io.EOF + } + + return errors.New(evt.Error) + } + + // Decode protobuf payloads into the provided message. + if msg, ok := m.(proto.Message); ok { + if evt.MessageType != "" { + got := string(proto.MessageName(msg)) + if got != evt.MessageType { + return fmt.Errorf("grpc %s recv[%d] type "+ + "mismatch: got %s want %s", s.method, + evtIdx, got, evt.MessageType) + } + } + + err := protoUnmarshal.Unmarshal(evt.Payload, msg) + if err != nil { + return fmt.Errorf("grpc %s recv[%d] unmarshal: %w", + s.method, evtIdx, err) + } + + return nil + } + + // Decode JSON payloads into non-protobuf messages. + if len(evt.Payload) > 0 { + if err := json.Unmarshal(evt.Payload, m); err != nil { + return fmt.Errorf("grpc %s recv[%d] unmarshal: %w", + s.method, evtIdx, err) + } + } + + return nil +} + +// consumeLocked fetches the next matching event. +// The caller must hold c.mu. +func (c *recordedClientConn) consumeLocked(method, expected string, + alternatives ...string) (*grpcPayload, int, error) { + + // Ensure there is another event to consume. + if c.idx >= len(c.events) { + return nil, c.idx, fmt.Errorf("grpc %s event[%d] missing, "+ + "expected %s", method, c.idx, expected) + } + + // Fetch the next event and advance the cursor. + idx := c.idx + evt := c.events[c.idx] + c.idx++ + + // Verify the method matches. + if evt.Method != method { + return nil, idx, fmt.Errorf("grpc event[%d] unexpected "+ + "method %s, want %s", idx, evt.Method, method) + } + + // Accept the expected event or a documented alternative. + if evt.Event == expected || contains(alternatives, evt.Event) { + return &evt, idx, nil + } + + return nil, idx, fmt.Errorf("grpc %s event[%d] unexpected event %s, "+ + "expected %s", method, idx, evt.Event, expected) +} + +// compareMessageWithContext marshals and compares a message against recorded +// JSON. +func compareMessageWithContext(method, event string, idx int, msg interface{}, + raw json.RawMessage) error { + + // Nothing to compare if there is no recorded payload. + if len(raw) == 0 { + return nil + } + + // Marshal the actual message to JSON and compare. + switch typed := msg.(type) { + case proto.Message: + actual, err := protoMarshal.Marshal(typed) + if err != nil { + return err + } + + return compareJSONWithContext(method, event, idx, actual, raw) + + default: + actual, err := json.Marshal(typed) + if err != nil { + return err + } + + return compareJSONWithContext(method, event, idx, actual, raw) + } +} + +// compareJSONWithContext compares two JSON-encoded payloads with context. +func compareJSONWithContext(method, event string, idx int, actual []byte, + recorded json.RawMessage) error { + + // Decode the actual and recorded payloads to generic maps. + var ( + actualValue interface{} + recordedValue interface{} + ) + + if err := json.Unmarshal(actual, &actualValue); err != nil { + return fmt.Errorf("grpc %s %s[%d] unmarshal actual: %w", + method, event, idx, err) + } + if err := json.Unmarshal(recorded, &recordedValue); err != nil { + return fmt.Errorf("grpc %s %s[%d] unmarshal recorded: %w", + method, event, idx, err) + } + + // Compare the decoded payloads and report any diff. + if diff := cmp.Diff(recordedValue, actualValue); diff != "" { + return fmt.Errorf("grpc %s %s[%d] mismatch (-want +got):\n%s", + method, event, idx, diff) + } + + return nil +} + +// contains returns true when v is in the slice. +func contains(values []string, v string) bool { + for _, value := range values { + if value == v { + return true + } + } + + return false +} + +// TestRecordedSessions replays all recorded sessions and compares output. +func TestRecordedSessions(t *testing.T) { + // Skip the test entirely when there is no session directory. + if _, err := fs.ReadDir(sessionsFS, "."); err != nil { + if errors.Is(err, fs.ErrNotExist) { + t.Skip("no recorded sessions present") + } + require.NoError(t, err) + } + + // Collect all session JSON files. + var sessionFiles []string + walkErr := fs.WalkDir(sessionsFS, ".", + func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + if strings.HasSuffix(d.Name(), sessionFileExt) { + sessionFiles = append(sessionFiles, path) + } + + return nil + }) + require.NoError(t, walkErr) + if len(sessionFiles) == 0 { + t.Skip("no recorded sessions present") + } + + for _, path := range sessionFiles { + t.Run(path, func(t *testing.T) { + // Force deterministic JSON output for replay. + prevDeterministic := forceDeterministicJSON + forceDeterministicJSON = true + defer func() { + forceDeterministicJSON = prevDeterministic + }() + + // Load the recorded session fixture. + replay, err := loadRecordedSessionFS(sessionsFS, path) + require.NoErrorf(t, err, "load session %s", path) + + // Capture replay output for comparison. + var ( + stdoutBuf bytes.Buffer + stderrBuf bytes.Buffer + ) + + // Hook stdout for capture. + stdoutUnhook, err := hookStdout( + os.Stdout, nil, func(p []byte) { + stdoutBuf.Write(p) + }, + ) + require.NoErrorf(t, err, "hook stdout for %s", path) + + // Hook stderr for capture. + stderrUnhook, err := hookStderr( + os.Stderr, nil, func(p []byte) { + stderrBuf.Write(p) + }, + ) + require.NoErrorf(t, err, "hook stderr for %s", path) + + // Hook stdin to feed the recorded input. + stdinUnhook, err := hookStdin( + os.Stdin, bytes.NewBufferString(replay.stdin), + nil, + ) + require.NoErrorf(t, err, "hook stdin for %s", path) + + // Install the replay gRPC transport. + restoreTransport := hookGrpc( + &replayTransport{conn: replay.conn}, + ) + defer restoreTransport() + + // Apply the recorded environment variables. + restoreEnv := applyEnv(replay.env) + defer restoreEnv() + + // Use a fixed clock during replay. + restoreClock := hookClock( + clock.NewTestClock( + time.Unix(sessionClockStartUnix, 0), + ), + ) + defer restoreClock() + + // Ensure the session recorder is disabled during + // replay runs. + sessionRec = nil + + // Run the CLI command with a fresh root. + cmd := newRootCommandForReplay() + + err = cmd.Run(t.Context(), replay.args) + if err != nil { + fmt.Fprintf(os.Stderr, "[loop] %v\n", err) + } + + // Restore IO hooks before checking output. + require.NoErrorf( + t, stdoutUnhook(), "unhook stdout for %s", path, + ) + require.NoErrorf( + t, stderrUnhook(), "unhook stderr for %s", path, + ) + require.NoErrorf( + t, stdinUnhook(), "unhook stdin for %s", path, + ) + + // Validate the recorded error status matches the + // replay result. + if replay.runError != nil { + require.Error(t, err, "expected run error") + + require.Equalf( + t, *replay.runError, err.Error(), + "run error mismatch for %s", path, + ) + } else { + require.NoErrorf( + t, err, "command failed for %s", path, + ) + } + + // Compare captured output to the recorded streams. + requireTextEqual( + t, "stdout", replay.stdout, stdoutBuf.String(), + ) + requireTextEqual( + t, "stderr", replay.stderr, stderrBuf.String(), + ) + }) + } +} + +// newRootCommandForReplay returns a root command clone with fresh flag state. +func newRootCommandForReplay() *cli.Command { + // Clone the root command tree to avoid shared flag state. + return cloneCommandForReplay(newRootCommand()) +} + +// cloneCommandForReplay deep-clones a command tree for deterministic replays. +func cloneCommandForReplay(cmd *cli.Command) *cli.Command { + // Guard against nil command trees. + if cmd == nil { + return nil + } + + // Clone the command struct and nested configuration. + cloned := cloneCommandStruct(cmd) + cloned.Flags, cloned.MutuallyExclusiveFlags = cloneFlagsWithGroups( + cmd.Flags, cmd.MutuallyExclusiveFlags, + ) + cloned.Arguments = cloneArguments(cmd.Arguments) + cloned.Commands = cloneCommands(cmd.Commands) + + return cloned +} + +// cloneCommandStruct copies exported fields of a command into a new instance. +func cloneCommandStruct(cmd *cli.Command) *cli.Command { + // Guard against nil command trees. + if cmd == nil { + return nil + } + + // Copy exported fields only to avoid deep internals. + src := reflect.ValueOf(cmd).Elem() + dst := reflect.New(src.Type()).Elem() + copyExportedFields(dst, src) + + return dst.Addr().Interface().(*cli.Command) +} + +// cloneCommands clones a list of subcommands for replay. +func cloneCommands(cmds []*cli.Command) []*cli.Command { + // Return nil to preserve the original structure. + if len(cmds) == 0 { + return nil + } + + // Clone each subcommand recursively. + cloned := make([]*cli.Command, len(cmds)) + for i, cmd := range cmds { + cloned[i] = cloneCommandForReplay(cmd) + } + + return cloned +} + +// cloneFlagsWithGroups clones flags and rebinds mutually exclusive groups. +func cloneFlagsWithGroups(flags []cli.Flag, + groups []cli.MutuallyExclusiveFlags) ([]cli.Flag, + []cli.MutuallyExclusiveFlags) { + + // Clone flags and then remap mutually exclusive groups. + clonedFlags, clonedMap := cloneFlags(flags) + clonedGroups := cloneMutuallyExclusiveFlags(groups, clonedMap) + + return clonedFlags, clonedGroups +} + +// cloneFlags creates fresh flag instances and returns a map of originals to +// clones. +func cloneFlags(flags []cli.Flag) ([]cli.Flag, map[cli.Flag]cli.Flag) { + // Return an empty map when no flags are present. + if len(flags) == 0 { + return nil, map[cli.Flag]cli.Flag{} + } + + // Clone each flag and record the mapping. + cloned := make([]cli.Flag, len(flags)) + clonedMap := make(map[cli.Flag]cli.Flag, len(flags)) + for i, flag := range flags { + if flag == nil { + continue + } + flagCopy := cloneFlag(flag) + cloned[i] = flagCopy + clonedMap[flag] = flagCopy + } + + return cloned, clonedMap +} + +// cloneMutuallyExclusiveFlags clones flag groups using the provided flag map. +func cloneMutuallyExclusiveFlags(groups []cli.MutuallyExclusiveFlags, + clonedMap map[cli.Flag]cli.Flag) []cli.MutuallyExclusiveFlags { + + // Return nil to preserve the original structure. + if len(groups) == 0 { + return nil + } + + // Clone each group and its flags. + clonedGroups := make([]cli.MutuallyExclusiveFlags, len(groups)) + for i, group := range groups { + clonedGroup := cli.MutuallyExclusiveFlags{ + Required: group.Required, + Category: group.Category, + } + + if len(group.Flags) == 0 { + clonedGroups[i] = clonedGroup + continue + } + + clonedGroup.Flags = make([][]cli.Flag, len(group.Flags)) + for j, option := range group.Flags { + if len(option) == 0 { + continue + } + + clonedOption := make([]cli.Flag, len(option)) + for k, flag := range option { + if flag == nil { + continue + } + + clone, ok := clonedMap[flag] + if !ok { + clone = cloneFlag(flag) + clonedMap[flag] = clone + } + clonedOption[k] = clone + } + clonedGroup.Flags[j] = clonedOption + } + + clonedGroups[i] = clonedGroup + } + + return clonedGroups +} + +// cloneFlag clones a single flag by copying its exported fields. +func cloneFlag(flag cli.Flag) cli.Flag { + // Preserve nil flags as-is. + if flag == nil { + return nil + } + + // Clone the concrete flag struct. + cloned, ok := cloneStructWithExportedFields(flag) + if !ok { + return flag + } + clonedFlag, ok := cloned.(cli.Flag) + if !ok { + return flag + } + + return clonedFlag +} + +// cloneArguments clones positional argument definitions. +func cloneArguments(args []cli.Argument) []cli.Argument { + // Return nil to preserve the original structure. + if len(args) == 0 { + return nil + } + + // Clone each argument. + cloned := make([]cli.Argument, len(args)) + for i, arg := range args { + cloned[i] = cloneArgument(arg) + } + + return cloned +} + +// cloneArgument clones a single argument by copying its exported fields. +func cloneArgument(arg cli.Argument) cli.Argument { + // Preserve nil arguments as-is. + if arg == nil { + return nil + } + + // Clone the concrete argument struct. + cloned, ok := cloneStructWithExportedFields(arg) + if !ok { + return arg + } + clonedArg, ok := cloned.(cli.Argument) + if !ok { + return arg + } + + return clonedArg +} + +// cloneStructWithExportedFields clones a pointer-to-struct by exported fields. +func cloneStructWithExportedFields(src interface{}) (interface{}, bool) { + // Validate the input type. + if src == nil { + return nil, false + } + + value := reflect.ValueOf(src) + if value.Kind() != reflect.Ptr || + value.Elem().Kind() != reflect.Struct { + + return nil, false + } + + // Allocate a new struct value and copy exported fields. + cloned := reflect.New(value.Elem().Type()) + copyExportedFields(cloned.Elem(), value.Elem()) + + return cloned.Interface(), true +} + +// copyExportedFields copies exported fields from src into dst. +func copyExportedFields(dst, src reflect.Value) { + // Iterate fields and copy only exported ones. + for i := 0; i < src.NumField(); i++ { + field := src.Type().Field(i) + if field.PkgPath != "" { + continue + } + + dstField := dst.Field(i) + if !dstField.CanSet() { + continue + } + + dstField.Set(cloneValue(src.Field(i))) + } +} + +// cloneValue shallow-clones slices and maps while preserving other values. +func cloneValue(value reflect.Value) reflect.Value { + // Return invalid values as-is. + if !value.IsValid() { + return value + } + + // Clone supported types while preserving value semantics. + switch value.Kind() { + case reflect.Slice: + if value.IsNil() { + return value + } + cloned := reflect.MakeSlice( + value.Type(), value.Len(), value.Len(), + ) + reflect.Copy(cloned, value) + + return cloned + + case reflect.Map: + if value.IsNil() { + return value + } + cloned := reflect.MakeMapWithSize(value.Type(), value.Len()) + for _, key := range value.MapKeys() { + cloned.SetMapIndex(key, value.MapIndex(key)) + } + + return cloned + + default: + return value + } +} + +// requireTextEqual compares text after normalizing timestamps. +func requireTextEqual(t *testing.T, label, expected, actual string) { + t.Helper() + + // Normalize timezone-dependent timestamps before comparing. + expected = normalizeTimestamps(expected) + actual = normalizeTimestamps(actual) + if diff := cmp.Diff(expected, actual); diff != "" { + t.Fatalf("%s mismatch (-want +got):\n%s", label, diff) + } +} + +// rfc3339TimestampRegex matches RFC3339 timestamps embedded in CLI output. +var rfc3339TimestampRegex = regexp.MustCompile( + `\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})`, +) + +// timeStringTimestampRegex matches time.String-style timestamps embedded in +// CLI output. +var timeStringTimestampRegex = regexp.MustCompile( + `\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [+-]\d{4} [A-Z]{2,5}`, +) + +// normalizeTimestamps rewrites embedded timestamps to UTC to avoid +// environment-dependent timezone output during session replay. +func normalizeTimestamps(text string) string { + // Normalize RFC3339 timestamps first. + rfc3339Replacer := func(ts string) string { + parsed, err := time.Parse(time.RFC3339Nano, ts) + if err != nil { + return ts + } + + return parsed.UTC().Format(time.RFC3339Nano) + } + text = rfc3339TimestampRegex.ReplaceAllStringFunc( + text, rfc3339Replacer, + ) + + // Normalize time.String timestamps next. + timeReplacer := func(ts string) string { + parsed, err := time.Parse("2006-01-02 15:04:05 -0700 MST", ts) + if err != nil { + return ts + } + + return parsed.UTC().Format("2006-01-02 15:04:05 -0700 MST") + } + + text = timeStringTimestampRegex.ReplaceAllStringFunc( + text, timeReplacer, + ) + + return text +} + +// TestCloneCommandForReplayResetsFlagState verifies cloned commands reset flag +// state. +func TestCloneCommandForReplayResetsFlagState(t *testing.T) { + // Prepare a flag that has been set. + originalFlag := &cli.StringFlag{ + Name: "alpha", + Usage: "alpha usage", + Aliases: []string{"a"}, + } + require.NoError(t, originalFlag.Set("alpha", "value")) + require.True(t, originalFlag.IsSet()) + + // Prepare a shared flag that appears in multiple command locations. + sharedFlag := &cli.BoolFlag{Name: "shared"} + require.NoError(t, sharedFlag.Set("shared", "true")) + require.True(t, sharedFlag.IsSet()) + + // Prepare a parsed argument. + originalArg := &cli.StringArg{ + Name: "arg", + UsageText: "arg usage", + Value: "default", + } + _, err := originalArg.Parse([]string{"parsed"}) + require.NoError(t, err) + require.Equal(t, "parsed", originalArg.Get()) + + // Build a command tree with flags, args, and metadata. + root := &cli.Command{ + Name: "root", + Flags: []cli.Flag{originalFlag, sharedFlag}, + MutuallyExclusiveFlags: []cli.MutuallyExclusiveFlags{ + { + Flags: [][]cli.Flag{ + {originalFlag}, + {sharedFlag}, + }, + Required: true, + Category: "cat", + }, + }, + Arguments: []cli.Argument{originalArg}, + Metadata: map[string]interface{}{ + "key": "value", + }, + Commands: []*cli.Command{ + { + Name: "sub", + Flags: []cli.Flag{sharedFlag}, + }, + }, + } + + // Clone the command tree for replay. + cloned := cloneCommandForReplay(root) + + // Validate structural equivalence. + require.NotSame(t, root, cloned) + require.Len(t, cloned.Flags, len(root.Flags)) + require.Len(t, cloned.Commands, len(root.Commands)) + require.Len( + t, cloned.MutuallyExclusiveFlags, + len(root.MutuallyExclusiveFlags), + ) + require.Len(t, cloned.Arguments, len(root.Arguments)) + + // Ensure flags are cloned and reset. + clonedAlpha := findFlagByName( + t, cloned.Flags, "alpha", + ).(*cli.StringFlag) + require.NotSame(t, originalFlag, clonedAlpha) + require.False(t, clonedAlpha.IsSet()) + require.Equal(t, originalFlag.Name, clonedAlpha.Name) + require.Equal(t, originalFlag.Usage, clonedAlpha.Usage) + require.Equal(t, originalFlag.Aliases, clonedAlpha.Aliases) + + // Ensure the clone is independent. + clonedAlpha.Aliases[0] = "b" + require.Equal(t, []string{"a"}, originalFlag.Aliases) + + // Ensure shared flags are cloned and reset. + clonedShared := findFlagByName( + t, cloned.Flags, "shared", + ).(*cli.BoolFlag) + require.NotSame(t, sharedFlag, clonedShared) + require.False(t, clonedShared.IsSet()) + + // Ensure the mutual exclusion groups reference clones. + group := cloned.MutuallyExclusiveFlags[0] + require.Same(t, clonedAlpha, group.Flags[0][0].(*cli.StringFlag)) + require.Same(t, clonedShared, group.Flags[1][0].(*cli.BoolFlag)) + + // Ensure positional arguments are cloned and reset. + clonedArg := cloned.Arguments[0].(*cli.StringArg) + require.NotSame(t, originalArg, clonedArg) + require.Equal(t, "default", clonedArg.Get()) + + // Ensure metadata maps are independent. + cloned.Metadata["key"] = "updated" + require.Equal(t, "value", root.Metadata["key"]) +} + +// findFlagByName locates a flag by name or alias. +func findFlagByName(t *testing.T, flags []cli.Flag, name string) cli.Flag { + t.Helper() + + // Scan each flag and its aliases for the name. + for _, flag := range flags { + if flag == nil { + continue + } + for _, candidate := range flag.Names() { + if candidate == name { + return flag + } + } + } + t.Fatalf("flag %q not found", name) + + return nil +} diff --git a/go.mod b/go.mod index 70b4c49ba..aa0b99384 100644 --- a/go.mod +++ b/go.mod @@ -91,6 +91,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.0.1 // indirect + github.com/google/go-cmp v0.7.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect From b2fd66cc8201eda609e0a386b2ebc50a1a379d2b Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 00:55:12 -0500 Subject: [PATCH 10/15] cmd/loop: add session recording guide --- cmd/loop/testdata/sessions/AGENTS.md | 68 ++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 cmd/loop/testdata/sessions/AGENTS.md diff --git a/cmd/loop/testdata/sessions/AGENTS.md b/cmd/loop/testdata/sessions/AGENTS.md new file mode 100644 index 000000000..8eb816182 --- /dev/null +++ b/cmd/loop/testdata/sessions/AGENTS.md @@ -0,0 +1,68 @@ +# Session Recording Notes (Loop CLI) + +## How to record sessions +- Use the local CLI binary: `/home/user/bin/loop`. +- Always include `--network regtest` **after** the main command and subcommands so it does not become part of the session filename. +- Record with `LOOP_SESSION_RECORD=true`, e.g.: + - `LOOP_SESSION_RECORD=true /home/user/bin/loop quote out --network regtest 500000` +- After recording several related commands, group the resulting JSON files into a subdir under `cmd/loop/testdata/sessions/`. + +## Control panel HTTP server (regtest helpers) +Base URL: `http://127.0.0.1:12345` +- Implementation: [httpcmd](https://github.com/starius/httpcmd/) +- Config: [control panel config](https://gist.github.com/starius/6604ffe27f51d55f4cf715b4202637dd) +- `/mine`: + - Mines a block. Returns JSON with `exit_code`, `stdout`, `stderr`, `duration`, `timed_out`. +- `/deposit`: + - Sends a deposit to the client static address. Returns JSON with a `txid` on success. + - May fail with insufficient funds unless blocks have been mined first. +- `/reservation`: + - Opens a reservation for instant out. Returns JSON with reservation details (id, amount, state, etc.). +- `/loop-log`: + - Returns loopd logs (text). Use a tail filter when inspecting. +- `/loop-server-log`: + - Returns loop server logs (text). Use a tail filter when inspecting. + - Tip: The response is JSON with a large `stdout` field; extract first, then tail: + - `curl -s http://127.0.0.1:12345/loop-server-log | jq -r '.stdout' > /tmp/loop-server-log.txt` + - `tail -n 50 /tmp/loop-server-log.txt` + +## Useful regtest flow observations +- Deposits may be unconfirmed for a few blocks; mine multiple blocks to move a deposit into `DEPOSITED`. +- After making a deposit, `loop static summary` reflects unconfirmed + confirmed values; `loop static listdeposits` lists confirmed deposits. +- Reservations should be opened (via `/reservation`) before `instantout`; list them with `loop reservations list`. +- `instantout` uses interactive selection; `ALL` then `y` works for a simple scenario: + - `printf "ALL\ny\n" | LOOP_SESSION_RECORD=true /home/user/bin/loop instantout --network regtest` + +## Coverage notes (high-level) +- Sessions were recorded for: terms, getinfo, quote in/out, listauth, fetchl402, getparams, setrule (error + success), suggestswaps (error + success), reservations list, instantout, listinstantouts, static withdraw/listwithdrawals/listswaps, listswaps, swapinfo, loop out (forced), abandon swap (help path), plus existing static-loop-in/basic-swaps. +- Some paths are intentionally skipped for now: + - `stop` (would shut down loopd; replay expects a real gRPC conn). + - Asset quote paths (`getAssetAmt`, `unmarshalFixedPoint`) require tapd/asset quotes. + - Real dialer/macaroon path handling (`extractPathArgs`, `readMacaroon`, `getClientConn`) aren’t exercised by replay. + + +## Replay stability notes +- Session replay now clones the CLI command tree per run, so flag state (`IsSet`) does not leak between sessions. +- Historical warning: earlier replays could have sticky flags across runs; if you see odd ordering-dependent failures, re-check that the replay uses the cloned command path. + +## Session coverage map +| Subdir | Commands / scenarios | +| --- | --- | +| `basic-swaps/` | `loop out` (success), `loop in` (success), `loop monitor` | +| `getinfo/` | `loop getinfo` | +| `instantout/` | `loop reservations list`, `loop instantout` (ALL + confirm), `loop instantout` (channel flag), `loop instantout` (select index), `loop instantout` (no confirmed reservations), `loop instantout` (cancel), `loop instantout` (invalid selection), `loop listinstantouts` | +| `l402/` | `loop listauth`, `loop fetchl402` | +| `liquidity/` | `loop getparams`, `loop setparams` (no flags, feepercent, conflict, many flags/categories, destaddr, account, includeallpeers; includes error cases), `loop setrule` (missing threshold, no args, incoming/outgoing/type in/out, clear), `loop suggestswaps` (error + success) | +| `loopin/` | `loop in` (invalid amount), `loop in` (external + conf_target error), `loop in` (route_hints + private error), `loop in` (external cancel + verbose, last_hop/amt flag), `loop in` (external force) | +| `loopout/` | `loop out` (forced success), `loop out` (invalid amount), `loop out` (addr + account error), `loop out` (invalid account address type), `loop out` (amt flag + channel + max routing fee + payment timeout), `loop out` (addr flag), `loop out` (positional addr), `loop out` (account + account_addr_type) | +| `misc/` | `loop terms` | +| `quote/` | `loop quote out` (success + verbose), `loop quote in` (help + verbose), `loop quote out` (help), `loop quote in` (deposit_outpoint success), `loop quote in` (positional + last_hop) | +| `static/` | `loop static withdraw` (no selection error), `loop static withdraw` (invalid utxo), `loop static withdraw` (all success), `loop static withdraw` (utxo + dest_addr success), `loop static listwithdrawals`, `loop static listswaps` | +| `static-loop-in/` | `loop static new`, `loop static` (help), `loop static listunspent` (incl alias), `loop static listdeposits`, `loop static summary`, `loop static in` (multiple args/flags cases), `loop static in` (duplicate outpoints), `loop static in` (positional low amount error), `loop static in` (positional + last_hop + payment_timeout), `loop static in` (all cancel) | +| `static-filters/` | `loop static listdeposits --filter ...` for each state (deposited/withdrawing/withdrawn/looping_in/looped_in/publish_expired_deposit/sweep_htlc_timeout/htlc_timeout_swept/wait_for_expiry_sweep/expired/failed) | +| `swaps/` | `loop listswaps` (success + conflicting filters + loop_out_only filters + loop_in_only), `loop swapinfo` (success + invalid id + id flag errors), `loop abandonswap` (help + invalid id + success) | + +## Missing / not covered yet +- `loop stop` (would terminate loopd; replay expects a live gRPC server). +- Docs generators: `loop man`, `loop markdown` (handled in a separate docs pipeline). +- Asset/tapd scenarios (explicitly out of scope for now). From 3a2f893a7a2e3c9cbf07851f7d2d015356844e76 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 00:55:52 -0500 Subject: [PATCH 11/15] testdata: add basic swap sessions --- .../sessions/basic-swaps/01_loop-out.json | 132 ++++++ .../sessions/basic-swaps/02_loop-in.json | 118 +++++ .../sessions/basic-swaps/03_loop-monitor.json | 402 ++++++++++++++++++ .../sessions/getinfo/01_loop-getinfo.json | 71 ++++ .../testdata/sessions/misc/01_loop-terms.json | 91 ++++ 5 files changed, 814 insertions(+) create mode 100644 cmd/loop/testdata/sessions/basic-swaps/01_loop-out.json create mode 100644 cmd/loop/testdata/sessions/basic-swaps/02_loop-in.json create mode 100644 cmd/loop/testdata/sessions/basic-swaps/03_loop-monitor.json create mode 100644 cmd/loop/testdata/sessions/getinfo/01_loop-getinfo.json create mode 100644 cmd/loop/testdata/sessions/misc/01_loop-terms.json diff --git a/cmd/loop/testdata/sessions/basic-swaps/01_loop-out.json b/cmd/loop/testdata/sessions/basic-swaps/01_loop-out.json new file mode 100644 index 000000000..09095b851 --- /dev/null +++ b/cmd/loop/testdata/sessions/basic-swaps/01_loop-out.json @@ -0,0 +1,132 @@ +{ + "metadata": { + "args": [ + "loop", + "out", + "--network", + "regtest", + "500000", + "--fast" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-64-g3b735173216470e023b3b72949dd82af9adbebe1 commit_hash=3b735173216470e023b3b72949dd82af9adbebe1", + "duration": 1332472129 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 9, + "external_htlc": false, + "swap_publication_deadline": "1769407086", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 22, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "response", + "message_type": "looprpc.OutQuoteResponse", + "payload": { + "swap_fee_sat": "3875", + "prepay_amt_sat": "1337", + "htlc_sweep_fee_sat": "3793", + "swap_payment_dest": "AhbcGtFvFiW2ru6gxtm66Xv9DpxBdSBXK4a7EX7jbSWd", + "cltv_delta": 0, + "conf_target": 9, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 23, + "kind": "stdout", + "data": { + "text": "Send off-chain: 500000 sat\nReceive on-chain: 492332 sat\nEstimated total fee: 7668 sat\n\nFast swap requested.\n\nCONTINUE SWAP? (y/n): " + } + }, + { + "time_ms": 1240, + "kind": "stdin", + "data": { + "text": "y\n" + } + }, + { + "time_ms": 1241, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "request", + "message_type": "looprpc.LoopOutRequest", + "payload": { + "amt": "500000", + "dest": "", + "max_swap_routing_fee": "10010", + "max_prepay_routing_fee": "36", + "max_swap_fee": "3875", + "max_prepay_amt": "1337", + "max_miner_fee": "948250", + "loop_out_channel": "0", + "outgoing_chan_set": [], + "sweep_conf_target": 9, + "htlc_confirmations": 1, + "swap_publication_deadline": "1769407086", + "label": "", + "initiator": "loop-cli", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "is_external_addr": false, + "reservation_ids": [], + "payment_timeout": 0, + "asset_info": null, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 1327, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "response", + "message_type": "looprpc.SwapResponse", + "payload": { + "id": "e5f3a1d5cee33e239571d0c1e8cbc6926cbc1d784b9fe185ff6589e949db4549", + "id_bytes": "5fOh1c7jPiOVcdDB6MvGkmy8HXhLn+GF/2WJ6UnbRUk=", + "htlc_address": "bcrt1p69ekm32epfcy8ymkqdj5clvh37vmlgw76k9x5nfs76c7qgghnpqqmtf80x", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1p69ekm32epfcy8ymkqdj5clvh37vmlgw76k9x5nfs76c7qgghnpqqmtf80x", + "server_message": "" + } + } + }, + { + "time_ms": 1329, + "kind": "stdout", + "data": { + "text": "Swap initiated\nID: e5f3a1d5cee33e239571d0c1e8cbc6926cbc1d784b9fe185ff6589e949db4549\n\nRun `loop monitor` to monitor progress.\n" + } + }, + { + "time_ms": 1332, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/basic-swaps/02_loop-in.json b/cmd/loop/testdata/sessions/basic-swaps/02_loop-in.json new file mode 100644 index 000000000..93e6a982f --- /dev/null +++ b/cmd/loop/testdata/sessions/basic-swaps/02_loop-in.json @@ -0,0 +1,118 @@ +{ + "metadata": { + "args": [ + "loop", + "in", + "--network", + "regtest", + "500000" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-69-g057ef82340ab279a5659ab6ae7edab61448a2acd commit_hash=057ef82340ab279a5659ab6ae7edab61448a2acd", + "duration": 2146386627 + }, + "events": [ + { + "time_ms": 5, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 444, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1825", + "htlc_publish_fee_sat": "3875", + "cltv_delta": 0, + "conf_target": 6, + "quoted_amt": "500000" + } + } + }, + { + "time_ms": 445, + "kind": "stdout", + "data": { + "text": "Send on-chain: 500000 sat\nReceive off-chain: 494300 sat\nEstimated total fee: 5700 sat\n\nCONTINUE SWAP? (y/n): " + } + }, + { + "time_ms": 1682, + "kind": "stdin", + "data": { + "text": "y\n" + } + }, + { + "time_ms": 1682, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopIn", + "event": "request", + "message_type": "looprpc.LoopInRequest", + "payload": { + "amt": "500000", + "max_swap_fee": "1825", + "max_miner_fee": "11625", + "last_hop": "", + "external_htlc": false, + "htlc_conf_target": 0, + "label": "", + "initiator": "loop-cli", + "route_hints": [], + "private": false + } + } + }, + { + "time_ms": 2140, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopIn", + "event": "response", + "message_type": "looprpc.SwapResponse", + "payload": { + "id": "33b431ce62ab7f8f3ff5e2aee9452ec9aa18713e734ecd79fc9cfb4bd77cc7d8", + "id_bytes": "M7QxzmKrf48/9eKu6UUuyaoYcT5zTs15/Jz7S9d8x9g=", + "htlc_address": "bcrt1pmtw7fch8de39wxfqunuucudgulkvyxm59epz9p0ph673squ7l2ns3gpcsu", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1pmtw7fch8de39wxfqunuucudgulkvyxm59epz9p0ph673squ7l2ns3gpcsu", + "server_message": "" + } + } + }, + { + "time_ms": 2141, + "kind": "stdout", + "data": { + "text": "Swap initiated\nID: 33b431ce62ab7f8f3ff5e2aee9452ec9aa18713e734ecd79fc9cfb4bd77cc7d8\nHTLC address (P2TR): bcrt1pmtw7fch8de39wxfqunuucudgulkvyxm59epz9p0ph673squ7l2ns3gpcsu\n\nRun `loop monitor` to monitor progress.\n" + } + }, + { + "time_ms": 2146, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/basic-swaps/03_loop-monitor.json b/cmd/loop/testdata/sessions/basic-swaps/03_loop-monitor.json new file mode 100644 index 000000000..bd9aae085 --- /dev/null +++ b/cmd/loop/testdata/sessions/basic-swaps/03_loop-monitor.json @@ -0,0 +1,402 @@ +{ + "metadata": { + "args": [ + "loop", + "monitor", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "run_error": "recv: rpc error: code = Canceled desc = context canceled", + "duration": 58532880576 + }, + "events": [ + { + "time_ms": 8, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "send", + "message_type": "looprpc.MonitorRequest", + "payload": {} + } + }, + { + "time_ms": 8, + "kind": "stdout", + "data": { + "text": "Note: offchain cost may report as 0 after loopd restart during swap\n" + } + }, + { + "time_ms": 13, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "33b431ce62ab7f8f3ff5e2aee9452ec9aa18713e734ecd79fc9cfb4bd77cc7d8", + "id_bytes": "M7QxzmKrf48/9eKu6UUuyaoYcT5zTs15/Jz7S9d8x9g=", + "type": "LOOP_IN", + "state": "INVOICE_SETTLED", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769413263544127799", + "last_update_time": "1769413312288899857", + "htlc_address": "bcrt1pmtw7fch8de39wxfqunuucudgulkvyxm59epz9p0ph673squ7l2ns3gpcsu", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1pmtw7fch8de39wxfqunuucudgulkvyxm59epz9p0ph673squ7l2ns3gpcsu", + "cost_server": "0", + "cost_onchain": "3850", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 13, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "4a8f1dd97addf8222c7613f6a41e3942f4bf9ca64026107c484c1f7e551df658", + "id_bytes": "So8d2Xrd+CIsdhP2pB45QvS/nKZAJhB8SEwfflUd9lg=", + "type": "LOOP_OUT", + "state": "SUCCESS", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769407041704702192", + "last_update_time": "1769413318432807159", + "htlc_address": "bcrt1pmvvj28wnuwe70xfy6kjzwxcg7cx0kc2dy8l6armutegs8y3p0j7qg0atua", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1pmvvj28wnuwe70xfy6kjzwxcg7cx0kc2dy8l6armutegs8y3p0j7qg0atua", + "cost_server": "3875", + "cost_onchain": "2775", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 14, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "e5f3a1d5cee33e239571d0c1e8cbc6926cbc1d784b9fe185ff6589e949db4549", + "id_bytes": "5fOh1c7jPiOVcdDB6MvGkmy8HXhLn+GF/2WJ6UnbRUk=", + "type": "LOOP_OUT", + "state": "SUCCESS", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769407087874686997", + "last_update_time": "1769413322775449292", + "htlc_address": "bcrt1p69ekm32epfcy8ymkqdj5clvh37vmlgw76k9x5nfs76c7qgghnpqqmtf80x", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1p69ekm32epfcy8ymkqdj5clvh37vmlgw76k9x5nfs76c7qgghnpqqmtf80x", + "cost_server": "3875", + "cost_onchain": "2775", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 14, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "39424d7e6cf6d9c613c4026f5e6da48fd2b65989007895a0db7b937b7f8563e4", + "id_bytes": "OUJNfmz22cYTxAJvXm2kj9K2WYkAeJWg23uTe3+FY+Q=", + "type": "LOOP_OUT", + "state": "SUCCESS", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769413204269210604", + "last_update_time": "1769413329442159169", + "htlc_address": "bcrt1prz80rm04fhf5y73ps9txxslnhj8e3nqcsnmz6ca6vs6jkrce2l9svtd8sl", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1prz80rm04fhf5y73ps9txxslnhj8e3nqcsnmz6ca6vs6jkrce2l9svtd8sl", + "cost_server": "3875", + "cost_onchain": "2774", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 14, + "kind": "stdout", + "data": { + "text": "2026-01-26T02:41:52-05:00 LOOP_IN INVOICE_SETTLED 0.00500000 BTC - P2TR: bcrt1pmtw7fch8de39wxfqunuucudgulkvyxm59epz9p0ph673squ7l2ns3gpcsu (cost: server 0, onchain 3850, offchain 0)\n2026-01-26T02:41:58-05:00 LOOP_OUT SUCCESS 0.00500000 BTC - (cost: server 3875, onchain 2775, offchain 0)\n2026-01-26T02:42:02-05:00 LOOP_OUT SUCCESS 0.00500000 BTC - (cost: server 3875, onchain 2775, offchain 0)\n2026-01-26T02:42:09-05:00 LOOP_OUT SUCCESS 0.00500000 BTC - (cost: server 3875, onchain 2774, offchain 0)\n" + } + }, + { + "time_ms": 19978, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "13da0be986d8a1f095794f78c5e716150e93c92834e3be52f6eb2fbfc84b8eb0", + "id_bytes": "E9oL6YbYofCVeU94xecWFQ6TySg0475S9usvv8hLjrA=", + "type": "LOOP_OUT", + "state": "INITIATED", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769414430311530071", + "last_update_time": "1769414430311530071", + "htlc_address": "bcrt1ps8vvwey05ezrmhe4mpz60nre256ggl2uyazs7fayh83z7ptnclnstaxvu2", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1ps8vvwey05ezrmhe4mpz60nre256ggl2uyazs7fayh83z7ptnclnstaxvu2", + "cost_server": "0", + "cost_onchain": "0", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 19978, + "kind": "stdout", + "data": { + "text": "2026-01-26T03:00:30-05:00 LOOP_OUT INITIATED 0.00500000 BTC - \n" + } + }, + { + "time_ms": 32802, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "3f4ec343ba4087eec3cdf501b4e19733d9685cc151db360bb67d2c924677ce71", + "id_bytes": "P07DQ7pAh+7DzfUBtOGXM9loXMFR2zYLtn0skkZ3znE=", + "type": "LOOP_IN", + "state": "INITIATED", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769414443188873986", + "last_update_time": "1769414443188873986", + "htlc_address": "bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch", + "cost_server": "0", + "cost_onchain": "0", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 32802, + "kind": "stdout", + "data": { + "text": "2026-01-26T03:00:43-05:00 LOOP_IN INITIATED 0.00500000 BTC - P2TR: bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch\n" + } + }, + { + "time_ms": 32829, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "3f4ec343ba4087eec3cdf501b4e19733d9685cc151db360bb67d2c924677ce71", + "id_bytes": "P07DQ7pAh+7DzfUBtOGXM9loXMFR2zYLtn0skkZ3znE=", + "type": "LOOP_IN", + "state": "HTLC_PUBLISHED", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769414443188873986", + "last_update_time": "1769414443212089572", + "htlc_address": "bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch", + "cost_server": "0", + "cost_onchain": "0", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 32829, + "kind": "stdout", + "data": { + "text": "2026-01-26T03:00:43-05:00 LOOP_IN HTLC_PUBLISHED 0.00500000 BTC - P2TR: bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch\n" + } + }, + { + "time_ms": 39513, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "3f4ec343ba4087eec3cdf501b4e19733d9685cc151db360bb67d2c924677ce71", + "id_bytes": "P07DQ7pAh+7DzfUBtOGXM9loXMFR2zYLtn0skkZ3znE=", + "type": "LOOP_IN", + "state": "INVOICE_SETTLED", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769414443188873986", + "last_update_time": "1769414449902523194", + "htlc_address": "bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch", + "cost_server": "0", + "cost_onchain": "3850", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 39513, + "kind": "stdout", + "data": { + "text": "2026-01-26T03:00:49-05:00 LOOP_IN INVOICE_SETTLED 0.00500000 BTC - P2TR: bcrt1ppuw9wtl65avd026t9nkxux8whz3gyhkjh6n9cryp8a5xz9jacf9qlgxsch (cost: server 0, onchain 3850, offchain 0)\n" + } + }, + { + "time_ms": 40341, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "13da0be986d8a1f095794f78c5e716150e93c92834e3be52f6eb2fbfc84b8eb0", + "id_bytes": "E9oL6YbYofCVeU94xecWFQ6TySg0475S9usvv8hLjrA=", + "type": "LOOP_OUT", + "state": "PREIMAGE_REVEALED", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769414430311530071", + "last_update_time": "1769414450735780318", + "htlc_address": "bcrt1ps8vvwey05ezrmhe4mpz60nre256ggl2uyazs7fayh83z7ptnclnstaxvu2", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1ps8vvwey05ezrmhe4mpz60nre256ggl2uyazs7fayh83z7ptnclnstaxvu2", + "cost_server": "0", + "cost_onchain": "0", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 40341, + "kind": "stdout", + "data": { + "text": "2026-01-26T03:00:50-05:00 LOOP_OUT PREIMAGE_REVEALED 0.00500000 BTC - \n" + } + }, + { + "time_ms": 44110, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "recv", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "13da0be986d8a1f095794f78c5e716150e93c92834e3be52f6eb2fbfc84b8eb0", + "id_bytes": "E9oL6YbYofCVeU94xecWFQ6TySg0475S9usvv8hLjrA=", + "type": "LOOP_OUT", + "state": "SUCCESS", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1769414430311530071", + "last_update_time": "1769414454503356191", + "htlc_address": "bcrt1ps8vvwey05ezrmhe4mpz60nre256ggl2uyazs7fayh83z7ptnclnstaxvu2", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1ps8vvwey05ezrmhe4mpz60nre256ggl2uyazs7fayh83z7ptnclnstaxvu2", + "cost_server": "3873", + "cost_onchain": "2774", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 44110, + "kind": "stdout", + "data": { + "text": "2026-01-26T03:00:54-05:00 LOOP_OUT SUCCESS 0.00500000 BTC - (cost: server 3873, onchain 2774, offchain 0)\n" + } + }, + { + "time_ms": 58531, + "kind": "signal", + "data": { + "signal": "interrupt" + } + }, + { + "time_ms": 58531, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/Monitor", + "event": "error", + "error": "rpc error: code = Canceled desc = context canceled" + } + }, + { + "time_ms": 58532, + "kind": "stderr", + "data": { + "text": "[loop] recv: rpc error: code = Canceled desc = context canceled\n" + } + }, + { + "time_ms": 58532, + "kind": "exit", + "data": { + "run_error": "recv: rpc error: code = Canceled desc = context canceled" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/getinfo/01_loop-getinfo.json b/cmd/loop/testdata/sessions/getinfo/01_loop-getinfo.json new file mode 100644 index 000000000..9170993cf --- /dev/null +++ b/cmd/loop/testdata/sessions/getinfo/01_loop-getinfo.json @@ -0,0 +1,71 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "getinfo", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 200590737 + }, + "events": [ + { + "time_ms": 4, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetInfo", + "event": "request", + "message_type": "looprpc.GetInfoRequest", + "payload": {} + } + }, + { + "time_ms": 200, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetInfo", + "event": "response", + "message_type": "looprpc.GetInfoResponse", + "payload": { + "version": "0.31.7-beta", + "network": "regtest", + "rpc_listen": "localhost:11010", + "rest_listen": "localhost:8081", + "macaroon_path": "/home/user/.loop/regtest/loop.macaroon", + "tls_cert_path": "/home/user/.loop/regtest/tls.cert", + "loop_out_stats": { + "pending_count": "0", + "success_count": "0", + "fail_count": "0", + "sum_pending_amt": "0", + "sum_succeeded_amt": "0" + }, + "loop_in_stats": { + "pending_count": "0", + "success_count": "0", + "fail_count": "0", + "sum_pending_amt": "0", + "sum_succeeded_amt": "0" + }, + "commit_hash": "579ea31979e0cdb1ee6049ab97cc2768888eac40" + } + } + }, + { + "time_ms": 200, + "kind": "stdout", + "data": { + "text": "{\n \"commit_hash\": \"579ea31979e0cdb1ee6049ab97cc2768888eac40\",\n \"loop_in_stats\": {\n \"fail_count\": \"0\",\n \"pending_count\": \"0\",\n \"success_count\": \"0\",\n \"sum_pending_amt\": \"0\",\n \"sum_succeeded_amt\": \"0\"\n },\n \"loop_out_stats\": {\n \"fail_count\": \"0\",\n \"pending_count\": \"0\",\n \"success_count\": \"0\",\n \"sum_pending_amt\": \"0\",\n \"sum_succeeded_amt\": \"0\"\n },\n \"macaroon_path\": \"/home/user/.loop/regtest/loop.macaroon\",\n \"network\": \"regtest\",\n \"rest_listen\": \"localhost:8081\",\n \"rpc_listen\": \"localhost:11010\",\n \"tls_cert_path\": \"/home/user/.loop/regtest/tls.cert\",\n \"version\": \"0.31.7-beta\"\n}\n" + } + }, + { + "time_ms": 200, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/misc/01_loop-terms.json b/cmd/loop/testdata/sessions/misc/01_loop-terms.json new file mode 100644 index 000000000..091bb89e5 --- /dev/null +++ b/cmd/loop/testdata/sessions/misc/01_loop-terms.json @@ -0,0 +1,91 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "terms", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 199188467 + }, + "events": [ + { + "time_ms": 7, + "kind": "stdout", + "data": { + "text": "Loop Out\n--------\n" + } + }, + { + "time_ms": 7, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutTerms", + "event": "request", + "message_type": "looprpc.TermsRequest", + "payload": {} + } + }, + { + "time_ms": 156, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutTerms", + "event": "response", + "message_type": "looprpc.OutTermsResponse", + "payload": { + "min_swap_amount": "50000", + "max_swap_amount": "1000000", + "min_cltv_delta": 50, + "max_cltv_delta": 250 + } + } + }, + { + "time_ms": 156, + "kind": "stdout", + "data": { + "text": "Amount: 50000 - 1000000\nCltv delta: 50 - 250\n\nLoop In\n------\n" + } + }, + { + "time_ms": 156, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInTerms", + "event": "request", + "message_type": "looprpc.TermsRequest", + "payload": {} + } + }, + { + "time_ms": 198, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInTerms", + "event": "response", + "message_type": "looprpc.InTermsResponse", + "payload": { + "min_swap_amount": "50000", + "max_swap_amount": "1000000" + } + } + }, + { + "time_ms": 198, + "kind": "stdout", + "data": { + "text": "Amount: 50000 - 1000000\n" + } + }, + { + "time_ms": 199, + "kind": "exit", + "data": {} + } + ] +} From 3bd9aff783533a3288aed6ee93a3e0e07cf73e9b Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 00:56:26 -0500 Subject: [PATCH 12/15] testdata: add instantout and l402 sessions --- .../instantout/01_loop-reservations-list.json | 77 ++++++++ .../instantout/02_loop-instantout.json | 167 ++++++++++++++++ .../instantout/03_loop-listinstantouts.json | 63 ++++++ .../04_loop-instantout-no-confirmed.json | 91 +++++++++ .../instantout/05_loop-instantout-cancel.json | 137 +++++++++++++ .../06_loop-instantout-invalid-selection.json | 101 ++++++++++ .../07_loop-instantout-channel.json | 185 ++++++++++++++++++ .../08_loop-instantout-select-index.json | 180 +++++++++++++++++ .../sessions/l402/01_loop-listauth.json | 63 ++++++ .../sessions/l402/02_loop-fetchl402.json | 49 +++++ 10 files changed, 1113 insertions(+) create mode 100644 cmd/loop/testdata/sessions/instantout/01_loop-reservations-list.json create mode 100644 cmd/loop/testdata/sessions/instantout/02_loop-instantout.json create mode 100644 cmd/loop/testdata/sessions/instantout/03_loop-listinstantouts.json create mode 100644 cmd/loop/testdata/sessions/instantout/04_loop-instantout-no-confirmed.json create mode 100644 cmd/loop/testdata/sessions/instantout/05_loop-instantout-cancel.json create mode 100644 cmd/loop/testdata/sessions/instantout/06_loop-instantout-invalid-selection.json create mode 100644 cmd/loop/testdata/sessions/instantout/07_loop-instantout-channel.json create mode 100644 cmd/loop/testdata/sessions/instantout/08_loop-instantout-select-index.json create mode 100644 cmd/loop/testdata/sessions/l402/01_loop-listauth.json create mode 100644 cmd/loop/testdata/sessions/l402/02_loop-fetchl402.json diff --git a/cmd/loop/testdata/sessions/instantout/01_loop-reservations-list.json b/cmd/loop/testdata/sessions/instantout/01_loop-reservations-list.json new file mode 100644 index 000000000..e4b8d3031 --- /dev/null +++ b/cmd/loop/testdata/sessions/instantout/01_loop-reservations-list.json @@ -0,0 +1,77 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "reservations", + "list", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 177945855 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "request", + "message_type": "looprpc.ListReservationsRequest", + "payload": {} + } + }, + { + "time_ms": 177, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "response", + "message_type": "looprpc.ListReservationsResponse", + "payload": { + "reservations": [ + { + "reservation_id": "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "8b3b5e235ad24be42bc3802c6694566964c394df247b4ae1f2f4fd785e5acd17", + "vout": 0, + "expiry": 1619 + }, + { + "reservation_id": "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "beb447976c6c1a93fdadee41280b912e62b305c7c30815dc172d58732b6c3836", + "vout": 0, + "expiry": 1623 + }, + { + "reservation_id": "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "5f898ca1b3852c62889f1113e07c73d0a3d721fd98d0a5433c6b7122cc706952", + "vout": 0, + "expiry": 1626 + } + ] + } + } + }, + { + "time_ms": 177, + "kind": "stdout", + "data": { + "text": "{\n \"reservations\": [\n {\n \"amount\": \"800000\",\n \"expiry\": 1619,\n \"reservation_id\": \"b3f443e8b8ff797766b450ad77fe80beb250acfd7887562b6e5c9964c5884d87\",\n \"state\": \"Confirmed\",\n \"tx_id\": \"8b3b5e235ad24be42bc3802c6694566964c394df247b4ae1f2f4fd785e5acd17\",\n \"vout\": 0\n },\n {\n \"amount\": \"800000\",\n \"expiry\": 1623,\n \"reservation_id\": \"5a5f824ec63e576cd4be42b96ecf5622db64bca2eb28cf00d64a59e5567f307b\",\n \"state\": \"Confirmed\",\n \"tx_id\": \"beb447976c6c1a93fdadee41280b912e62b305c7c30815dc172d58732b6c3836\",\n \"vout\": 0\n },\n {\n \"amount\": \"800000\",\n \"expiry\": 1626,\n \"reservation_id\": \"32eeb97db85ac84b51ce8ba028b067a1e44df1ffad10cd7e3bd42e36f5087db2\",\n \"state\": \"Confirmed\",\n \"tx_id\": \"5f898ca1b3852c62889f1113e07c73d0a3d721fd98d0a5433c6b7122cc706952\",\n \"vout\": 0\n }\n ]\n}\n" + } + }, + { + "time_ms": 177, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/instantout/02_loop-instantout.json b/cmd/loop/testdata/sessions/instantout/02_loop-instantout.json new file mode 100644 index 000000000..1047106db --- /dev/null +++ b/cmd/loop/testdata/sessions/instantout/02_loop-instantout.json @@ -0,0 +1,167 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "instantout", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 1574538838 + }, + "events": [ + { + "time_ms": 0, + "kind": "stdin", + "data": { + "text": "ALL\ny\n" + } + }, + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "request", + "message_type": "looprpc.ListReservationsRequest", + "payload": {} + } + }, + { + "time_ms": 152, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "response", + "message_type": "looprpc.ListReservationsResponse", + "payload": { + "reservations": [ + { + "reservation_id": "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "8b3b5e235ad24be42bc3802c6694566964c394df247b4ae1f2f4fd785e5acd17", + "vout": 0, + "expiry": 1619 + }, + { + "reservation_id": "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "beb447976c6c1a93fdadee41280b912e62b305c7c30815dc172d58732b6c3836", + "vout": 0, + "expiry": 1623 + }, + { + "reservation_id": "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "5f898ca1b3852c62889f1113e07c73d0a3d721fd98d0a5433c6b7122cc706952", + "vout": 0, + "expiry": 1626 + } + ] + } + } + }, + { + "time_ms": 152, + "kind": "stdout", + "data": { + "text": "Available reservations: \n\nReservation 1: shortid b3f443, amt 800000, expiry height 1619 \nReservation 2: shortid 5a5f82, amt 800000, expiry height 1623 \nReservation 3: shortid 32eeb9, amt 800000, expiry height 1626 \n\nMax amount to instant out: 2400000\n\nSelect reservations for instantout (e.g. '1,2,3')\n" + } + }, + { + "time_ms": 152, + "kind": "stdout", + "data": { + "text": "Type 'ALL' to use all available reservations.\n" + } + }, + { + "time_ms": 152, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOutQuote", + "event": "request", + "message_type": "looprpc.InstantOutQuoteRequest", + "payload": { + "amt": "2400000", + "num_reservations": 0, + "reservation_ids": [ + "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=" + ] + } + } + }, + { + "time_ms": 177, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOutQuote", + "event": "response", + "message_type": "looprpc.InstantOutQuoteResponse", + "payload": { + "service_fee_sat": "4800", + "sweep_fee_sat": "5650" + } + } + }, + { + "time_ms": 177, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOut", + "event": "request", + "message_type": "looprpc.InstantOutRequest", + "payload": { + "reservation_ids": [ + "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=" + ], + "outgoing_chan_set": [], + "dest_addr": "" + } + } + }, + { + "time_ms": 177, + "kind": "stdout", + "data": { + "text": "\nEstimated on-chain fee: 5650 sat\nService fee: 4800 sat\n\nCONTINUE SWAP? (y/n): Starting instant swap out\n" + } + }, + { + "time_ms": 1574, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOut", + "event": "response", + "message_type": "looprpc.InstantOutResponse", + "payload": { + "instant_out_hash": "uxbiybKoHjn4B4b+yHRFGI9e12jMMtTLEvNnF7wYriU=", + "sweep_tx_id": "a1650cb339118e58f317bbbbd8cff720e0cc02a9fe159c9286724d6f5722fef2", + "state": "PushPreimage" + } + } + }, + { + "time_ms": 1574, + "kind": "stdout", + "data": { + "text": "Instant out swap initiated with ID: bb16e2c9b2a81e39f80786fec87445188f5ed768cc32d4cb12f36717bc18ae25, State: PushPreimage \nSweepless sweep tx id: a1650cb339118e58f317bbbbd8cff720e0cc02a9fe159c9286724d6f5722fef2 \n" + } + }, + { + "time_ms": 1574, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/instantout/03_loop-listinstantouts.json b/cmd/loop/testdata/sessions/instantout/03_loop-listinstantouts.json new file mode 100644 index 000000000..58333fce5 --- /dev/null +++ b/cmd/loop/testdata/sessions/instantout/03_loop-listinstantouts.json @@ -0,0 +1,63 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "listinstantouts", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 142800927 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListInstantOuts", + "event": "request", + "message_type": "looprpc.ListInstantOutsRequest", + "payload": {} + } + }, + { + "time_ms": 142, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListInstantOuts", + "event": "response", + "message_type": "looprpc.ListInstantOutsResponse", + "payload": { + "swaps": [ + { + "swap_hash": "uxbiybKoHjn4B4b+yHRFGI9e12jMMtTLEvNnF7wYriU=", + "state": "WaitForSweeplessSweepConfirmed", + "amount": "2400000", + "reservation_ids": [ + "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=" + ], + "sweep_tx_id": "a1650cb339118e58f317bbbbd8cff720e0cc02a9fe159c9286724d6f5722fef2" + } + ] + } + } + }, + { + "time_ms": 142, + "kind": "stdout", + "data": { + "text": "{\n \"swaps\": [\n {\n \"amount\": \"2400000\",\n \"reservation_ids\": [\n \"b3f443e8b8ff797766b450ad77fe80beb250acfd7887562b6e5c9964c5884d87\",\n \"5a5f824ec63e576cd4be42b96ecf5622db64bca2eb28cf00d64a59e5567f307b\",\n \"32eeb97db85ac84b51ce8ba028b067a1e44df1ffad10cd7e3bd42e36f5087db2\"\n ],\n \"state\": \"WaitForSweeplessSweepConfirmed\",\n \"swap_hash\": \"bb16e2c9b2a81e39f80786fec87445188f5ed768cc32d4cb12f36717bc18ae25\",\n \"sweep_tx_id\": \"a1650cb339118e58f317bbbbd8cff720e0cc02a9fe159c9286724d6f5722fef2\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 142, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/instantout/04_loop-instantout-no-confirmed.json b/cmd/loop/testdata/sessions/instantout/04_loop-instantout-no-confirmed.json new file mode 100644 index 000000000..3f0a5b036 --- /dev/null +++ b/cmd/loop/testdata/sessions/instantout/04_loop-instantout-no-confirmed.json @@ -0,0 +1,91 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "instantout", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 271911644 + }, + "events": [ + { + "time_ms": 2, + "kind": "stdin", + "data": { + "text": "ALL\nn\n" + } + }, + { + "time_ms": 9, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "request", + "message_type": "looprpc.ListReservationsRequest", + "payload": {} + } + }, + { + "time_ms": 270, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "response", + "message_type": "looprpc.ListReservationsResponse", + "payload": { + "reservations": [ + { + "reservation_id": "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "state": "Spent", + "amount": "800000", + "tx_id": "8b3b5e235ad24be42bc3802c6694566964c394df247b4ae1f2f4fd785e5acd17", + "vout": 0, + "expiry": 1619 + }, + { + "reservation_id": "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "state": "Spent", + "amount": "800000", + "tx_id": "beb447976c6c1a93fdadee41280b912e62b305c7c30815dc172d58732b6c3836", + "vout": 0, + "expiry": 1623 + }, + { + "reservation_id": "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=", + "state": "Spent", + "amount": "800000", + "tx_id": "5f898ca1b3852c62889f1113e07c73d0a3d721fd98d0a5433c6b7122cc706952", + "vout": 0, + "expiry": 1626 + }, + { + "reservation_id": "/AslVrUe/D6Eum+CZsg1x+EalEVACi6ICfc8rVURH3U=", + "state": "WaitForConfirmation", + "amount": "800000", + "tx_id": "", + "vout": 0, + "expiry": 1632 + } + ] + } + } + }, + { + "time_ms": 271, + "kind": "stdout", + "data": { + "text": "No confirmed reservations found \n" + } + }, + { + "time_ms": 271, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/instantout/05_loop-instantout-cancel.json b/cmd/loop/testdata/sessions/instantout/05_loop-instantout-cancel.json new file mode 100644 index 000000000..8529d0a6e --- /dev/null +++ b/cmd/loop/testdata/sessions/instantout/05_loop-instantout-cancel.json @@ -0,0 +1,137 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "instantout", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "swap canceled", + "duration": 229272887 + }, + "events": [ + { + "time_ms": 1, + "kind": "stdin", + "data": { + "text": "ALL\nn\n" + } + }, + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "request", + "message_type": "looprpc.ListReservationsRequest", + "payload": {} + } + }, + { + "time_ms": 188, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "response", + "message_type": "looprpc.ListReservationsResponse", + "payload": { + "reservations": [ + { + "reservation_id": "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "state": "Spent", + "amount": "800000", + "tx_id": "8b3b5e235ad24be42bc3802c6694566964c394df247b4ae1f2f4fd785e5acd17", + "vout": 0, + "expiry": 1619 + }, + { + "reservation_id": "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "state": "Spent", + "amount": "800000", + "tx_id": "beb447976c6c1a93fdadee41280b912e62b305c7c30815dc172d58732b6c3836", + "vout": 0, + "expiry": 1623 + }, + { + "reservation_id": "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=", + "state": "Spent", + "amount": "800000", + "tx_id": "5f898ca1b3852c62889f1113e07c73d0a3d721fd98d0a5433c6b7122cc706952", + "vout": 0, + "expiry": 1626 + }, + { + "reservation_id": "/AslVrUe/D6Eum+CZsg1x+EalEVACi6ICfc8rVURH3U=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "322d031e9ab55e0bcdac421c57d2d5d7705b80d01d3217a672aa1bf73edfc963", + "vout": 0, + "expiry": 1632 + } + ] + } + } + }, + { + "time_ms": 188, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOutQuote", + "event": "request", + "message_type": "looprpc.InstantOutQuoteRequest", + "payload": { + "amt": "800000", + "num_reservations": 0, + "reservation_ids": [ + "/AslVrUe/D6Eum+CZsg1x+EalEVACi6ICfc8rVURH3U=" + ] + } + } + }, + { + "time_ms": 188, + "kind": "stdout", + "data": { + "text": "Available reservations: \n\nReservation 1: shortid fc0b25, amt 800000, expiry height 1632 \n\nMax amount to instant out: 800000\n\nSelect reservations for instantout (e.g. '1,2,3')\nType 'ALL' to use all available reservations.\n" + } + }, + { + "time_ms": 228, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOutQuote", + "event": "response", + "message_type": "looprpc.InstantOutQuoteResponse", + "payload": { + "service_fee_sat": "1600", + "sweep_fee_sat": "2773" + } + } + }, + { + "time_ms": 228, + "kind": "stdout", + "data": { + "text": "\nEstimated on-chain fee: 2773 sat\nService fee: 1600 sat\n\nCONTINUE SWAP? (y/n): " + } + }, + { + "time_ms": 229, + "kind": "stderr", + "data": { + "text": "[loop] swap canceled\n" + } + }, + { + "time_ms": 229, + "kind": "exit", + "data": { + "run_error": "swap canceled" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/instantout/06_loop-instantout-invalid-selection.json b/cmd/loop/testdata/sessions/instantout/06_loop-instantout-invalid-selection.json new file mode 100644 index 000000000..81467d0a6 --- /dev/null +++ b/cmd/loop/testdata/sessions/instantout/06_loop-instantout-invalid-selection.json @@ -0,0 +1,101 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "instantout", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "invalid index 99", + "duration": 203873152 + }, + "events": [ + { + "time_ms": 0, + "kind": "stdin", + "data": { + "text": "99\n" + } + }, + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "request", + "message_type": "looprpc.ListReservationsRequest", + "payload": {} + } + }, + { + "time_ms": 202, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "response", + "message_type": "looprpc.ListReservationsResponse", + "payload": { + "reservations": [ + { + "reservation_id": "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "state": "Spent", + "amount": "800000", + "tx_id": "8b3b5e235ad24be42bc3802c6694566964c394df247b4ae1f2f4fd785e5acd17", + "vout": 0, + "expiry": 1619 + }, + { + "reservation_id": "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "state": "Spent", + "amount": "800000", + "tx_id": "beb447976c6c1a93fdadee41280b912e62b305c7c30815dc172d58732b6c3836", + "vout": 0, + "expiry": 1623 + }, + { + "reservation_id": "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=", + "state": "Spent", + "amount": "800000", + "tx_id": "5f898ca1b3852c62889f1113e07c73d0a3d721fd98d0a5433c6b7122cc706952", + "vout": 0, + "expiry": 1626 + }, + { + "reservation_id": "/AslVrUe/D6Eum+CZsg1x+EalEVACi6ICfc8rVURH3U=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "322d031e9ab55e0bcdac421c57d2d5d7705b80d01d3217a672aa1bf73edfc963", + "vout": 0, + "expiry": 1632 + } + ] + } + } + }, + { + "time_ms": 202, + "kind": "stdout", + "data": { + "text": "Available reservations: \n\nReservation 1: shortid fc0b25, amt 800000, expiry height 1632 \n\nMax amount to instant out: 800000\n\nSelect reservations for instantout (e.g. '1,2,3')\nType 'ALL' to use all available reservations.\n" + } + }, + { + "time_ms": 203, + "kind": "stderr", + "data": { + "text": "[loop] invalid index 99\n" + } + }, + { + "time_ms": 203, + "kind": "exit", + "data": { + "run_error": "invalid index 99" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/instantout/07_loop-instantout-channel.json b/cmd/loop/testdata/sessions/instantout/07_loop-instantout-channel.json new file mode 100644 index 000000000..4f23c81c3 --- /dev/null +++ b/cmd/loop/testdata/sessions/instantout/07_loop-instantout-channel.json @@ -0,0 +1,185 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "instantout", + "--network", + "regtest", + "--channel", + "125344325763072" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 1716733605 + }, + "events": [ + { + "time_ms": 1, + "kind": "stdin", + "data": { + "text": "ALL\ny\n" + } + }, + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "request", + "message_type": "looprpc.ListReservationsRequest", + "payload": {} + } + }, + { + "time_ms": 317, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "response", + "message_type": "looprpc.ListReservationsResponse", + "payload": { + "reservations": [ + { + "reservation_id": "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "state": "Spent", + "amount": "800000", + "tx_id": "8b3b5e235ad24be42bc3802c6694566964c394df247b4ae1f2f4fd785e5acd17", + "vout": 0, + "expiry": 1619 + }, + { + "reservation_id": "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "state": "Spent", + "amount": "800000", + "tx_id": "beb447976c6c1a93fdadee41280b912e62b305c7c30815dc172d58732b6c3836", + "vout": 0, + "expiry": 1623 + }, + { + "reservation_id": "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=", + "state": "Spent", + "amount": "800000", + "tx_id": "5f898ca1b3852c62889f1113e07c73d0a3d721fd98d0a5433c6b7122cc706952", + "vout": 0, + "expiry": 1626 + }, + { + "reservation_id": "/AslVrUe/D6Eum+CZsg1x+EalEVACi6ICfc8rVURH3U=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "322d031e9ab55e0bcdac421c57d2d5d7705b80d01d3217a672aa1bf73edfc963", + "vout": 0, + "expiry": 1632 + }, + { + "reservation_id": "0JK1m4RmC5iKV9dR/SlixC0IEGmobPMTlVgmk13thx8=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "081eed1a78e87498ca29af380aaecc64e949c47aeb400375e662fdf630554ace", + "vout": 0, + "expiry": 1653 + } + ] + } + } + }, + { + "time_ms": 317, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOutQuote", + "event": "request", + "message_type": "looprpc.InstantOutQuoteRequest", + "payload": { + "amt": "1600000", + "num_reservations": 0, + "reservation_ids": [ + "/AslVrUe/D6Eum+CZsg1x+EalEVACi6ICfc8rVURH3U=", + "0JK1m4RmC5iKV9dR/SlixC0IEGmobPMTlVgmk13thx8=" + ] + } + } + }, + { + "time_ms": 317, + "kind": "stdout", + "data": { + "text": "Available reservations: \n\nReservation 1: shortid fc0b25, amt 800000, expiry height 1632 \nReservation 2: shortid d092b5, amt 800000, expiry height 1653 \n\nMax amount to instant out: 1600000\n\nSelect reservations for instantout (e.g. '1,2,3')\nType 'ALL' to use all available reservations.\n" + } + }, + { + "time_ms": 359, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOutQuote", + "event": "response", + "message_type": "looprpc.InstantOutQuoteResponse", + "payload": { + "service_fee_sat": "3200", + "sweep_fee_sat": "4210" + } + } + }, + { + "time_ms": 359, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOut", + "event": "request", + "message_type": "looprpc.InstantOutRequest", + "payload": { + "reservation_ids": [ + "/AslVrUe/D6Eum+CZsg1x+EalEVACi6ICfc8rVURH3U=", + "0JK1m4RmC5iKV9dR/SlixC0IEGmobPMTlVgmk13thx8=" + ], + "outgoing_chan_set": [ + "125344325763072" + ], + "dest_addr": "" + } + } + }, + { + "time_ms": 360, + "kind": "stdout", + "data": { + "text": "\nEstimated on-chain fee: 4210 sat\nService fee: 3200 sat\n\nCONTINUE SWAP? (y/n): Starting instant swap out\n" + } + }, + { + "time_ms": 1711, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOut", + "event": "response", + "message_type": "looprpc.InstantOutResponse", + "payload": { + "instant_out_hash": "RfjHjKyop9NqqQzGXnyF1mnv9mPeWJXyz+5seKnKZ4k=", + "sweep_tx_id": "6f6f29961d2b4ab9f893850a0250f1f55fb93b144966833a5546986b171255a4", + "state": "PushPreimage" + } + } + }, + { + "time_ms": 1711, + "kind": "stdout", + "data": { + "text": "Instant out swap initiated with ID: 45f8c78caca8a7d36aa90cc65e7c85d669eff663de5895f2cfee6c78a9ca6789, State: PushPreimage \n" + } + }, + { + "time_ms": 1711, + "kind": "stdout", + "data": { + "text": "Sweepless sweep tx id: 6f6f29961d2b4ab9f893850a0250f1f55fb93b144966833a5546986b171255a4 \n" + } + }, + { + "time_ms": 1716, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/instantout/08_loop-instantout-select-index.json b/cmd/loop/testdata/sessions/instantout/08_loop-instantout-select-index.json new file mode 100644 index 000000000..ca8e5acb4 --- /dev/null +++ b/cmd/loop/testdata/sessions/instantout/08_loop-instantout-select-index.json @@ -0,0 +1,180 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "instantout", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 1377442432 + }, + "events": [ + { + "time_ms": 2, + "kind": "stdin", + "data": { + "text": "1\ny\n" + } + }, + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "request", + "message_type": "looprpc.ListReservationsRequest", + "payload": {} + } + }, + { + "time_ms": 178, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListReservations", + "event": "response", + "message_type": "looprpc.ListReservationsResponse", + "payload": { + "reservations": [ + { + "reservation_id": "s/RD6Lj/eXdmtFCtd/6AvrJQrP14h1YrblyZZMWITYc=", + "state": "Spent", + "amount": "800000", + "tx_id": "8b3b5e235ad24be42bc3802c6694566964c394df247b4ae1f2f4fd785e5acd17", + "vout": 0, + "expiry": 1619 + }, + { + "reservation_id": "Wl+CTsY+V2zUvkK5bs9WIttkvKLrKM8A1kpZ5VZ/MHs=", + "state": "Spent", + "amount": "800000", + "tx_id": "beb447976c6c1a93fdadee41280b912e62b305c7c30815dc172d58732b6c3836", + "vout": 0, + "expiry": 1623 + }, + { + "reservation_id": "Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI=", + "state": "Spent", + "amount": "800000", + "tx_id": "5f898ca1b3852c62889f1113e07c73d0a3d721fd98d0a5433c6b7122cc706952", + "vout": 0, + "expiry": 1626 + }, + { + "reservation_id": "/AslVrUe/D6Eum+CZsg1x+EalEVACi6ICfc8rVURH3U=", + "state": "Spent", + "amount": "800000", + "tx_id": "322d031e9ab55e0bcdac421c57d2d5d7705b80d01d3217a672aa1bf73edfc963", + "vout": 0, + "expiry": 1632 + }, + { + "reservation_id": "0JK1m4RmC5iKV9dR/SlixC0IEGmobPMTlVgmk13thx8=", + "state": "Spent", + "amount": "800000", + "tx_id": "081eed1a78e87498ca29af380aaecc64e949c47aeb400375e662fdf630554ace", + "vout": 0, + "expiry": 1653 + }, + { + "reservation_id": "cSfKVONNmsK9+p4Uc5nc3ZtE+37uOODHeq1vprhh/x4=", + "state": "Confirmed", + "amount": "800000", + "tx_id": "46808a670542c1f3bf20ade2af77c254e3535378aab6ccd32c58de9976b0cf26", + "vout": 0, + "expiry": 1671 + } + ] + } + } + }, + { + "time_ms": 179, + "kind": "stdout", + "data": { + "text": "Available reservations: \n\nReservation 1: shortid 7127ca, amt 800000, expiry height 1671 \n\nMax amount to instant out: 800000\n\nSelect reservations for instantout (e.g. '1,2,3')\nType 'ALL' to use all available reservations.\n" + } + }, + { + "time_ms": 179, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOutQuote", + "event": "request", + "message_type": "looprpc.InstantOutQuoteRequest", + "payload": { + "amt": "800000", + "num_reservations": 0, + "reservation_ids": [ + "cSfKVONNmsK9+p4Uc5nc3ZtE+37uOODHeq1vprhh/x4=" + ] + } + } + }, + { + "time_ms": 186, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOutQuote", + "event": "response", + "message_type": "looprpc.InstantOutQuoteResponse", + "payload": { + "service_fee_sat": "1600", + "sweep_fee_sat": "2772" + } + } + }, + { + "time_ms": 186, + "kind": "stdout", + "data": { + "text": "\nEstimated on-chain fee: 2772 sat\nService fee: 1600 sat\n\nCONTINUE SWAP? (y/n): Starting instant swap out\n" + } + }, + { + "time_ms": 186, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOut", + "event": "request", + "message_type": "looprpc.InstantOutRequest", + "payload": { + "reservation_ids": [ + "cSfKVONNmsK9+p4Uc5nc3ZtE+37uOODHeq1vprhh/x4=" + ], + "outgoing_chan_set": [], + "dest_addr": "" + } + } + }, + { + "time_ms": 1376, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/InstantOut", + "event": "response", + "message_type": "looprpc.InstantOutResponse", + "payload": { + "instant_out_hash": "0LvpOmXv+cqCnXgQ/lNOlbCvlI0AZkkkS1pFJk2n3us=", + "sweep_tx_id": "650e166a7d346f2b268c26c7fe075d8e2dc25655a747f546f5a039f01973d979", + "state": "WaitForSweeplessSweepConfirmed" + } + } + }, + { + "time_ms": 1377, + "kind": "stdout", + "data": { + "text": "Instant out swap initiated with ID: d0bbe93a65eff9ca829d7810fe534e95b0af948d006649244b5a45264da7deeb, State: WaitForSweeplessSweepConfirmed \nSweepless sweep tx id: 650e166a7d346f2b268c26c7fe075d8e2dc25655a747f546f5a039f01973d979 \n" + } + }, + { + "time_ms": 1377, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/l402/01_loop-listauth.json b/cmd/loop/testdata/sessions/l402/01_loop-listauth.json new file mode 100644 index 000000000..c4cbea79b --- /dev/null +++ b/cmd/loop/testdata/sessions/l402/01_loop-listauth.json @@ -0,0 +1,63 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "listauth", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 157631491 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetL402Tokens", + "event": "request", + "message_type": "looprpc.TokensRequest", + "payload": {} + } + }, + { + "time_ms": 157, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetL402Tokens", + "event": "response", + "message_type": "looprpc.TokensResponse", + "payload": { + "tokens": [ + { + "base_macaroon": "AgEEbHNhdAJCAAAkJPkWepsd1GgURnFywD7MZi7yoPZC/BjJHNrIs6en83L1T2GVJqpTIlrcw09RnFx5xHfjsNDjLRIekGAPVN/oAAIPc2VydmljZXM9bG9vcDowAAISbG9vcF9jYXBhYmlsaXRpZXM9AAAGIGIkKNbF9/LxQzqEKurnzP7lkGJbA2CsVbkwrKXyUTx/", + "payment_hash": "JCT5FnqbHdRoFEZxcsA+zGYu8qD2QvwYyRzayLOnp/M=", + "payment_preimage": "pSZZqEORw/4tPCPPS3sTDeh/2mq3EAzwqqWor/xwTmM=", + "amount_paid_msat": "1000000", + "routing_fee_paid_msat": "0", + "time_created": "1770076917", + "expired": false, + "storage_name": "/home/user/.loop/regtest/l402.token", + "id": "72f54f619526aa53225adcc34f519c5c79c477e3b0d0e32d121e90600f54dfe8" + } + ] + } + } + }, + { + "time_ms": 157, + "kind": "stdout", + "data": { + "text": "[\n {\n \"amount_paid_msat\": 1000000,\n \"base_macaroon\": \"0201046c736174024200002424f9167a9b1dd46814467172c03ecc662ef2a0f642fc18c91cdac8b3a7a7f372f54f619526aa53225adcc34f519c5c79c477e3b0d0e32d121e90600f54dfe800020f73657276696365733d6c6f6f703a300002126c6f6f705f6361706162696c69746965733d00000620622428d6c5f7f2f1433a842aeae7ccfee590625b0360ac55b930aca5f2513c7f\",\n \"expired\": false,\n \"file_name\": \"/home/user/.loop/regtest/l402.token\",\n \"id\": \"72f54f619526aa53225adcc34f519c5c79c477e3b0d0e32d121e90600f54dfe8\",\n \"payment_hash\": \"2424f9167a9b1dd46814467172c03ecc662ef2a0f642fc18c91cdac8b3a7a7f3\",\n \"payment_preimage\": \"a52659a84391c3fe2d3c23cf4b7b130de87fda6ab7100cf0aaa5a8affc704e63\",\n \"routing_fee_paid_msat\": 0,\n \"time_created\": \"2026-02-02T19:01:57-05:00\",\n \"valid_until\": \"\"\n }\n]\n" + } + }, + { + "time_ms": 157, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/l402/02_loop-fetchl402.json b/cmd/loop/testdata/sessions/l402/02_loop-fetchl402.json new file mode 100644 index 000000000..9561ad389 --- /dev/null +++ b/cmd/loop/testdata/sessions/l402/02_loop-fetchl402.json @@ -0,0 +1,49 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "fetchl402", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 177710196 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/FetchL402Token", + "event": "request", + "message_type": "looprpc.FetchL402TokenRequest", + "payload": {} + } + }, + { + "time_ms": 177, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/FetchL402Token", + "event": "response", + "message_type": "looprpc.FetchL402TokenResponse", + "payload": {} + } + }, + { + "time_ms": 177, + "kind": "stdout", + "data": { + "text": "{}\n" + } + }, + { + "time_ms": 177, + "kind": "exit", + "data": {} + } + ] +} From f70d2ce18ab7253ff2efa2a72a54afe18b6379b4 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 00:57:01 -0500 Subject: [PATCH 13/15] testdata: add loop in/out and quote sessions --- .../loopin/01_loop-in-invalid-amount.json | 33 +++++ .../02_loop-in-external-conf-target.json | 36 +++++ .../03_loop-in-route-hints-private.json | 36 +++++ .../loopin/04_loop-in-external-cancel.json | 89 ++++++++++++ .../05_loop-in-external-verbose-cancel.json | 90 ++++++++++++ .../loopin/06_loop-in-external-force.json | 109 +++++++++++++++ .../sessions/loopout/01_loop-out.json | 121 ++++++++++++++++ .../loopout/02_loop-out-invalid-amount.json | 33 +++++ .../loopout/03_loop-out-addr-account.json | 37 +++++ ...04_loop-out-invalid-account-addr-type.json | 37 +++++ ...5_loop-out-amt-channel-maxfee-timeout.json | 129 ++++++++++++++++++ .../loopout/06_loop-out-addr-flag.json | 123 +++++++++++++++++ .../loopout/07_loop-out-addr-positional.json | 122 +++++++++++++++++ .../sessions/loopout/08_loop-out-account.json | 125 +++++++++++++++++ .../sessions/quote/01_loop-quote-out.json | 71 ++++++++++ .../sessions/quote/02_loop-quote-in-help.json | 65 +++++++++ .../quote/03_loop-quote-out-help.json | 37 +++++ .../sessions/quote/04_loop-quote-in.json | 109 +++++++++++++++ .../quote/05_loop-quote-in-last-hop.json | 71 ++++++++++ .../quote/06_loop-quote-out-verbose.json | 79 +++++++++++ .../quote/07_loop-quote-in-verbose.json | 70 ++++++++++ 21 files changed, 1622 insertions(+) create mode 100644 cmd/loop/testdata/sessions/loopin/01_loop-in-invalid-amount.json create mode 100644 cmd/loop/testdata/sessions/loopin/02_loop-in-external-conf-target.json create mode 100644 cmd/loop/testdata/sessions/loopin/03_loop-in-route-hints-private.json create mode 100644 cmd/loop/testdata/sessions/loopin/04_loop-in-external-cancel.json create mode 100644 cmd/loop/testdata/sessions/loopin/05_loop-in-external-verbose-cancel.json create mode 100644 cmd/loop/testdata/sessions/loopin/06_loop-in-external-force.json create mode 100644 cmd/loop/testdata/sessions/loopout/01_loop-out.json create mode 100644 cmd/loop/testdata/sessions/loopout/02_loop-out-invalid-amount.json create mode 100644 cmd/loop/testdata/sessions/loopout/03_loop-out-addr-account.json create mode 100644 cmd/loop/testdata/sessions/loopout/04_loop-out-invalid-account-addr-type.json create mode 100644 cmd/loop/testdata/sessions/loopout/05_loop-out-amt-channel-maxfee-timeout.json create mode 100644 cmd/loop/testdata/sessions/loopout/06_loop-out-addr-flag.json create mode 100644 cmd/loop/testdata/sessions/loopout/07_loop-out-addr-positional.json create mode 100644 cmd/loop/testdata/sessions/loopout/08_loop-out-account.json create mode 100644 cmd/loop/testdata/sessions/quote/01_loop-quote-out.json create mode 100644 cmd/loop/testdata/sessions/quote/02_loop-quote-in-help.json create mode 100644 cmd/loop/testdata/sessions/quote/03_loop-quote-out-help.json create mode 100644 cmd/loop/testdata/sessions/quote/04_loop-quote-in.json create mode 100644 cmd/loop/testdata/sessions/quote/05_loop-quote-in-last-hop.json create mode 100644 cmd/loop/testdata/sessions/quote/06_loop-quote-out-verbose.json create mode 100644 cmd/loop/testdata/sessions/quote/07_loop-quote-in-verbose.json diff --git a/cmd/loop/testdata/sessions/loopin/01_loop-in-invalid-amount.json b/cmd/loop/testdata/sessions/loopin/01_loop-in-invalid-amount.json new file mode 100644 index 000000000..df7312ef4 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopin/01_loop-in-invalid-amount.json @@ -0,0 +1,33 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "in", + "--network", + "regtest", + "notanumber" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "invalid amt value \"notanumber\"", + "duration": 3964079 + }, + "events": [ + { + "time_ms": 3, + "kind": "stderr", + "data": { + "text": "[loop] invalid amt value \"notanumber\"\n" + } + }, + { + "time_ms": 3, + "kind": "exit", + "data": { + "run_error": "invalid amt value \"notanumber\"" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopin/02_loop-in-external-conf-target.json b/cmd/loop/testdata/sessions/loopin/02_loop-in-external-conf-target.json new file mode 100644 index 000000000..e780c5a64 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopin/02_loop-in-external-conf-target.json @@ -0,0 +1,36 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "in", + "--external", + "--conf_target", + "6", + "--network", + "regtest", + "10000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "external and conf_target both set", + "duration": 13741983 + }, + "events": [ + { + "time_ms": 13, + "kind": "stderr", + "data": { + "text": "[loop] external and conf_target both set\n" + } + }, + { + "time_ms": 13, + "kind": "exit", + "data": { + "run_error": "external and conf_target both set" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopin/03_loop-in-route-hints-private.json b/cmd/loop/testdata/sessions/loopin/03_loop-in-route-hints-private.json new file mode 100644 index 000000000..e2d0f360d --- /dev/null +++ b/cmd/loop/testdata/sessions/loopin/03_loop-in-route-hints-private.json @@ -0,0 +1,36 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "in", + "--route_hints", + "{}", + "--private", + "--network", + "regtest", + "10000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "private and route_hints both set", + "duration": 2834558 + }, + "events": [ + { + "time_ms": 2, + "kind": "stderr", + "data": { + "text": "[loop] private and route_hints both set\n" + } + }, + { + "time_ms": 2, + "kind": "exit", + "data": { + "run_error": "private and route_hints both set" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopin/04_loop-in-external-cancel.json b/cmd/loop/testdata/sessions/loopin/04_loop-in-external-cancel.json new file mode 100644 index 000000000..56c3247a3 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopin/04_loop-in-external-cancel.json @@ -0,0 +1,89 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "in", + "--network", + "regtest", + "--external", + "--amt", + "50000", + "--last_hop", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "swap canceled", + "duration": 539895736 + }, + "events": [ + { + "time_ms": 1, + "kind": "stdin", + "data": { + "text": "n\n" + } + }, + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "50000", + "conf_target": 0, + "external_htlc": true, + "swap_publication_deadline": "0", + "loop_in_last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 539, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1801", + "htlc_publish_fee_sat": "0", + "cltv_delta": 0, + "conf_target": 0, + "quoted_amt": "50000" + } + } + }, + { + "time_ms": 539, + "kind": "stderr", + "data": { + "text": "[loop] swap canceled\n" + } + }, + { + "time_ms": 539, + "kind": "stdout", + "data": { + "text": "On-chain fee for external loop in is not included.\nSufficient fees will need to be paid when constructing the transaction in the external wallet.\n\nSend on-chain: 50000 sat\nReceive off-chain: 48199 sat\nLoop service fee: 1801 sat\n\nCONTINUE SWAP? (y/n): " + } + }, + { + "time_ms": 539, + "kind": "exit", + "data": { + "run_error": "swap canceled" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopin/05_loop-in-external-verbose-cancel.json b/cmd/loop/testdata/sessions/loopin/05_loop-in-external-verbose-cancel.json new file mode 100644 index 000000000..fc5201ca4 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopin/05_loop-in-external-verbose-cancel.json @@ -0,0 +1,90 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "in", + "--network", + "regtest", + "--external", + "--verbose", + "--amt", + "50000", + "--last_hop", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "swap canceled", + "duration": 164102130 + }, + "events": [ + { + "time_ms": 0, + "kind": "stdin", + "data": { + "text": "n\n" + } + }, + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "50000", + "conf_target": 0, + "external_htlc": true, + "swap_publication_deadline": "0", + "loop_in_last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 163, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1801", + "htlc_publish_fee_sat": "0", + "cltv_delta": 0, + "conf_target": 0, + "quoted_amt": "50000" + } + } + }, + { + "time_ms": 163, + "kind": "stdout", + "data": { + "text": "On-chain fee for external loop in is not included.\nSufficient fees will need to be paid when constructing the transaction in the external wallet.\n\nSend on-chain: 50000 sat\nReceive off-chain: 48199 sat\nLoop service fee: 1801 sat\n\nCLTV expiry delta: 0 block\n\nCONTINUE SWAP? (y/n): " + } + }, + { + "time_ms": 164, + "kind": "stderr", + "data": { + "text": "[loop] swap canceled\n" + } + }, + { + "time_ms": 164, + "kind": "exit", + "data": { + "run_error": "swap canceled" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopin/06_loop-in-external-force.json b/cmd/loop/testdata/sessions/loopin/06_loop-in-external-force.json new file mode 100644 index 000000000..2d4f391a1 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopin/06_loop-in-external-force.json @@ -0,0 +1,109 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "in", + "--network", + "regtest", + "--external", + "--amt", + "500000", + "--force" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 1067066878 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 0, + "external_htlc": true, + "swap_publication_deadline": "0", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 561, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1824", + "htlc_publish_fee_sat": "0", + "cltv_delta": 0, + "conf_target": 0, + "quoted_amt": "500000" + } + } + }, + { + "time_ms": 561, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopIn", + "event": "request", + "message_type": "looprpc.LoopInRequest", + "payload": { + "amt": "500000", + "max_swap_fee": "1824", + "max_miner_fee": "0", + "last_hop": "", + "external_htlc": true, + "htlc_conf_target": 0, + "label": "", + "initiator": "loop-cli", + "route_hints": [], + "private": false + } + } + }, + { + "time_ms": 1065, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopIn", + "event": "response", + "message_type": "looprpc.SwapResponse", + "payload": { + "id": "2f46a232e0f584fadf2abc7e7aaeefab0176f21e0fba5344a10e21838ec390fe", + "id_bytes": "L0aiMuD1hPrfKrx+eq7vqwF28h4PulNEoQ4hg47DkP4=", + "htlc_address": "bcrt1pcred99xc9l2cxphneej4ph6d6mczc0442d6ulyh3a9ad389z2aaq4n775y", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1pcred99xc9l2cxphneej4ph6d6mczc0442d6ulyh3a9ad389z2aaq4n775y", + "server_message": "" + } + } + }, + { + "time_ms": 1066, + "kind": "stdout", + "data": { + "text": "Swap initiated\nID: 2f46a232e0f584fadf2abc7e7aaeefab0176f21e0fba5344a10e21838ec390fe\nHTLC address (P2TR): bcrt1pcred99xc9l2cxphneej4ph6d6mczc0442d6ulyh3a9ad389z2aaq4n775y\n\nRun `loop monitor` to monitor progress.\n" + } + }, + { + "time_ms": 1067, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopout/01_loop-out.json b/cmd/loop/testdata/sessions/loopout/01_loop-out.json new file mode 100644 index 000000000..5e2db6cdf --- /dev/null +++ b/cmd/loop/testdata/sessions/loopout/01_loop-out.json @@ -0,0 +1,121 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "out", + "--network", + "regtest", + "--force", + "--fast", + "500000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 228730686 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 9, + "external_htlc": false, + "swap_publication_deadline": "1769407086", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 139, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "response", + "message_type": "looprpc.OutQuoteResponse", + "payload": { + "swap_fee_sat": "3875", + "prepay_amt_sat": "1337", + "htlc_sweep_fee_sat": "3793", + "swap_payment_dest": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "cltv_delta": 0, + "conf_target": 9, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 139, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "request", + "message_type": "looprpc.LoopOutRequest", + "payload": { + "amt": "500000", + "dest": "", + "max_swap_routing_fee": "10010", + "max_prepay_routing_fee": "36", + "max_swap_fee": "3875", + "max_prepay_amt": "1337", + "max_miner_fee": "948250", + "loop_out_channel": "0", + "outgoing_chan_set": [], + "sweep_conf_target": 9, + "htlc_confirmations": 1, + "swap_publication_deadline": "1769407086", + "label": "", + "initiator": "loop-cli", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "is_external_addr": false, + "reservation_ids": [], + "payment_timeout": 0, + "asset_info": null, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 228, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "response", + "message_type": "looprpc.SwapResponse", + "payload": { + "id": "46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b", + "id_bytes": "RrjbZBEKYAi9NrQjQ5y7oejnbAJk6KaPRC/CKjwrT2s=", + "htlc_address": "bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv", + "server_message": "" + } + } + }, + { + "time_ms": 228, + "kind": "stdout", + "data": { + "text": "Swap initiated\nID: 46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\n\nRun `loop monitor` to monitor progress.\n" + } + }, + { + "time_ms": 228, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopout/02_loop-out-invalid-amount.json b/cmd/loop/testdata/sessions/loopout/02_loop-out-invalid-amount.json new file mode 100644 index 000000000..297e93623 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopout/02_loop-out-invalid-amount.json @@ -0,0 +1,33 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "out", + "--network", + "regtest", + "notanumber" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "invalid amt value \"notanumber\"", + "duration": 1215843 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "[loop] invalid amt value \"notanumber\"\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": { + "run_error": "invalid amt value \"notanumber\"" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopout/03_loop-out-addr-account.json b/cmd/loop/testdata/sessions/loopout/03_loop-out-addr-account.json new file mode 100644 index 000000000..989602882 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopout/03_loop-out-addr-account.json @@ -0,0 +1,37 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "out", + "--addr", + "bcrt1qtest", + "--account", + "testacct", + "--network", + "regtest", + "50000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "cannot set --addr and --account at the same time. Please specify only one source for a new address to sweep the loop amount to", + "duration": 1276860 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "[loop] cannot set --addr and --account at the same time. Please specify only one source for a new address to sweep the loop amount to\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": { + "run_error": "cannot set --addr and --account at the same time. Please specify only one source for a new address to sweep the loop amount to" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopout/04_loop-out-invalid-account-addr-type.json b/cmd/loop/testdata/sessions/loopout/04_loop-out-invalid-account-addr-type.json new file mode 100644 index 000000000..d7f581d4c --- /dev/null +++ b/cmd/loop/testdata/sessions/loopout/04_loop-out-invalid-account-addr-type.json @@ -0,0 +1,37 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "out", + "--account", + "testacct", + "--account_addr_type", + "foo", + "--network", + "regtest", + "50000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "unknown account address type", + "duration": 1107998 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "[loop] unknown account address type\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": { + "run_error": "unknown account address type" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopout/05_loop-out-amt-channel-maxfee-timeout.json b/cmd/loop/testdata/sessions/loopout/05_loop-out-amt-channel-maxfee-timeout.json new file mode 100644 index 000000000..7b37d63be --- /dev/null +++ b/cmd/loop/testdata/sessions/loopout/05_loop-out-amt-channel-maxfee-timeout.json @@ -0,0 +1,129 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "out", + "--network", + "regtest", + "--amt", + "500000", + "--channel", + "125344325763072", + "--max_swap_routing_fee", + "1000", + "--payment_timeout", + "30s", + "--force" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 288562226 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 9, + "external_htlc": false, + "swap_publication_deadline": "1769408886", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 161, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "response", + "message_type": "looprpc.OutQuoteResponse", + "payload": { + "swap_fee_sat": "3873", + "prepay_amt_sat": "1337", + "htlc_sweep_fee_sat": "3791", + "swap_payment_dest": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "cltv_delta": 0, + "conf_target": 9, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 161, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "request", + "message_type": "looprpc.LoopOutRequest", + "payload": { + "amt": "500000", + "dest": "", + "max_swap_routing_fee": "1000", + "max_prepay_routing_fee": "36", + "max_swap_fee": "3873", + "max_prepay_amt": "1337", + "max_miner_fee": "947750", + "loop_out_channel": "0", + "outgoing_chan_set": [ + "125344325763072" + ], + "sweep_conf_target": 9, + "htlc_confirmations": 1, + "swap_publication_deadline": "1769408886", + "label": "", + "initiator": "loop-cli", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "is_external_addr": false, + "reservation_ids": [], + "payment_timeout": 30, + "asset_info": null, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 288, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "response", + "message_type": "looprpc.SwapResponse", + "payload": { + "id": "a564cdea5bac2fa1e350da6e7096ddd3bc0256c157f9f4b9b71a1262742f4f0d", + "id_bytes": "pWTN6lusL6HjUNpucJbd07wCVsFX+fS5txoSYnQvTw0=", + "htlc_address": "bcrt1pg84j6m04s6ecvlgput74dh4kfppn0lxn7f9h5cyl7vylyu3l55ss2f9xyh", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1pg84j6m04s6ecvlgput74dh4kfppn0lxn7f9h5cyl7vylyu3l55ss2f9xyh", + "server_message": "" + } + } + }, + { + "time_ms": 288, + "kind": "stdout", + "data": { + "text": "Swap initiated\nID: a564cdea5bac2fa1e350da6e7096ddd3bc0256c157f9f4b9b71a1262742f4f0d\n\nRun `loop monitor` to monitor progress.\n" + } + }, + { + "time_ms": 288, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopout/06_loop-out-addr-flag.json b/cmd/loop/testdata/sessions/loopout/06_loop-out-addr-flag.json new file mode 100644 index 000000000..2d23bedd5 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopout/06_loop-out-addr-flag.json @@ -0,0 +1,123 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "out", + "--network", + "regtest", + "--amt", + "500000", + "--addr", + "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "--force" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 299201197 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 9, + "external_htlc": false, + "swap_publication_deadline": "1769408886", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 230, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "response", + "message_type": "looprpc.OutQuoteResponse", + "payload": { + "swap_fee_sat": "3873", + "prepay_amt_sat": "1337", + "htlc_sweep_fee_sat": "3791", + "swap_payment_dest": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "cltv_delta": 0, + "conf_target": 9, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 230, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "request", + "message_type": "looprpc.LoopOutRequest", + "payload": { + "amt": "500000", + "dest": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "max_swap_routing_fee": "10010", + "max_prepay_routing_fee": "36", + "max_swap_fee": "3873", + "max_prepay_amt": "1337", + "max_miner_fee": "947750", + "loop_out_channel": "0", + "outgoing_chan_set": [], + "sweep_conf_target": 9, + "htlc_confirmations": 1, + "swap_publication_deadline": "1769408886", + "label": "", + "initiator": "loop-cli", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "is_external_addr": true, + "reservation_ids": [], + "payment_timeout": 0, + "asset_info": null, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 298, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "response", + "message_type": "looprpc.SwapResponse", + "payload": { + "id": "67712e10d785636ec4b19c0c3d0f7b7612c1de5ccb2cb81df94e32ff13914fab", + "id_bytes": "Z3EuENeFY27EsZwMPQ97dhLB3lzLLLgd+U4y/xORT6s=", + "htlc_address": "bcrt1p0fn96tdw5ngu9cpww0w8q96tcps6w7jezaf0xnw0wa7e5d5gxv3st47amw", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1p0fn96tdw5ngu9cpww0w8q96tcps6w7jezaf0xnw0wa7e5d5gxv3st47amw", + "server_message": "" + } + } + }, + { + "time_ms": 298, + "kind": "stdout", + "data": { + "text": "Swap initiated\nID: 67712e10d785636ec4b19c0c3d0f7b7612c1de5ccb2cb81df94e32ff13914fab\n\nRun `loop monitor` to monitor progress.\n" + } + }, + { + "time_ms": 299, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopout/07_loop-out-addr-positional.json b/cmd/loop/testdata/sessions/loopout/07_loop-out-addr-positional.json new file mode 100644 index 000000000..b6e0facaa --- /dev/null +++ b/cmd/loop/testdata/sessions/loopout/07_loop-out-addr-positional.json @@ -0,0 +1,122 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "out", + "--network", + "regtest", + "--amt", + "500000", + "--force", + "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 290631176 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 9, + "external_htlc": false, + "swap_publication_deadline": "1769408886", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 205, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "response", + "message_type": "looprpc.OutQuoteResponse", + "payload": { + "swap_fee_sat": "3873", + "prepay_amt_sat": "1337", + "htlc_sweep_fee_sat": "3791", + "swap_payment_dest": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "cltv_delta": 0, + "conf_target": 9, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 205, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "request", + "message_type": "looprpc.LoopOutRequest", + "payload": { + "amt": "500000", + "dest": "", + "max_swap_routing_fee": "10010", + "max_prepay_routing_fee": "36", + "max_swap_fee": "3873", + "max_prepay_amt": "1337", + "max_miner_fee": "947750", + "loop_out_channel": "0", + "outgoing_chan_set": [], + "sweep_conf_target": 9, + "htlc_confirmations": 1, + "swap_publication_deadline": "1769408886", + "label": "", + "initiator": "loop-cli", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "is_external_addr": false, + "reservation_ids": [], + "payment_timeout": 0, + "asset_info": null, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 290, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "response", + "message_type": "looprpc.SwapResponse", + "payload": { + "id": "aa7d0c558627aaa8af70503cd81d4679400cc9771063cb474c32c625d5f2a8f3", + "id_bytes": "qn0MVYYnqqivcFA82B1GeUAMyXcQY8tHTDLGJdXyqPM=", + "htlc_address": "bcrt1p9jhv4amddjazuyzs8xr2u2fzzqdt2s5tx95ffhd43avxvq7d0xxsykf5r5", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1p9jhv4amddjazuyzs8xr2u2fzzqdt2s5tx95ffhd43avxvq7d0xxsykf5r5", + "server_message": "" + } + } + }, + { + "time_ms": 290, + "kind": "stdout", + "data": { + "text": "Swap initiated\nID: aa7d0c558627aaa8af70503cd81d4679400cc9771063cb474c32c625d5f2a8f3\n\nRun `loop monitor` to monitor progress.\n" + } + }, + { + "time_ms": 290, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/loopout/08_loop-out-account.json b/cmd/loop/testdata/sessions/loopout/08_loop-out-account.json new file mode 100644 index 000000000..180fa5f25 --- /dev/null +++ b/cmd/loop/testdata/sessions/loopout/08_loop-out-account.json @@ -0,0 +1,125 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "out", + "--network", + "regtest", + "--amt", + "500000", + "--account", + "default", + "--account_addr_type", + "p2tr", + "--force" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 466934696 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 9, + "external_htlc": false, + "swap_publication_deadline": "1769408886", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 360, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "response", + "message_type": "looprpc.OutQuoteResponse", + "payload": { + "swap_fee_sat": "3873", + "prepay_amt_sat": "1337", + "htlc_sweep_fee_sat": "3791", + "swap_payment_dest": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "cltv_delta": 0, + "conf_target": 9, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 360, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "request", + "message_type": "looprpc.LoopOutRequest", + "payload": { + "amt": "500000", + "dest": "", + "max_swap_routing_fee": "10010", + "max_prepay_routing_fee": "36", + "max_swap_fee": "3873", + "max_prepay_amt": "1337", + "max_miner_fee": "947750", + "loop_out_channel": "0", + "outgoing_chan_set": [], + "sweep_conf_target": 9, + "htlc_confirmations": 1, + "swap_publication_deadline": "1769408886", + "label": "", + "initiator": "loop-cli", + "account": "default", + "account_addr_type": "TAPROOT_PUBKEY", + "is_external_addr": false, + "reservation_ids": [], + "payment_timeout": 0, + "asset_info": null, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 462, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOut", + "event": "response", + "message_type": "looprpc.SwapResponse", + "payload": { + "id": "04c1ef677f170f50ad3f221f49a779b99a464907bde2e0003a7b1dd6402d1419", + "id_bytes": "BMHvZ38XD1CtPyIfSad5uZpGSQe94uAAOnsd1kAtFBk=", + "htlc_address": "bcrt1p8lvg7l4zkdu0l4pe74h96240ndmp3demreml3zeqy28dvgq7j95q23zqcy", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1p8lvg7l4zkdu0l4pe74h96240ndmp3demreml3zeqy28dvgq7j95q23zqcy", + "server_message": "" + } + } + }, + { + "time_ms": 462, + "kind": "stdout", + "data": { + "text": "Swap initiated\nID: 04c1ef677f170f50ad3f221f49a779b99a464907bde2e0003a7b1dd6402d1419\n\nRun `loop monitor` to monitor progress.\n" + } + }, + { + "time_ms": 466, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/quote/01_loop-quote-out.json b/cmd/loop/testdata/sessions/quote/01_loop-quote-out.json new file mode 100644 index 000000000..32378367b --- /dev/null +++ b/cmd/loop/testdata/sessions/quote/01_loop-quote-out.json @@ -0,0 +1,71 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "quote", + "out", + "--network", + "regtest", + "500000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 159166421 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 9, + "external_htlc": false, + "swap_publication_deadline": "1769408886", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 158, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "response", + "message_type": "looprpc.OutQuoteResponse", + "payload": { + "swap_fee_sat": "3875", + "prepay_amt_sat": "1337", + "htlc_sweep_fee_sat": "3793", + "swap_payment_dest": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "cltv_delta": 0, + "conf_target": 9, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 158, + "kind": "stdout", + "data": { + "text": "Send off-chain: 500000 sat\nReceive on-chain: 492332 sat\nEstimated total fee: 7668 sat\n" + } + }, + { + "time_ms": 159, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/quote/02_loop-quote-in-help.json b/cmd/loop/testdata/sessions/quote/02_loop-quote-in-help.json new file mode 100644 index 000000000..401e79949 --- /dev/null +++ b/cmd/loop/testdata/sessions/quote/02_loop-quote-in-help.json @@ -0,0 +1,65 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "quote", + "in", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 1248128 + }, + "events": [ + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "NAME:\n loop quote in - get a quote for the cost of a loop in swap\n\nUSAGE:\n loop quote in amt\n\nDESCRIPTION:\n Allows to determine the cost of a swap up front.Either specify an amount or deposit outpoints.\n\nOPTIONS:\n" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " --last_hop string the pubkey of the last hop to use for the quote\n --conf_target uint the target number of blocks the on-chain htlc broadcast by the swap client should confirm within (default: 0)\n --verbose, -v show expanded details (default: false)\n --private generates and passes routehints. Should be used if the connected node is only reachable via private channels (default: false)\n --route_hints string [ --route_hints string ] " + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " route hints that can each be individually used to assist in reaching the invoice's destination\n --deposit_outpoint string [ --deposit_outpoint string ] one or more static address deposit outpoints to quote for. Deposit outpoints are not to be used in combination with an amount. Eachadditional outpoint can be added by specifying --deposit_outpoint tx_id:idx\n" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " --help, -h " + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " " + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "show help\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/quote/03_loop-quote-out-help.json b/cmd/loop/testdata/sessions/quote/03_loop-quote-out-help.json new file mode 100644 index 000000000..4e09ff239 --- /dev/null +++ b/cmd/loop/testdata/sessions/quote/03_loop-quote-out-help.json @@ -0,0 +1,37 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "quote", + "out", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 1687027 + }, + "events": [ + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "NAME:" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "\n loop quote out - get a quote for the cost of a loop out swap\n\nUSAGE:\n loop quote out amt\n\nDESCRIPTION:\n Allows to determine the cost of a swap up front\n\nOPTIONS:\n --conf_target uint the number of blocks from the swap initiation height that the on-chain HTLC should be swept within in a Loop Out (default: 9)\n --fast Indicate you want to swap immediately, paying potentially a higher fee. If not set the swap server might choose to wait up to 30 minutes before publishing the swap HTLC on-chain, to save on chain fees. Not setting this flag might result in a lower swap fee. (default: false)\n --verbose, -v show expanded details (default: false)\n --help, -h show help\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/quote/04_loop-quote-in.json b/cmd/loop/testdata/sessions/quote/04_loop-quote-in.json new file mode 100644 index 000000000..cad66cb4f --- /dev/null +++ b/cmd/loop/testdata/sessions/quote/04_loop-quote-in.json @@ -0,0 +1,109 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "quote", + "in", + "--network", + "regtest", + "--deposit_outpoint", + "edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 622954327 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "UNKNOWN_STATE", + "outpoints": [ + "edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0" + ] + } + } + }, + { + "time_ms": 165, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "aCYqEEyewyXea+w3uOMb2HW70vXwuc4togzwvWNvxEg=", + "state": "DEPOSITED", + "outpoint": "edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0", + "value": "500000", + "confirmation_height": "125", + "blocks_until_expiry": "14394", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 165, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "0", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [ + "edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0" + ], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 622, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1825", + "htlc_publish_fee_sat": "0", + "cltv_delta": 0, + "conf_target": 0, + "quoted_amt": "500000" + } + } + }, + { + "time_ms": 622, + "kind": "stdout", + "data": { + "text": "Previously deposited on-chain: 500000 sat\nReceive off-chain: 498175 sat\nEstimated total fee: 1825 sat\n" + } + }, + { + "time_ms": 622, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/quote/05_loop-quote-in-last-hop.json b/cmd/loop/testdata/sessions/quote/05_loop-quote-in-last-hop.json new file mode 100644 index 000000000..3f4db969a --- /dev/null +++ b/cmd/loop/testdata/sessions/quote/05_loop-quote-in-last-hop.json @@ -0,0 +1,71 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "quote", + "in", + "--network", + "regtest", + "--last_hop", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7", + "50000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 226964878 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "50000", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 226, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1801", + "htlc_publish_fee_sat": "3873", + "cltv_delta": 0, + "conf_target": 6, + "quoted_amt": "50000" + } + } + }, + { + "time_ms": 226, + "kind": "stdout", + "data": { + "text": "Send on-chain: 50000 sat\nReceive off-chain: 44326 sat\nEstimated total fee: 5674 sat\n" + } + }, + { + "time_ms": 226, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/quote/06_loop-quote-out-verbose.json b/cmd/loop/testdata/sessions/quote/06_loop-quote-out-verbose.json new file mode 100644 index 000000000..3d5b0d9d4 --- /dev/null +++ b/cmd/loop/testdata/sessions/quote/06_loop-quote-out-verbose.json @@ -0,0 +1,79 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "quote", + "out", + "--network", + "regtest", + "--verbose", + "50000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 273326957 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "50000", + "conf_target": 9, + "external_htlc": false, + "swap_publication_deadline": "1769408886", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 272, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/LoopOutQuote", + "event": "response", + "message_type": "looprpc.OutQuoteResponse", + "payload": { + "swap_fee_sat": "3828", + "prepay_amt_sat": "1337", + "htlc_sweep_fee_sat": "3791", + "swap_payment_dest": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "cltv_delta": 0, + "conf_target": 9, + "asset_rfq_info": null + } + } + }, + { + "time_ms": 273, + "kind": "stdout", + "data": { + "text": "Send off-chain: 50000 sat\nReceive on-chain: 42381 sat\n\nEstimated on-chain fee: 3791 sat\nLoop service fee: 3828 sat\nEstimated total fee: 7619 sat\n\n" + } + }, + { + "time_ms": 273, + "kind": "stdout", + "data": { + "text": "No show penalty (prepay): 1337 sat\nConf target: 9 block\nCLTV expiry delta: 0 block\nPublication deadline: 2026-01-26 01:28:06 -0500 EST\n" + } + }, + { + "time_ms": 273, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/quote/07_loop-quote-in-verbose.json b/cmd/loop/testdata/sessions/quote/07_loop-quote-in-verbose.json new file mode 100644 index 000000000..5445b97a6 --- /dev/null +++ b/cmd/loop/testdata/sessions/quote/07_loop-quote-in-verbose.json @@ -0,0 +1,70 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "quote", + "in", + "--network", + "regtest", + "--verbose", + "50000" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 380680881 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "50000", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 379, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1800", + "htlc_publish_fee_sat": "3871", + "cltv_delta": 0, + "conf_target": 6, + "quoted_amt": "50000" + } + } + }, + { + "time_ms": 380, + "kind": "stdout", + "data": { + "text": "Send on-chain: 50000 sat\nReceive off-chain: 44329 sat\n\nEstimated on-chain fee: 3871 sat\nLoop service fee: 1800 sat\nEstimated total fee: 5671 sat\n\nConf target: 6 block\nCLTV expiry delta: 0 block\n" + } + }, + { + "time_ms": 380, + "kind": "exit", + "data": {} + } + ] +} From f18a2ee42a6e614267cf8d06d35f011ca2bcb68f Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 00:57:32 -0500 Subject: [PATCH 14/15] testdata: add liquidity sessions --- .../sessions/liquidity/01_loop-getparams.json | 77 ++++++++ .../liquidity/02_loop-setparams-no-flags.json | 89 +++++++++ .../03_loop-setparams-feepercent.json | 122 ++++++++++++ ...04_loop-setparams-feepercent-conflict.json | 93 +++++++++ .../05_loop-setrule-missing-threshold.json | 90 +++++++++ .../liquidity/06_loop-setrule-no-args.json | 32 +++ .../liquidity/07_loop-suggestswaps.json | 51 +++++ .../liquidity/08_loop-setrule-success.json | 141 ++++++++++++++ .../09_loop-suggestswaps-success.json | 53 +++++ .../liquidity/10_loop-setrule-incoming.json | 149 ++++++++++++++ .../11_loop-setrule-outgoing-type-in.json | 176 +++++++++++++++++ .../liquidity/12_loop-setrule-clear.json | 148 ++++++++++++++ .../13_loop-setparams-many-flags-error.json | 182 +++++++++++++++++ ...oop-setparams-many-flags-error-minamt.json | 184 ++++++++++++++++++ .../15_loop-setparams-many-flags.json | 175 +++++++++++++++++ .../liquidity/16_loop-setparams-destaddr.json | 144 ++++++++++++++ .../liquidity/17_loop-setparams-account.json | 146 ++++++++++++++ .../18_loop-setparams-includeallpeers.json | 141 ++++++++++++++ .../liquidity/19_loop-setrule-type-out.json | 151 ++++++++++++++ 19 files changed, 2344 insertions(+) create mode 100644 cmd/loop/testdata/sessions/liquidity/01_loop-getparams.json create mode 100644 cmd/loop/testdata/sessions/liquidity/02_loop-setparams-no-flags.json create mode 100644 cmd/loop/testdata/sessions/liquidity/03_loop-setparams-feepercent.json create mode 100644 cmd/loop/testdata/sessions/liquidity/04_loop-setparams-feepercent-conflict.json create mode 100644 cmd/loop/testdata/sessions/liquidity/05_loop-setrule-missing-threshold.json create mode 100644 cmd/loop/testdata/sessions/liquidity/06_loop-setrule-no-args.json create mode 100644 cmd/loop/testdata/sessions/liquidity/07_loop-suggestswaps.json create mode 100644 cmd/loop/testdata/sessions/liquidity/08_loop-setrule-success.json create mode 100644 cmd/loop/testdata/sessions/liquidity/09_loop-suggestswaps-success.json create mode 100644 cmd/loop/testdata/sessions/liquidity/10_loop-setrule-incoming.json create mode 100644 cmd/loop/testdata/sessions/liquidity/11_loop-setrule-outgoing-type-in.json create mode 100644 cmd/loop/testdata/sessions/liquidity/12_loop-setrule-clear.json create mode 100644 cmd/loop/testdata/sessions/liquidity/13_loop-setparams-many-flags-error.json create mode 100644 cmd/loop/testdata/sessions/liquidity/14_loop-setparams-many-flags-error-minamt.json create mode 100644 cmd/loop/testdata/sessions/liquidity/15_loop-setparams-many-flags.json create mode 100644 cmd/loop/testdata/sessions/liquidity/16_loop-setparams-destaddr.json create mode 100644 cmd/loop/testdata/sessions/liquidity/17_loop-setparams-account.json create mode 100644 cmd/loop/testdata/sessions/liquidity/18_loop-setparams-includeallpeers.json create mode 100644 cmd/loop/testdata/sessions/liquidity/19_loop-setrule-type-out.json diff --git a/cmd/loop/testdata/sessions/liquidity/01_loop-getparams.json b/cmd/loop/testdata/sessions/liquidity/01_loop-getparams.json new file mode 100644 index 000000000..46aa00acd --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/01_loop-getparams.json @@ -0,0 +1,77 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "getparams", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 213058408 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 212, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 212, + "kind": "stdout", + "data": { + "text": "{\n \"account\": \"\",\n \"account_addr_type\": \"ADDRESS_TYPE_UNKNOWN\",\n \"auto_max_in_flight\": \"1\",\n \"autoloop\": false,\n \"autoloop_budget_last_refresh\": \"1770076824\",\n \"autoloop_budget_refresh_period_sec\": \"604800\",\n \"autoloop_budget_sat\": \"335544\",\n \"autoloop_budget_start_sec\": \"0\",\n \"autoloop_dest_address\": \"\",\n \"easy_asset_params\": {},\n \"easy_autoloop\": false,\n \"easy_autoloop_excluded_peers\": [],\n \"easy_autoloop_local_target_sat\": \"0\",\n \"failure_backoff_sec\": \"86400\",\n \"fast_swap_publication\": true,\n \"fee_ppm\": \"20000\",\n \"htlc_conf_target\": 6,\n \"max_miner_fee_sat\": \"0\",\n \"max_prepay_routing_fee_ppm\": \"0\",\n \"max_prepay_sat\": \"0\",\n \"max_routing_fee_ppm\": \"0\",\n \"max_swap_amount\": \"0\",\n \"max_swap_fee_ppm\": \"0\",\n \"min_swap_amount\": \"0\",\n \"rules\": [],\n \"sweep_conf_target\": 100,\n \"sweep_fee_rate_sat_per_vbyte\": \"0\"\n}\n" + } + }, + { + "time_ms": 213, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/02_loop-setparams-no-flags.json b/cmd/loop/testdata/sessions/liquidity/02_loop-setparams-no-flags.json new file mode 100644 index 000000000..029fe614a --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/02_loop-setparams-no-flags.json @@ -0,0 +1,89 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "at least one flag required to set params", + "duration": 150177446 + }, + "events": [ + { + "time_ms": 5, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 149, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 150, + "kind": "stderr", + "data": { + "text": "[loop] at least one flag required to set params\n" + } + }, + { + "time_ms": 150, + "kind": "exit", + "data": { + "run_error": "at least one flag required to set params" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/03_loop-setparams-feepercent.json b/cmd/loop/testdata/sessions/liquidity/03_loop-setparams-feepercent.json new file mode 100644 index 000000000..db59d30c9 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/03_loop-setparams-feepercent.json @@ -0,0 +1,122 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest", + "--feepercent", + "2" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 249608692 + }, + "events": [ + { + "time_ms": 6, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 188, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 189, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + } + }, + { + "time_ms": 248, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 249, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/04_loop-setparams-feepercent-conflict.json b/cmd/loop/testdata/sessions/liquidity/04_loop-setparams-feepercent-conflict.json new file mode 100644 index 000000000..a7442217c --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/04_loop-setparams-feepercent-conflict.json @@ -0,0 +1,93 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest", + "--feepercent", + "2", + "--sweeplimit", + "1" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "feepercent cannot be set with specific fee category flags", + "duration": 161206474 + }, + "events": [ + { + "time_ms": 4, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 159, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 161, + "kind": "stderr", + "data": { + "text": "[loop] feepercent cannot be set with specific fee category flags\n" + } + }, + { + "time_ms": 161, + "kind": "exit", + "data": { + "run_error": "feepercent cannot be set with specific fee category flags" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/05_loop-setrule-missing-threshold.json b/cmd/loop/testdata/sessions/liquidity/05_loop-setrule-missing-threshold.json new file mode 100644 index 000000000..80a874277 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/05_loop-setrule-missing-threshold.json @@ -0,0 +1,90 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setrule", + "--network", + "regtest", + "034fa8802fdc9f8c137e8f2cce2e4d30e590a1314e16bd060ac7d772dc698ff4bc" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "provide at least one flag to set rules or use the --clear flag to remove rules", + "duration": 143258905 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 142, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 143, + "kind": "stderr", + "data": { + "text": "[loop] provide at least one flag to set rules or use the --clear flag to remove rules\n" + } + }, + { + "time_ms": 143, + "kind": "exit", + "data": { + "run_error": "provide at least one flag to set rules or use the --clear flag to remove rules" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/06_loop-setrule-no-args.json b/cmd/loop/testdata/sessions/liquidity/06_loop-setrule-no-args.json new file mode 100644 index 000000000..66b654052 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/06_loop-setrule-no-args.json @@ -0,0 +1,32 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setrule", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "please set a channel id or peer pubkey for the rule update", + "duration": 1924009 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "[loop] please set a channel id or peer pubkey for the rule update\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": { + "run_error": "please set a channel id or peer pubkey for the rule update" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/07_loop-suggestswaps.json b/cmd/loop/testdata/sessions/liquidity/07_loop-suggestswaps.json new file mode 100644 index 000000000..284b62397 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/07_loop-suggestswaps.json @@ -0,0 +1,51 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "suggestswaps", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "rpc error: code = FailedPrecondition desc = no rules set for autoloop", + "duration": 178932401 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SuggestSwaps", + "event": "request", + "message_type": "looprpc.SuggestSwapsRequest", + "payload": {} + } + }, + { + "time_ms": 178, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SuggestSwaps", + "event": "error", + "error": "rpc error: code = FailedPrecondition desc = no rules set for autoloop" + } + }, + { + "time_ms": 178, + "kind": "stderr", + "data": { + "text": "[loop] rpc error: code = FailedPrecondition desc = no rules set for autoloop\n" + } + }, + { + "time_ms": 178, + "kind": "exit", + "data": { + "run_error": "rpc error: code = FailedPrecondition desc = no rules set for autoloop" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/08_loop-setrule-success.json b/cmd/loop/testdata/sessions/liquidity/08_loop-setrule-success.json new file mode 100644 index 000000000..38b61c81d --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/08_loop-setrule-success.json @@ -0,0 +1,141 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setrule", + "--network", + "regtest", + "--incoming_threshold", + "10", + "034fa8802fdc9f8c137e8f2cce2e4d30e590a1314e16bd060ac7d772dc698ff4bc" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 130661787 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 124, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 124, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + } + }, + { + "time_ms": 130, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 130, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/09_loop-suggestswaps-success.json b/cmd/loop/testdata/sessions/liquidity/09_loop-suggestswaps-success.json new file mode 100644 index 000000000..93e308c29 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/09_loop-suggestswaps-success.json @@ -0,0 +1,53 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "suggestswaps", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 137916583 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SuggestSwaps", + "event": "request", + "message_type": "looprpc.SuggestSwapsRequest", + "payload": {} + } + }, + { + "time_ms": 137, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SuggestSwaps", + "event": "response", + "message_type": "looprpc.SuggestSwapsResponse", + "payload": { + "loop_out": [], + "loop_in": [], + "disqualified": [] + } + } + }, + { + "time_ms": 137, + "kind": "stdout", + "data": { + "text": "{\n \"disqualified\": [],\n \"loop_in\": [],\n \"loop_out\": []\n}\n" + } + }, + { + "time_ms": 137, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/10_loop-setrule-incoming.json b/cmd/loop/testdata/sessions/liquidity/10_loop-setrule-incoming.json new file mode 100644 index 000000000..81d1a9f46 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/10_loop-setrule-incoming.json @@ -0,0 +1,149 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setrule", + "--network", + "regtest", + "--incoming_threshold", + "40", + "125344325763072" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 204743867 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 135, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 135, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + }, + { + "channel_id": "125344325763072", + "swap_type": "LOOP_OUT", + "pubkey": "", + "type": "THRESHOLD", + "incoming_threshold": 40, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + } + }, + { + "time_ms": 204, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 204, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/11_loop-setrule-outgoing-type-in.json b/cmd/loop/testdata/sessions/liquidity/11_loop-setrule-outgoing-type-in.json new file mode 100644 index 000000000..b3aa9cbde --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/11_loop-setrule-outgoing-type-in.json @@ -0,0 +1,176 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setrule", + "--network", + "regtest", + "--type", + "in", + "--outgoing_threshold", + "30", + "124244814135296" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "rpc error: code = Unknown desc = channel level rules not supported for loop in swaps, only peer-level rules allowed", + "duration": 212373344 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 168, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "125344325763072", + "swap_type": "LOOP_OUT", + "pubkey": "", + "type": "THRESHOLD", + "incoming_threshold": 40, + "outgoing_threshold": 0 + }, + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 168, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "125344325763072", + "swap_type": "LOOP_OUT", + "pubkey": "", + "type": "THRESHOLD", + "incoming_threshold": 40, + "outgoing_threshold": 0 + }, + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + }, + { + "channel_id": "124244814135296", + "swap_type": "LOOP_IN", + "pubkey": "", + "type": "THRESHOLD", + "incoming_threshold": 0, + "outgoing_threshold": 30 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + } + }, + { + "time_ms": 212, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "error", + "error": "rpc error: code = Unknown desc = channel level rules not supported for loop in swaps, only peer-level rules allowed" + } + }, + { + "time_ms": 212, + "kind": "stderr", + "data": { + "text": "[loop] rpc error: code = Unknown desc = channel level rules not supported for loop in swaps, only peer-level rules allowed\n" + } + }, + { + "time_ms": 212, + "kind": "exit", + "data": { + "run_error": "rpc error: code = Unknown desc = channel level rules not supported for loop in swaps, only peer-level rules allowed" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/12_loop-setrule-clear.json b/cmd/loop/testdata/sessions/liquidity/12_loop-setrule-clear.json new file mode 100644 index 000000000..2ca1602c5 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/12_loop-setrule-clear.json @@ -0,0 +1,148 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setrule", + "--network", + "regtest", + "--clear", + "125344325763072" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 232507711 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 150, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "125344325763072", + "swap_type": "LOOP_OUT", + "pubkey": "", + "type": "THRESHOLD", + "incoming_threshold": 40, + "outgoing_threshold": 0 + }, + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 150, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + } + }, + { + "time_ms": 231, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 232, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/13_loop-setparams-many-flags-error.json b/cmd/loop/testdata/sessions/liquidity/13_loop-setparams-many-flags-error.json new file mode 100644 index 000000000..ca28c2231 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/13_loop-setparams-many-flags-error.json @@ -0,0 +1,182 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest", + "--maxswapfee", + "0.1", + "--maxroutingfee", + "0.1", + "--maxprepayfee", + "0.1", + "--maxprepay", + "1000", + "--maxminer", + "1000", + "--sweepconf", + "10", + "--failurebackoff", + "60", + "--autoloop", + "--autobudget", + "1000", + "--autobudgetrefreshperiod", + "1h", + "--autoinflight", + "2", + "--minamt", + "1000", + "--maxamt", + "200000", + "--htlc_conf", + "2", + "--easyautoloop", + "--localbalancesat", + "1000000", + "--easyautoloop_excludepeer", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7", + "--fast" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "rpc error: code = Unknown desc = sweep fee rate limit must be \u003e 1 sat/vByte", + "duration": 325173938 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 276, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 276, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "1000", + "max_swap_amount": "200000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [ + "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3" + ] + } + } + } + }, + { + "time_ms": 324, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "error", + "error": "rpc error: code = Unknown desc = sweep fee rate limit must be \u003e 1 sat/vByte" + } + }, + { + "time_ms": 325, + "kind": "stderr", + "data": { + "text": "[loop] rpc error: code = Unknown desc = sweep fee rate limit must be \u003e 1 sat/vByte\n" + } + }, + { + "time_ms": 325, + "kind": "exit", + "data": { + "run_error": "rpc error: code = Unknown desc = sweep fee rate limit must be \u003e 1 sat/vByte" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/14_loop-setparams-many-flags-error-minamt.json b/cmd/loop/testdata/sessions/liquidity/14_loop-setparams-many-flags-error-minamt.json new file mode 100644 index 000000000..af94073ee --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/14_loop-setparams-many-flags-error-minamt.json @@ -0,0 +1,184 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest", + "--sweeplimit", + "2", + "--maxswapfee", + "0.1", + "--maxroutingfee", + "0.1", + "--maxprepayfee", + "0.1", + "--maxprepay", + "1000", + "--maxminer", + "1000", + "--sweepconf", + "10", + "--failurebackoff", + "60", + "--autoloop", + "--autobudget", + "1000", + "--autobudgetrefreshperiod", + "1h", + "--autoinflight", + "2", + "--minamt", + "1000", + "--maxamt", + "200000", + "--htlc_conf", + "2", + "--easyautoloop", + "--localbalancesat", + "1000000", + "--easyautoloop_excludepeer", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7", + "--fast" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "rpc error: code = Unknown desc = minimum swap amount is less than server minimum", + "duration": 273083406 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 191, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 191, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "1000", + "max_swap_amount": "200000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [ + "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3" + ] + } + } + } + }, + { + "time_ms": 272, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "error", + "error": "rpc error: code = Unknown desc = minimum swap amount is less than server minimum" + } + }, + { + "time_ms": 272, + "kind": "stderr", + "data": { + "text": "[loop] rpc error: code = Unknown desc = minimum swap amount is less than server minimum\n" + } + }, + { + "time_ms": 273, + "kind": "exit", + "data": { + "run_error": "rpc error: code = Unknown desc = minimum swap amount is less than server minimum" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/15_loop-setparams-many-flags.json b/cmd/loop/testdata/sessions/liquidity/15_loop-setparams-many-flags.json new file mode 100644 index 000000000..9efb4226d --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/15_loop-setparams-many-flags.json @@ -0,0 +1,175 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest", + "--sweeplimit", + "2", + "--maxswapfee", + "0.1", + "--maxroutingfee", + "0.1", + "--maxprepayfee", + "0.1", + "--maxprepay", + "1000", + "--maxminer", + "1000", + "--sweepconf", + "10", + "--failurebackoff", + "60", + "--autoloop", + "--autobudget", + "1000", + "--autobudgetrefreshperiod", + "1h", + "--autoinflight", + "2", + "--minamt", + "500000", + "--maxamt", + "1000000", + "--htlc_conf", + "2", + "--easyautoloop", + "--localbalancesat", + "1000000", + "--easyautoloop_excludepeer", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7", + "--fast" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 184771728 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 160, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "20000", + "sweep_fee_rate_sat_per_vbyte": "0", + "max_swap_fee_ppm": "0", + "max_routing_fee_ppm": "0", + "max_prepay_routing_fee_ppm": "0", + "max_prepay_sat": "0", + "max_miner_fee_sat": "0", + "sweep_conf_target": 100, + "failure_backoff_sec": "86400", + "autoloop": false, + "autoloop_budget_sat": "335544", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "1", + "min_swap_amount": "0", + "max_swap_amount": "0", + "htlc_conf_target": 6, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "604800", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": false, + "easy_autoloop_local_target_sat": "0", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 161, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [ + "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3" + ] + } + } + } + }, + { + "time_ms": 182, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 184, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/16_loop-setparams-destaddr.json b/cmd/loop/testdata/sessions/liquidity/16_loop-setparams-destaddr.json new file mode 100644 index 000000000..9f55fc39a --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/16_loop-setparams-destaddr.json @@ -0,0 +1,144 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest", + "--destaddr", + "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 235471909 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 223, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [ + "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3" + ] + } + } + }, + { + "time_ms": 224, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [ + "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3" + ] + } + } + } + }, + { + "time_ms": 234, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 235, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/17_loop-setparams-account.json b/cmd/loop/testdata/sessions/liquidity/17_loop-setparams-account.json new file mode 100644 index 000000000..d86852036 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/17_loop-setparams-account.json @@ -0,0 +1,146 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest", + "--account", + "default", + "--account_addr_type", + "p2tr" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 264493138 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 249, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "", + "account_addr_type": "ADDRESS_TYPE_UNKNOWN", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [ + "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3" + ] + } + } + }, + { + "time_ms": 250, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "default", + "account_addr_type": "TAPROOT_PUBKEY", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [ + "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3" + ] + } + } + } + }, + { + "time_ms": 264, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 264, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/18_loop-setparams-includeallpeers.json b/cmd/loop/testdata/sessions/liquidity/18_loop-setparams-includeallpeers.json new file mode 100644 index 000000000..b221c3086 --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/18_loop-setparams-includeallpeers.json @@ -0,0 +1,141 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setparams", + "--network", + "regtest", + "--easyatutoloop_includeallpeers" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 304215261 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 263, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "default", + "account_addr_type": "TAPROOT_PUBKEY", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [ + "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3" + ] + } + } + }, + { + "time_ms": 271, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770076824", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "default", + "account_addr_type": "TAPROOT_PUBKEY", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + } + }, + { + "time_ms": 303, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 304, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/liquidity/19_loop-setrule-type-out.json b/cmd/loop/testdata/sessions/liquidity/19_loop-setrule-type-out.json new file mode 100644 index 000000000..c7ac8f8ae --- /dev/null +++ b/cmd/loop/testdata/sessions/liquidity/19_loop-setrule-type-out.json @@ -0,0 +1,151 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "setrule", + "--network", + "regtest", + "--type", + "out", + "--incoming_threshold", + "20", + "125344325763072" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 195037901 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "request", + "message_type": "looprpc.GetLiquidityParamsRequest", + "payload": {} + } + }, + { + "time_ms": 137, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLiquidityParams", + "event": "response", + "message_type": "looprpc.LiquidityParameters", + "payload": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770092424", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "default", + "account_addr_type": "TAPROOT_PUBKEY", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + }, + { + "time_ms": 137, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "request", + "message_type": "looprpc.SetLiquidityParamsRequest", + "payload": { + "parameters": { + "rules": [ + { + "channel_id": "0", + "swap_type": "LOOP_OUT", + "pubkey": "A0+ogC/cn4wTfo8szi5NMOWQoTFOFr0GCsfXctxpj/S8", + "type": "THRESHOLD", + "incoming_threshold": 10, + "outgoing_threshold": 0 + }, + { + "channel_id": "125344325763072", + "swap_type": "LOOP_OUT", + "pubkey": "", + "type": "THRESHOLD", + "incoming_threshold": 20, + "outgoing_threshold": 0 + } + ], + "fee_ppm": "0", + "sweep_fee_rate_sat_per_vbyte": "2", + "max_swap_fee_ppm": "1000", + "max_routing_fee_ppm": "1000", + "max_prepay_routing_fee_ppm": "1000", + "max_prepay_sat": "1000", + "max_miner_fee_sat": "1000", + "sweep_conf_target": 10, + "failure_backoff_sec": "60", + "autoloop": true, + "autoloop_budget_sat": "1000", + "autoloop_budget_start_sec": "0", + "auto_max_in_flight": "2", + "min_swap_amount": "500000", + "max_swap_amount": "1000000", + "htlc_conf_target": 2, + "autoloop_dest_address": "", + "autoloop_budget_refresh_period_sec": "3600", + "autoloop_budget_last_refresh": "1770092424", + "easy_autoloop": true, + "easy_autoloop_local_target_sat": "1000000", + "account": "default", + "account_addr_type": "TAPROOT_PUBKEY", + "easy_asset_params": {}, + "fast_swap_publication": true, + "easy_autoloop_excluded_peers": [] + } + } + } + }, + { + "time_ms": 194, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SetLiquidityParams", + "event": "response", + "message_type": "looprpc.SetLiquidityParamsResponse", + "payload": {} + } + }, + { + "time_ms": 195, + "kind": "exit", + "data": {} + } + ] +} From 763c480ac29b3ba0a2456655529a47224ae93a96 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Tue, 3 Feb 2026 00:58:09 -0500 Subject: [PATCH 15/15] testdata: add static address and swaps sessions --- ...01_loop-static-listdeposits-deposited.json | 57 ++++++ ..._loop-static-listdeposits-withdrawing.json | 67 +++++++ ...03_loop-static-listdeposits-withdrawn.json | 94 +++++++++ ...4_loop-static-listdeposits-looping_in.json | 57 ++++++ ...05_loop-static-listdeposits-looped_in.json | 67 +++++++ ...-listdeposits-publish_expired_deposit.json | 57 ++++++ ...tatic-listdeposits-sweep_htlc_timeout.json | 57 ++++++ ...tatic-listdeposits-htlc_timeout_swept.json | 57 ++++++ ...ic-listdeposits-wait_for_expiry_sweep.json | 57 ++++++ .../10_loop-static-listdeposits-expired.json | 57 ++++++ .../11_loop-static-listdeposits-failed.json | 112 +++++++++++ .../static-loop-in/01_loop-static-new.json | 67 +++++++ .../static-loop-in/04_loop-static.json | 34 ++++ .../05_loop-static-listunspent.json | 60 ++++++ .../static-loop-in/06_loop-static-l.json | 60 ++++++ .../07_loop-static-listdeposits.json | 53 ++++++ .../08_loop-static-listunspent.json | 60 ++++++ .../09_loop-static-listunspent.json | 60 ++++++ .../10_loop-static-listdeposits.json | 63 ++++++ .../11_loop-static-summary.json | 58 ++++++ .../static-loop-in/12_loop-static-in.json | 66 +++++++ .../static-loop-in/13_loop-static-in.json | 100 ++++++++++ .../static-loop-in/14_loop-static-in.json | 106 +++++++++++ .../static-loop-in/15_loop-static-in.json | 179 ++++++++++++++++++ ...16_loop-static-in-duplicate-outpoints.json | 72 +++++++ .../17_loop-static-in-positional-low-amt.json | 105 ++++++++++ ...-static-in-positional-payment-timeout.json | 166 ++++++++++++++++ .../19_loop-static-in-all-cancel.json | 123 ++++++++++++ .../01_loop-static-withdraw-no-selection.json | 33 ++++ .../02_loop-static-listwithdrawals.json | 71 +++++++ .../static/03_loop-static-listswaps.json | 52 +++++ .../04_loop-static-withdraw-invalid-utxo.json | 35 ++++ .../static/05_loop-static-withdraw-all.json | 60 ++++++ ...06_loop-static-withdraw-utxo-destaddr.json | 69 +++++++ .../sessions/swaps/01_loop-listswaps.json | 84 ++++++++ .../sessions/swaps/02_loop-swapinfo.json | 71 +++++++ .../sessions/swaps/03_loop-abandonswap.json | 29 +++ ...04_loop-listswaps-conflicting-filters.json | 34 ++++ .../swaps/05_loop-swapinfo-invalid-id.json | 33 ++++ .../swaps/06_loop-abandonswap-invalid-id.json | 34 ++++ .../07_loop-listswaps-loop-out-filtered.json | 76 ++++++++ .../swaps/08_loop-listswaps-loop-in-only.json | 64 +++++++ .../09_loop-swapinfo-id-flag-parse-error.json | 34 ++++ .../swaps/10_loop-swapinfo-id-flag.json | 34 ++++ .../swaps/11_loop-abandonswap-success.json | 54 ++++++ 45 files changed, 3038 insertions(+) create mode 100644 cmd/loop/testdata/sessions/static-filters/01_loop-static-listdeposits-deposited.json create mode 100644 cmd/loop/testdata/sessions/static-filters/02_loop-static-listdeposits-withdrawing.json create mode 100644 cmd/loop/testdata/sessions/static-filters/03_loop-static-listdeposits-withdrawn.json create mode 100644 cmd/loop/testdata/sessions/static-filters/04_loop-static-listdeposits-looping_in.json create mode 100644 cmd/loop/testdata/sessions/static-filters/05_loop-static-listdeposits-looped_in.json create mode 100644 cmd/loop/testdata/sessions/static-filters/06_loop-static-listdeposits-publish_expired_deposit.json create mode 100644 cmd/loop/testdata/sessions/static-filters/07_loop-static-listdeposits-sweep_htlc_timeout.json create mode 100644 cmd/loop/testdata/sessions/static-filters/08_loop-static-listdeposits-htlc_timeout_swept.json create mode 100644 cmd/loop/testdata/sessions/static-filters/09_loop-static-listdeposits-wait_for_expiry_sweep.json create mode 100644 cmd/loop/testdata/sessions/static-filters/10_loop-static-listdeposits-expired.json create mode 100644 cmd/loop/testdata/sessions/static-filters/11_loop-static-listdeposits-failed.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/01_loop-static-new.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/04_loop-static.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/05_loop-static-listunspent.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/06_loop-static-l.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/07_loop-static-listdeposits.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/08_loop-static-listunspent.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/09_loop-static-listunspent.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/10_loop-static-listdeposits.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/11_loop-static-summary.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/12_loop-static-in.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/13_loop-static-in.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/14_loop-static-in.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/15_loop-static-in.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/16_loop-static-in-duplicate-outpoints.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/17_loop-static-in-positional-low-amt.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/18_loop-static-in-positional-payment-timeout.json create mode 100644 cmd/loop/testdata/sessions/static-loop-in/19_loop-static-in-all-cancel.json create mode 100644 cmd/loop/testdata/sessions/static/01_loop-static-withdraw-no-selection.json create mode 100644 cmd/loop/testdata/sessions/static/02_loop-static-listwithdrawals.json create mode 100644 cmd/loop/testdata/sessions/static/03_loop-static-listswaps.json create mode 100644 cmd/loop/testdata/sessions/static/04_loop-static-withdraw-invalid-utxo.json create mode 100644 cmd/loop/testdata/sessions/static/05_loop-static-withdraw-all.json create mode 100644 cmd/loop/testdata/sessions/static/06_loop-static-withdraw-utxo-destaddr.json create mode 100644 cmd/loop/testdata/sessions/swaps/01_loop-listswaps.json create mode 100644 cmd/loop/testdata/sessions/swaps/02_loop-swapinfo.json create mode 100644 cmd/loop/testdata/sessions/swaps/03_loop-abandonswap.json create mode 100644 cmd/loop/testdata/sessions/swaps/04_loop-listswaps-conflicting-filters.json create mode 100644 cmd/loop/testdata/sessions/swaps/05_loop-swapinfo-invalid-id.json create mode 100644 cmd/loop/testdata/sessions/swaps/06_loop-abandonswap-invalid-id.json create mode 100644 cmd/loop/testdata/sessions/swaps/07_loop-listswaps-loop-out-filtered.json create mode 100644 cmd/loop/testdata/sessions/swaps/08_loop-listswaps-loop-in-only.json create mode 100644 cmd/loop/testdata/sessions/swaps/09_loop-swapinfo-id-flag-parse-error.json create mode 100644 cmd/loop/testdata/sessions/swaps/10_loop-swapinfo-id-flag.json create mode 100644 cmd/loop/testdata/sessions/swaps/11_loop-abandonswap-success.json diff --git a/cmd/loop/testdata/sessions/static-filters/01_loop-static-listdeposits-deposited.json b/cmd/loop/testdata/sessions/static-filters/01_loop-static-listdeposits-deposited.json new file mode 100644 index 000000000..f2da3c340 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/01_loop-static-listdeposits-deposited.json @@ -0,0 +1,57 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "deposited" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 304503708 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "DEPOSITED", + "outpoints": [] + } + } + }, + { + "time_ms": 303, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [] + } + } + }, + { + "time_ms": 304, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": []\n}\n" + } + }, + { + "time_ms": 304, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/02_loop-static-listdeposits-withdrawing.json b/cmd/loop/testdata/sessions/static-filters/02_loop-static-listdeposits-withdrawing.json new file mode 100644 index 000000000..f206d3a74 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/02_loop-static-listdeposits-withdrawing.json @@ -0,0 +1,67 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "withdrawing" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 210052149 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "WITHDRAWING", + "outpoints": [] + } + } + }, + { + "time_ms": 209, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "u38FDfC3w+H+YQEOEK1F4w3fes0wH6bgWi3bgltcLvs=", + "state": "WITHDRAWING", + "outpoint": "56cd081a3a6eadf25b7d3fe0b61207389352ed69a622d2ec28c5d669bf6a5313:0", + "value": "500000", + "confirmation_height": "160", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 209, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": [\n {\n \"blocks_until_expiry\": \"14395\",\n \"confirmation_height\": \"160\",\n \"id\": \"bb7f050df0b7c3e1fe61010e10ad45e30ddf7acd301fa6e05a2ddb825b5c2efb\",\n \"outpoint\": \"56cd081a3a6eadf25b7d3fe0b61207389352ed69a622d2ec28c5d669bf6a5313:0\",\n \"state\": \"WITHDRAWING\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 210, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/03_loop-static-listdeposits-withdrawn.json b/cmd/loop/testdata/sessions/static-filters/03_loop-static-listdeposits-withdrawn.json new file mode 100644 index 000000000..0fc78be8a --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/03_loop-static-listdeposits-withdrawn.json @@ -0,0 +1,94 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "withdrawn" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 271219039 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "WITHDRAWN", + "outpoints": [] + } + } + }, + { + "time_ms": 269, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "aCYqEEyewyXea+w3uOMb2HW70vXwuc4togzwvWNvxEg=", + "state": "WITHDRAWN", + "outpoint": "edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0", + "value": "500000", + "confirmation_height": "125", + "blocks_until_expiry": "14360", + "swap_hash": "" + }, + { + "id": "hrXizflpTI5zmOQq/eEJdm180hQiA5Bbpj+9DrE3DvM=", + "state": "WITHDRAWN", + "outpoint": "bb358e4f73ae97c4e2d99c6d64e852bba7cf56e13105b05d1200b8ae1796665e:0", + "value": "500000", + "confirmation_height": "127", + "blocks_until_expiry": "14362", + "swap_hash": "" + }, + { + "id": "bCkPdTbqUJeUav/6xqaZBqJtd1gj67rO3+by1pwHReQ=", + "state": "WITHDRAWN", + "outpoint": "5eaa7dd7a291665393eddf5dece91feef901f22665933cce7a0732a9b81c3001:0", + "value": "500000", + "confirmation_height": "128", + "blocks_until_expiry": "14363", + "swap_hash": "" + }, + { + "id": "AYK02JWxxGcpCue1xsQv92sqQiWAepQhHJcxcNWog+s=", + "state": "WITHDRAWN", + "outpoint": "7e6360d6e6a394cfd096adf0bfe1275c5a83541eb573e90e463a78dc715f8894:0", + "value": "500000", + "confirmation_height": "142", + "blocks_until_expiry": "14377", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 269, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": [\n {\n \"blocks_until_expiry\": \"14360\",\n \"confirmation_height\": \"125\",\n \"id\": \"68262a104c9ec325de6bec37b8e31bd875bbd2f5f0b9ce2da20cf0bd636fc448\",\n \"outpoint\": \"edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0\",\n \"state\": \"WITHDRAWN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n },\n {\n \"blocks_until_expiry\": \"14362\",\n \"confirmation_height\": \"127\",\n \"id\": \"86b5e2cdf9694c8e7398e42afde109766d7cd2142203905ba63fbd0eb1370ef3\",\n \"outpoint\": \"bb358e4f73ae97c4e2d99c6d64e852bba7cf56e13105b05d1200b8ae1796665e:0\",\n \"state\": \"WITHDRAWN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n },\n {\n \"blocks_until_expiry\": \"14363\",\n \"confirmation_height\": \"128\",\n \"id\": \"6c290f7536ea5097946afffac6a69906a26d775823ebbacedfe6f2d69c0745e4\",\n \"outpoint\": \"5eaa7dd7a291665393eddf5dece91feef901f22665933cce7a0732a9b81c3001:0\",\n \"state\": \"WITHDRAWN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n },\n {\n \"blocks_until_expiry\": \"14377\",\n \"confirmation_height\": \"142\",\n \"id\": \"0182b4d895b1c467290ae7b5c6c42ff76b2a4225807a94211c973170d5a883eb\",\n \"outpoint\": \"7e6360d6e6a394cfd096adf0bfe1275c5a83541eb573e90e463a78dc715f8894:0\",\n \"state\": \"WITHDRAWN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 271, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/04_loop-static-listdeposits-looping_in.json b/cmd/loop/testdata/sessions/static-filters/04_loop-static-listdeposits-looping_in.json new file mode 100644 index 000000000..9fc1c947f --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/04_loop-static-listdeposits-looping_in.json @@ -0,0 +1,57 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "looping_in" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 268850770 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "LOOPING_IN", + "outpoints": [] + } + } + }, + { + "time_ms": 268, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [] + } + } + }, + { + "time_ms": 268, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": []\n}\n" + } + }, + { + "time_ms": 268, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/05_loop-static-listdeposits-looped_in.json b/cmd/loop/testdata/sessions/static-filters/05_loop-static-listdeposits-looped_in.json new file mode 100644 index 000000000..e9b3b1a91 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/05_loop-static-listdeposits-looped_in.json @@ -0,0 +1,67 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "looped_in" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 169458759 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "LOOPED_IN", + "outpoints": [] + } + } + }, + { + "time_ms": 168, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "j71tovlF3ikFqn+pOGB0TZOH00ZEhDYOluRnpR3jvJ0=", + "state": "LOOPED_IN", + "outpoint": "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0", + "value": "500000", + "confirmation_height": "148", + "blocks_until_expiry": "14383", + "swap_hash": "hDAjN0JANkGTlqt5ZN14uFsaSBqfHbc9tc3e5XwkQ+c=" + } + ] + } + } + }, + { + "time_ms": 168, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": [\n {\n \"blocks_until_expiry\": \"14383\",\n \"confirmation_height\": \"148\",\n \"id\": \"8fbd6da2f945de2905aa7fa93860744d9387d3464484360e96e467a51de3bc9d\",\n \"outpoint\": \"9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0\",\n \"state\": \"LOOPED_IN\",\n \"swap_hash\": \"84302337424036419396ab7964dd78b85b1a481a9f1db73db5cddee57c2443e7\",\n \"value\": \"500000\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 169, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/06_loop-static-listdeposits-publish_expired_deposit.json b/cmd/loop/testdata/sessions/static-filters/06_loop-static-listdeposits-publish_expired_deposit.json new file mode 100644 index 000000000..46288e057 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/06_loop-static-listdeposits-publish_expired_deposit.json @@ -0,0 +1,57 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "publish_expired_deposit" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 230057326 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "PUBLISH_EXPIRED", + "outpoints": [] + } + } + }, + { + "time_ms": 229, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [] + } + } + }, + { + "time_ms": 230, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": []\n}\n" + } + }, + { + "time_ms": 230, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/07_loop-static-listdeposits-sweep_htlc_timeout.json b/cmd/loop/testdata/sessions/static-filters/07_loop-static-listdeposits-sweep_htlc_timeout.json new file mode 100644 index 000000000..b9bf16959 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/07_loop-static-listdeposits-sweep_htlc_timeout.json @@ -0,0 +1,57 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "sweep_htlc_timeout" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 224559305 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "SWEEP_HTLC_TIMEOUT", + "outpoints": [] + } + } + }, + { + "time_ms": 223, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [] + } + } + }, + { + "time_ms": 224, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": []\n}\n" + } + }, + { + "time_ms": 224, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/08_loop-static-listdeposits-htlc_timeout_swept.json b/cmd/loop/testdata/sessions/static-filters/08_loop-static-listdeposits-htlc_timeout_swept.json new file mode 100644 index 000000000..0bdad0d5b --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/08_loop-static-listdeposits-htlc_timeout_swept.json @@ -0,0 +1,57 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "htlc_timeout_swept" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 211493641 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "HTLC_TIMEOUT_SWEPT", + "outpoints": [] + } + } + }, + { + "time_ms": 211, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [] + } + } + }, + { + "time_ms": 211, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": []\n}\n" + } + }, + { + "time_ms": 211, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/09_loop-static-listdeposits-wait_for_expiry_sweep.json b/cmd/loop/testdata/sessions/static-filters/09_loop-static-listdeposits-wait_for_expiry_sweep.json new file mode 100644 index 000000000..05a9dc450 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/09_loop-static-listdeposits-wait_for_expiry_sweep.json @@ -0,0 +1,57 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "wait_for_expiry_sweep" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 194966554 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "WAIT_FOR_EXPIRY_SWEEP", + "outpoints": [] + } + } + }, + { + "time_ms": 192, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [] + } + } + }, + { + "time_ms": 193, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": []\n}\n" + } + }, + { + "time_ms": 194, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/10_loop-static-listdeposits-expired.json b/cmd/loop/testdata/sessions/static-filters/10_loop-static-listdeposits-expired.json new file mode 100644 index 000000000..96495de8c --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/10_loop-static-listdeposits-expired.json @@ -0,0 +1,57 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "expired" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 224807103 + }, + "events": [ + { + "time_ms": 4, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "EXPIRED", + "outpoints": [] + } + } + }, + { + "time_ms": 224, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [] + } + } + }, + { + "time_ms": 224, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": []\n}\n" + } + }, + { + "time_ms": 224, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-filters/11_loop-static-listdeposits-failed.json b/cmd/loop/testdata/sessions/static-filters/11_loop-static-listdeposits-failed.json new file mode 100644 index 000000000..0212c1f4e --- /dev/null +++ b/cmd/loop/testdata/sessions/static-filters/11_loop-static-listdeposits-failed.json @@ -0,0 +1,112 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listdeposits", + "--network", + "regtest", + "--filter", + "failed" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 140385482 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "UNKNOWN_STATE", + "outpoints": [] + } + } + }, + { + "time_ms": 139, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "aCYqEEyewyXea+w3uOMb2HW70vXwuc4togzwvWNvxEg=", + "state": "WITHDRAWN", + "outpoint": "edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0", + "value": "500000", + "confirmation_height": "125", + "blocks_until_expiry": "14360", + "swap_hash": "" + }, + { + "id": "hrXizflpTI5zmOQq/eEJdm180hQiA5Bbpj+9DrE3DvM=", + "state": "WITHDRAWN", + "outpoint": "bb358e4f73ae97c4e2d99c6d64e852bba7cf56e13105b05d1200b8ae1796665e:0", + "value": "500000", + "confirmation_height": "127", + "blocks_until_expiry": "14362", + "swap_hash": "" + }, + { + "id": "bCkPdTbqUJeUav/6xqaZBqJtd1gj67rO3+by1pwHReQ=", + "state": "WITHDRAWN", + "outpoint": "5eaa7dd7a291665393eddf5dece91feef901f22665933cce7a0732a9b81c3001:0", + "value": "500000", + "confirmation_height": "128", + "blocks_until_expiry": "14363", + "swap_hash": "" + }, + { + "id": "AYK02JWxxGcpCue1xsQv92sqQiWAepQhHJcxcNWog+s=", + "state": "WITHDRAWN", + "outpoint": "7e6360d6e6a394cfd096adf0bfe1275c5a83541eb573e90e463a78dc715f8894:0", + "value": "500000", + "confirmation_height": "142", + "blocks_until_expiry": "14377", + "swap_hash": "" + }, + { + "id": "j71tovlF3ikFqn+pOGB0TZOH00ZEhDYOluRnpR3jvJ0=", + "state": "LOOPED_IN", + "outpoint": "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0", + "value": "500000", + "confirmation_height": "148", + "blocks_until_expiry": "14383", + "swap_hash": "hDAjN0JANkGTlqt5ZN14uFsaSBqfHbc9tc3e5XwkQ+c=" + }, + { + "id": "u38FDfC3w+H+YQEOEK1F4w3fes0wH6bgWi3bgltcLvs=", + "state": "WITHDRAWING", + "outpoint": "56cd081a3a6eadf25b7d3fe0b61207389352ed69a622d2ec28c5d669bf6a5313:0", + "value": "500000", + "confirmation_height": "160", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 139, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": [\n {\n \"blocks_until_expiry\": \"14360\",\n \"confirmation_height\": \"125\",\n \"id\": \"68262a104c9ec325de6bec37b8e31bd875bbd2f5f0b9ce2da20cf0bd636fc448\",\n \"outpoint\": \"edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0\",\n \"state\": \"WITHDRAWN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n },\n {\n \"blocks_until_expiry\": \"14362\",\n \"confirmation_height\": \"127\",\n \"id\": \"86b5e2cdf9694c8e7398e42afde109766d7cd2142203905ba63fbd0eb1370ef3\",\n \"outpoint\": \"bb358e4f73ae97c4e2d99c6d64e852bba7cf56e13105b05d1200b8ae1796665e:0\",\n \"state\": \"WITHDRAWN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n },\n {\n \"blocks_until_expiry\": \"14363\",\n \"confirmation_height\": \"128\",\n \"id\": \"6c290f7536ea5097946afffac6a69906a26d775823ebbacedfe6f2d69c0745e4\",\n \"outpoint\": \"5eaa7dd7a291665393eddf5dece91feef901f22665933cce7a0732a9b81c3001:0\",\n \"state\": \"WITHDRAWN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n },\n {\n \"blocks_until_expiry\": \"14377\",\n \"confirmation_height\": \"142\",\n \"id\": \"0182b4d895b1c467290ae7b5c6c42ff76b2a4225807a94211c973170d5a883eb\",\n \"outpoint\": \"7e6360d6e6a394cfd096adf0bfe1275c5a83541eb573e90e463a78dc715f8894:0\",\n \"state\": \"WITHDRAWN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n },\n {\n \"blocks_until_expiry\": \"14383\",\n \"confirmation_height\": \"148\",\n \"id\": \"8fbd6da2f945de2905aa7fa93860744d9387d3464484360e96e467a51de3bc9d\",\n \"outpoint\": \"9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0\",\n \"state\": \"LOOPED_IN\",\n \"swap_hash\": \"84302337424036419396ab7964dd78b85b1a481a9f1db73db5cddee57c2443e7\",\n \"value\": \"500000\"\n },\n {\n \"blocks_until_expiry\": \"14395\",\n \"confirmation_height\": \"160\",\n \"id\": \"bb7f050df0b7c3e1fe61010e10ad45e30ddf7acd301fa6e05a2ddb825b5c2efb\",\n \"outpoint\": \"56cd081a3a6eadf25b7d3fe0b61207389352ed69a622d2ec28c5d669bf6a5313:0\",\n \"state\": \"WITHDRAWING\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 140, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/01_loop-static-new.json b/cmd/loop/testdata/sessions/static-loop-in/01_loop-static-new.json new file mode 100644 index 000000000..15b0b17f8 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/01_loop-static-new.json @@ -0,0 +1,67 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "new", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 2871791649 + }, + "events": [ + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "\nWARNING: Be aware that loosing your l402.token file in .loop under your home directory will take your ability to spend funds sent to the static address via loop-ins or withdrawals. You will have to wait until the deposit expires and your loop client sweeps the funds back to your lnd wallet. The deposit expiry could be months in the future.\n\nCONTINUE WITH NEW ADDRESS? (y/n): " + } + }, + { + "time_ms": 2685, + "kind": "stdin", + "data": { + "text": "y\n" + } + }, + { + "time_ms": 2686, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/NewStaticAddress", + "event": "request", + "message_type": "looprpc.NewStaticAddressRequest", + "payload": { + "client_key": "" + } + } + }, + { + "time_ms": 2868, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/NewStaticAddress", + "event": "response", + "message_type": "looprpc.NewStaticAddressResponse", + "payload": { + "address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "expiry": 14400 + } + } + }, + { + "time_ms": 2869, + "kind": "stdout", + "data": { + "text": "{\n \"address\": \"bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw\",\n \"expiry\": 14400\n}\n" + } + }, + { + "time_ms": 2871, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/04_loop-static.json b/cmd/loop/testdata/sessions/static-loop-in/04_loop-static.json new file mode 100644 index 000000000..2c7883042 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/04_loop-static.json @@ -0,0 +1,34 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 2504188 + }, + "events": [ + { + "time_ms": 2, + "kind": "stdout", + "data": { + "text": "NAME:\n loop static - perform on-chain to off-chain swaps using static addresses.\n\nUSAGE:\n loop static [command [command options]]\n\nCOMMANDS:\n new, n Create a new static loop in address.\n listunspent, l List unspent static address outputs.\n listdeposits Displays static address deposits. A filter can be applied to only show deposits in a specific state.\n listwithdrawals Display a summary of past withdrawals.\n listswaps Shows a list of finalized static address swaps.\n withdraw, w Withdraw from static address deposits.\n summary, s Display a summary of static address related information.\n in Loop in funds from static address deposits.\n\n" + } + }, + { + "time_ms": 2, + "kind": "stdout", + "data": { + "text": "OPTIONS:\n --help, -h show help\n" + } + }, + { + "time_ms": 2, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/05_loop-static-listunspent.json b/cmd/loop/testdata/sessions/static-loop-in/05_loop-static-listunspent.json new file mode 100644 index 000000000..b4fd71186 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/05_loop-static-listunspent.json @@ -0,0 +1,60 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "listunspent", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 22853293 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListUnspentDeposits", + "event": "request", + "message_type": "looprpc.ListUnspentDepositsRequest", + "payload": { + "min_confs": 0, + "max_confs": 0 + } + } + }, + { + "time_ms": 22, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListUnspentDeposits", + "event": "response", + "message_type": "looprpc.ListUnspentDepositsResponse", + "payload": { + "utxos": [ + { + "static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "amount_sat": "2500000", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "confirmations": "0" + } + ] + } + } + }, + { + "time_ms": 22, + "kind": "stdout", + "data": { + "text": "{\n \"utxos\": [\n {\n \"amount_sat\": \"2500000\",\n \"confirmations\": \"0\",\n \"outpoint\": \"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0\",\n \"static_address\": \"bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 22, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/06_loop-static-l.json b/cmd/loop/testdata/sessions/static-loop-in/06_loop-static-l.json new file mode 100644 index 000000000..49e3bf1a4 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/06_loop-static-l.json @@ -0,0 +1,60 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "l", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 17567260 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListUnspentDeposits", + "event": "request", + "message_type": "looprpc.ListUnspentDepositsRequest", + "payload": { + "min_confs": 0, + "max_confs": 0 + } + } + }, + { + "time_ms": 14, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListUnspentDeposits", + "event": "response", + "message_type": "looprpc.ListUnspentDepositsResponse", + "payload": { + "utxos": [ + { + "static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "amount_sat": "2500000", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "confirmations": "0" + } + ] + } + } + }, + { + "time_ms": 14, + "kind": "stdout", + "data": { + "text": "{\n \"utxos\": [\n {\n \"amount_sat\": \"2500000\",\n \"confirmations\": \"0\",\n \"outpoint\": \"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0\",\n \"static_address\": \"bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 17, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/07_loop-static-listdeposits.json b/cmd/loop/testdata/sessions/static-loop-in/07_loop-static-listdeposits.json new file mode 100644 index 000000000..efe48000b --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/07_loop-static-listdeposits.json @@ -0,0 +1,53 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "listdeposits", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 20668519 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "UNKNOWN_STATE", + "outpoints": [] + } + } + }, + { + "time_ms": 19, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [] + } + } + }, + { + "time_ms": 19, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": []\n}\n" + } + }, + { + "time_ms": 20, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/08_loop-static-listunspent.json b/cmd/loop/testdata/sessions/static-loop-in/08_loop-static-listunspent.json new file mode 100644 index 000000000..09516c28d --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/08_loop-static-listunspent.json @@ -0,0 +1,60 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "listunspent", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 20894580 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListUnspentDeposits", + "event": "request", + "message_type": "looprpc.ListUnspentDepositsRequest", + "payload": { + "min_confs": 0, + "max_confs": 0 + } + } + }, + { + "time_ms": 20, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListUnspentDeposits", + "event": "response", + "message_type": "looprpc.ListUnspentDepositsResponse", + "payload": { + "utxos": [ + { + "static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "amount_sat": "2500000", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "confirmations": "1" + } + ] + } + } + }, + { + "time_ms": 20, + "kind": "stdout", + "data": { + "text": "{\n \"utxos\": [\n {\n \"amount_sat\": \"2500000\",\n \"confirmations\": \"1\",\n \"outpoint\": \"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0\",\n \"static_address\": \"bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 20, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/09_loop-static-listunspent.json b/cmd/loop/testdata/sessions/static-loop-in/09_loop-static-listunspent.json new file mode 100644 index 000000000..25661a87a --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/09_loop-static-listunspent.json @@ -0,0 +1,60 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "listunspent", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 11659340 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListUnspentDeposits", + "event": "request", + "message_type": "looprpc.ListUnspentDepositsRequest", + "payload": { + "min_confs": 0, + "max_confs": 0 + } + } + }, + { + "time_ms": 9, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListUnspentDeposits", + "event": "response", + "message_type": "looprpc.ListUnspentDepositsResponse", + "payload": { + "utxos": [ + { + "static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "amount_sat": "2500000", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "confirmations": "6" + } + ] + } + } + }, + { + "time_ms": 11, + "kind": "stdout", + "data": { + "text": "{\n \"utxos\": [\n {\n \"amount_sat\": \"2500000\",\n \"confirmations\": \"6\",\n \"outpoint\": \"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0\",\n \"static_address\": \"bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 11, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/10_loop-static-listdeposits.json b/cmd/loop/testdata/sessions/static-loop-in/10_loop-static-listdeposits.json new file mode 100644 index 000000000..576edd011 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/10_loop-static-listdeposits.json @@ -0,0 +1,63 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "listdeposits", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 18981734 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "UNKNOWN_STATE", + "outpoints": [] + } + } + }, + { + "time_ms": 18, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "6mq78FccC6ghF66fIIZhTqzqiykT3AVEtwwA3ng1PnE=", + "state": "DEPOSITED", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "value": "2500000", + "confirmation_height": "131", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 18, + "kind": "stdout", + "data": { + "text": "{\n \"filtered_deposits\": [\n {\n \"blocks_until_expiry\": \"14395\",\n \"confirmation_height\": \"131\",\n \"id\": \"ea6abbf0571c0ba82117ae9f2086614eacea8b2913dc0544b70c00de78353e71\",\n \"outpoint\": \"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0\",\n \"state\": \"DEPOSITED\",\n \"swap_hash\": \"\",\n \"value\": \"2500000\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 18, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/11_loop-static-summary.json b/cmd/loop/testdata/sessions/static-loop-in/11_loop-static-summary.json new file mode 100644 index 000000000..ffe85b6f7 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/11_loop-static-summary.json @@ -0,0 +1,58 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "summary", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 16058920 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetStaticAddressSummary", + "event": "request", + "message_type": "looprpc.StaticAddressSummaryRequest", + "payload": {} + } + }, + { + "time_ms": 15, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetStaticAddressSummary", + "event": "response", + "message_type": "looprpc.StaticAddressSummaryResponse", + "payload": { + "static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "relative_expiry_blocks": "14400", + "total_num_deposits": 1, + "value_unconfirmed_satoshis": "0", + "value_deposited_satoshis": "2500000", + "value_expired_satoshis": "0", + "value_withdrawn_satoshis": "0", + "value_looped_in_satoshis": "0", + "value_htlc_timeout_sweeps_satoshis": "0" + } + } + }, + { + "time_ms": 15, + "kind": "stdout", + "data": { + "text": "{\n \"relative_expiry_blocks\": \"14400\",\n \"static_address\": \"bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw\",\n \"total_num_deposits\": 1,\n \"value_deposited_satoshis\": \"2500000\",\n \"value_expired_satoshis\": \"0\",\n \"value_htlc_timeout_sweeps_satoshis\": \"0\",\n \"value_looped_in_satoshis\": \"0\",\n \"value_unconfirmed_satoshis\": \"0\",\n \"value_withdrawn_satoshis\": \"0\"\n}\n" + } + }, + { + "time_ms": 16, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/12_loop-static-in.json b/cmd/loop/testdata/sessions/static-loop-in/12_loop-static-in.json new file mode 100644 index 000000000..9c07182ce --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/12_loop-static-in.json @@ -0,0 +1,66 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "in", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "run_error": "unknown quote request", + "duration": 12090944 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "DEPOSITED", + "outpoints": [] + } + } + }, + { + "time_ms": 11, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "6mq78FccC6ghF66fIIZhTqzqiykT3AVEtwwA3ng1PnE=", + "state": "DEPOSITED", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "value": "2500000", + "confirmation_height": "131", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 12, + "kind": "stderr", + "data": { + "text": "[loop] unknown quote request\n" + } + }, + { + "time_ms": 12, + "kind": "exit", + "data": { + "run_error": "unknown quote request" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/13_loop-static-in.json b/cmd/loop/testdata/sessions/static-loop-in/13_loop-static-in.json new file mode 100644 index 000000000..b13589df6 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/13_loop-static-in.json @@ -0,0 +1,100 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "in", + "--all", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "run_error": "rpc error: code = Unknown desc = swap amount too high", + "duration": 29949728 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "DEPOSITED", + "outpoints": [] + } + } + }, + { + "time_ms": 19, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "6mq78FccC6ghF66fIIZhTqzqiykT3AVEtwwA3ng1PnE=", + "state": "DEPOSITED", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "value": "2500000", + "confirmation_height": "131", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 19, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "0", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [ + "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0" + ], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 29, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "error", + "error": "rpc error: code = Unknown desc = swap amount too high" + } + }, + { + "time_ms": 29, + "kind": "stderr", + "data": { + "text": "[loop] rpc error: code = Unknown desc = swap amount too high\n" + } + }, + { + "time_ms": 29, + "kind": "exit", + "data": { + "run_error": "rpc error: code = Unknown desc = swap amount too high" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/14_loop-static-in.json b/cmd/loop/testdata/sessions/static-loop-in/14_loop-static-in.json new file mode 100644 index 000000000..1830c301a --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/14_loop-static-in.json @@ -0,0 +1,106 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "in", + "--help", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 2400415 + }, + "events": [ + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "NAME:\n" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " loop static in - Loop in funds from static address deposits." + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "\n\nUSAGE:\n" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " loop static in [options] [amt] [--all | --utxo xxx:xx]\n\nDESCRIPTION:\n " + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "\n Requests a loop-in swap based on static address deposits. After the\n creation of a static address funds can be sent to it. Once the funds are\n " + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " confirmed on-chain they can be swapped instantaneously. If deposited\n funds are not needed they can we withdrawn back to the local lnd wallet.\n \n\nOPTIONS:\n" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " --utxo string [ --utxo string ] specify the utxos of deposits as outpoints(tx:idx) that should be looped in.\n --all loop in all static address deposits. (default: false)\n --payment_timeout duration " + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " the maximum time in seconds that the server is allowed to take for the swap payment. The client can retry the swap with adjusted parameters after the payment timed out. (default: 0s)\n --amt uint, --amount uint the number of satoshis that should be swapped from the selected deposits. If thereis change it is sent back to the static address. (default: 0)\n --fast Usage: complete the swap faster by paying a higher fee, so the change output is available sooner (default: false)\n --last_hop string the pubkey of the last hop to use for this swap\n --label string an optional label for this swap,limited to 500 characters. The label may not start with our reserved prefix: [reserved].\n --route_hints string [ --route_hints string ]" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " route hints that can each be individually used to assist in reaching the invoice's destination\n --private generates and passes routehints. Should be used if the connected node is only reachable via private channels (default: false)\n --force Assumes yes during confirmation. Using this option will result in an immediate swap (default: false)\n --verbose, -v show expanded details (default: false)\n --help, -h show help\n\n" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "GLOBAL OPTIONS:\n --rpcserver string " + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "loopd daemon address host:port (default: \"localhost:11010\") [$LOOPCLI_RPCSERVER]\n --network string, -n string the network loop is running on e.g. mainnet, testnet, etc. (default: \"mainnet\") [$LOOPCLI_NETWORK]\n --loopdir string path to loop's base directory (default: ~/.loop) [$LOOPCLI_LOOPDIR]\n --tlscertpath string" + } + }, + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": " path to loop's TLS certificate (default: ~/.loop/mainnet/tls.cert) [$LOOPCLI_TLSCERTPATH]\n --macaroonpath string path to macaroon file (default: ~/.loop/mainnet/loop.macaroon) [$LOOPCLI_MACAROONPATH]\n" + } + }, + { + "time_ms": 2, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/15_loop-static-in.json b/cmd/loop/testdata/sessions/static-loop-in/15_loop-static-in.json new file mode 100644 index 000000000..477b9c489 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/15_loop-static-in.json @@ -0,0 +1,179 @@ +{ + "metadata": { + "args": [ + "loop", + "static", + "in", + "--amt", + "500000", + "--all", + "--network", + "regtest" + ], + "env": {}, + "version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6", + "duration": 2826015164 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "DEPOSITED", + "outpoints": [] + } + } + }, + { + "time_ms": 22, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "6mq78FccC6ghF66fIIZhTqzqiykT3AVEtwwA3ng1PnE=", + "state": "DEPOSITED", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "value": "2500000", + "confirmation_height": "131", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 22, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [ + "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0" + ], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 65, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1824", + "htlc_publish_fee_sat": "0", + "cltv_delta": 0, + "conf_target": 0, + "quoted_amt": "500000" + } + } + }, + { + "time_ms": 65, + "kind": "stdout", + "data": { + "text": "On-chain fees for static address loop-ins are not included.\nThey were already paid when the deposits were created.\n\nPreviously deposited on-chain: 500000 sat\nReceive off-chain: 498176 sat\nEstimated total fee: 1824 sat\n\nCONTINUE SWAP? (y/n): " + } + }, + { + "time_ms": 2358, + "kind": "stdin", + "data": { + "text": "y\n" + } + }, + { + "time_ms": 2358, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/StaticAddressLoopIn", + "event": "request", + "message_type": "looprpc.StaticAddressLoopInRequest", + "payload": { + "outpoints": [ + "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0" + ], + "max_swap_fee_satoshis": "1824", + "last_hop": "", + "label": "", + "initiator": "loop-cli", + "route_hints": [], + "private": false, + "payment_timeout_seconds": 60, + "amount": "500000", + "fast": false + } + } + }, + { + "time_ms": 2824, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/StaticAddressLoopIn", + "event": "response", + "message_type": "looprpc.StaticAddressLoopInResponse", + "payload": { + "swap_hash": "nxn7UEKl3m2i8c4YPF4iT9eALbQI6a/dWY7oF0srzj8=", + "state": "SignHtlcTx", + "amount": "2500000", + "htlc_cltv": 1136, + "quoted_swap_fee_satoshis": "1824", + "max_swap_fee_satoshis": "1824", + "initiation_height": 136, + "protocol_version": "V0", + "label": "", + "initiator": "loop-cli", + "payment_timeout_seconds": 60, + "used_deposits": [ + { + "id": "6mq78FccC6ghF66fIIZhTqzqiykT3AVEtwwA3ng1PnE=", + "state": "LOOPING_IN", + "outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0", + "value": "2500000", + "confirmation_height": "131", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ], + "swap_amount": "500000", + "change": "2000000", + "fast": false + } + } + }, + { + "time_ms": 2825, + "kind": "stdout", + "data": { + "text": "{\n \"amount\": \"2500000\",\n \"change\": \"2000000\",\n \"fast\": false,\n \"htlc_cltv\": 1136,\n \"initiation_height\": 136,\n \"initiator\": \"loop-cli\",\n \"label\": \"\",\n \"max_swap_fee_satoshis\": \"1824\",\n \"payment_timeout_seconds\": 60,\n \"protocol_version\": \"V0\",\n \"quoted_swap_fee_satoshis\": \"1824\",\n \"state\": \"SignHtlcTx\",\n \"swap_amount\": \"500000\",\n \"swap_hash\": \"9f19fb5042a5de6da2f1ce183c5e224fd7802db408e9afdd598ee8174b2bce3f\",\n \"used_deposits\": [\n {\n \"blocks_until_expiry\": \"14395\",\n \"confirmation_height\": \"131\",\n \"id\": \"ea6abbf0571c0ba82117ae9f2086614eacea8b2913dc0544b70c00de78353e71\",\n \"outpoint\": \"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0\",\n \"state\": \"LOOPING_IN\",\n \"swap_hash\": \"\",\n \"value\": \"2500000\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 2826, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/16_loop-static-in-duplicate-outpoints.json b/cmd/loop/testdata/sessions/static-loop-in/16_loop-static-in-duplicate-outpoints.json new file mode 100644 index 000000000..e510c4f6e --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/16_loop-static-in-duplicate-outpoints.json @@ -0,0 +1,72 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "in", + "--utxo", + "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0", + "--utxo", + "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "duplicate outpoints detected", + "duration": 174401375 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "DEPOSITED", + "outpoints": [] + } + } + }, + { + "time_ms": 173, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "j71tovlF3ikFqn+pOGB0TZOH00ZEhDYOluRnpR3jvJ0=", + "state": "DEPOSITED", + "outpoint": "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0", + "value": "500000", + "confirmation_height": "148", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 174, + "kind": "stderr", + "data": { + "text": "[loop] duplicate outpoints detected\n" + } + }, + { + "time_ms": 174, + "kind": "exit", + "data": { + "run_error": "duplicate outpoints detected" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/17_loop-static-in-positional-low-amt.json b/cmd/loop/testdata/sessions/static-loop-in/17_loop-static-in-positional-low-amt.json new file mode 100644 index 000000000..d75406877 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/17_loop-static-in-positional-low-amt.json @@ -0,0 +1,105 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "in", + "--network", + "regtest", + "10000", + "--payment_timeout", + "30s", + "--last_hop", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7", + "--force" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "rpc error: code = Unknown desc = swap amount too low", + "duration": 226739365 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "DEPOSITED", + "outpoints": [] + } + } + }, + { + "time_ms": 182, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "j71tovlF3ikFqn+pOGB0TZOH00ZEhDYOluRnpR3jvJ0=", + "state": "DEPOSITED", + "outpoint": "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0", + "value": "500000", + "confirmation_height": "148", + "blocks_until_expiry": "14383", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 183, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "10000", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": true, + "fast": false + } + } + }, + { + "time_ms": 225, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "error", + "error": "rpc error: code = Unknown desc = swap amount too low" + } + }, + { + "time_ms": 226, + "kind": "stderr", + "data": { + "text": "[loop] rpc error: code = Unknown desc = swap amount too low\n" + } + }, + { + "time_ms": 226, + "kind": "exit", + "data": { + "run_error": "rpc error: code = Unknown desc = swap amount too low" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/18_loop-static-in-positional-payment-timeout.json b/cmd/loop/testdata/sessions/static-loop-in/18_loop-static-in-positional-payment-timeout.json new file mode 100644 index 000000000..e7cf8a6f5 --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/18_loop-static-in-positional-payment-timeout.json @@ -0,0 +1,166 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "in", + "--network", + "regtest", + "500000", + "--payment_timeout", + "30s", + "--last_hop", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7", + "--force" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 1078774451 + }, + "events": [ + { + "time_ms": 4, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "DEPOSITED", + "outpoints": [] + } + } + }, + { + "time_ms": 179, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "j71tovlF3ikFqn+pOGB0TZOH00ZEhDYOluRnpR3jvJ0=", + "state": "DEPOSITED", + "outpoint": "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0", + "value": "500000", + "confirmation_height": "148", + "blocks_until_expiry": "14383", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 180, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "500000", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [], + "asset_info": null, + "auto_select_deposits": true, + "fast": false + } + } + }, + { + "time_ms": 500, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1824", + "htlc_publish_fee_sat": "0", + "cltv_delta": 0, + "conf_target": 0, + "quoted_amt": "500000" + } + } + }, + { + "time_ms": 500, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/StaticAddressLoopIn", + "event": "request", + "message_type": "looprpc.StaticAddressLoopInRequest", + "payload": { + "outpoints": [], + "max_swap_fee_satoshis": "1824", + "last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "label": "", + "initiator": "loop-cli", + "route_hints": [], + "private": false, + "payment_timeout_seconds": 30, + "amount": "500000", + "fast": false + } + } + }, + { + "time_ms": 1078, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/StaticAddressLoopIn", + "event": "response", + "message_type": "looprpc.StaticAddressLoopInResponse", + "payload": { + "swap_hash": "hDAjN0JANkGTlqt5ZN14uFsaSBqfHbc9tc3e5XwkQ+c=", + "state": "SignHtlcTx", + "amount": "500000", + "htlc_cltv": 1165, + "quoted_swap_fee_satoshis": "1824", + "max_swap_fee_satoshis": "1824", + "initiation_height": 165, + "protocol_version": "V0", + "label": "", + "initiator": "loop-cli", + "payment_timeout_seconds": 30, + "used_deposits": [ + { + "id": "j71tovlF3ikFqn+pOGB0TZOH00ZEhDYOluRnpR3jvJ0=", + "state": "LOOPING_IN", + "outpoint": "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0", + "value": "500000", + "confirmation_height": "148", + "blocks_until_expiry": "14383", + "swap_hash": "" + } + ], + "swap_amount": "500000", + "change": "0", + "fast": false + } + } + }, + { + "time_ms": 1078, + "kind": "stdout", + "data": { + "text": "{\n \"amount\": \"500000\",\n \"change\": \"0\",\n \"fast\": false,\n \"htlc_cltv\": 1165,\n \"initiation_height\": 165,\n \"initiator\": \"loop-cli\",\n \"label\": \"\",\n \"max_swap_fee_satoshis\": \"1824\",\n \"payment_timeout_seconds\": 30,\n \"protocol_version\": \"V0\",\n \"quoted_swap_fee_satoshis\": \"1824\",\n \"state\": \"SignHtlcTx\",\n \"swap_amount\": \"500000\",\n \"swap_hash\": \"84302337424036419396ab7964dd78b85b1a481a9f1db73db5cddee57c2443e7\",\n \"used_deposits\": [\n {\n \"blocks_until_expiry\": \"14383\",\n \"confirmation_height\": \"148\",\n \"id\": \"8fbd6da2f945de2905aa7fa93860744d9387d3464484360e96e467a51de3bc9d\",\n \"outpoint\": \"9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0\",\n \"state\": \"LOOPING_IN\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 1078, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static-loop-in/19_loop-static-in-all-cancel.json b/cmd/loop/testdata/sessions/static-loop-in/19_loop-static-in-all-cancel.json new file mode 100644 index 000000000..829f3b7be --- /dev/null +++ b/cmd/loop/testdata/sessions/static-loop-in/19_loop-static-in-all-cancel.json @@ -0,0 +1,123 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "in", + "--network", + "regtest", + "--all" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "swap canceled", + "duration": 446675015 + }, + "events": [ + { + "time_ms": 3, + "kind": "stdin", + "data": { + "text": "n\n" + } + }, + { + "time_ms": 5, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "request", + "message_type": "looprpc.ListStaticAddressDepositsRequest", + "payload": { + "state_filter": "DEPOSITED", + "outpoints": [] + } + } + }, + { + "time_ms": 387, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressDeposits", + "event": "response", + "message_type": "looprpc.ListStaticAddressDepositsResponse", + "payload": { + "filtered_deposits": [ + { + "id": "S7MSLTegUia00YiHa4Q+ZLxUl4M4FfD8lunKy9HyI1E=", + "state": "DEPOSITED", + "outpoint": "bbd8a81ea27aa5427a6e0000853f33328946f7297ab43cb0a549bee300ffd8b9:1", + "value": "500000", + "confirmation_height": "166", + "blocks_until_expiry": "14395", + "swap_hash": "" + } + ] + } + } + }, + { + "time_ms": 388, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "request", + "message_type": "looprpc.QuoteRequest", + "payload": { + "amt": "0", + "conf_target": 0, + "external_htlc": false, + "swap_publication_deadline": "0", + "loop_in_last_hop": "", + "loop_in_route_hints": [], + "private": false, + "deposit_outpoints": [ + "bbd8a81ea27aa5427a6e0000853f33328946f7297ab43cb0a549bee300ffd8b9:1" + ], + "asset_info": null, + "auto_select_deposits": false, + "fast": false + } + } + }, + { + "time_ms": 446, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/GetLoopInQuote", + "event": "response", + "message_type": "looprpc.InQuoteResponse", + "payload": { + "swap_fee_sat": "1823", + "htlc_publish_fee_sat": "0", + "cltv_delta": 0, + "conf_target": 0, + "quoted_amt": "500000" + } + } + }, + { + "time_ms": 446, + "kind": "stdout", + "data": { + "text": "On-chain fees for static address loop-ins are not included.\nThey were already paid when the deposits were created.\n\nPreviously deposited on-chain: 500000 sat\nReceive off-chain: 498177 sat\nEstimated total fee: 1823 sat\n\nCONTINUE SWAP? (y/n): " + } + }, + { + "time_ms": 446, + "kind": "stderr", + "data": { + "text": "[loop] swap canceled\n" + } + }, + { + "time_ms": 446, + "kind": "exit", + "data": { + "run_error": "swap canceled" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/static/01_loop-static-withdraw-no-selection.json b/cmd/loop/testdata/sessions/static/01_loop-static-withdraw-no-selection.json new file mode 100644 index 000000000..deefdb816 --- /dev/null +++ b/cmd/loop/testdata/sessions/static/01_loop-static-withdraw-no-selection.json @@ -0,0 +1,33 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "withdraw", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "must select either all or some utxos", + "duration": 1520351 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "[loop] must select either all or some utxos\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": { + "run_error": "must select either all or some utxos" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/static/02_loop-static-listwithdrawals.json b/cmd/loop/testdata/sessions/static/02_loop-static-listwithdrawals.json new file mode 100644 index 000000000..c8c9a733d --- /dev/null +++ b/cmd/loop/testdata/sessions/static/02_loop-static-listwithdrawals.json @@ -0,0 +1,71 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listwithdrawals", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 164024932 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressWithdrawals", + "event": "request", + "message_type": "looprpc.ListStaticAddressWithdrawalRequest", + "payload": {} + } + }, + { + "time_ms": 163, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressWithdrawals", + "event": "response", + "message_type": "looprpc.ListStaticAddressWithdrawalResponse", + "payload": { + "withdrawals": [ + { + "tx_id": "0000000000000000000000000000000000000000000000000000000000000000", + "deposits": [ + { + "id": "aCYqEEyewyXea+w3uOMb2HW70vXwuc4togzwvWNvxEg=", + "state": "WITHDRAWING", + "outpoint": "edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0", + "value": "500000", + "confirmation_height": "125", + "blocks_until_expiry": "0", + "swap_hash": "" + } + ], + "total_deposit_amount_satoshis": "500000", + "withdrawn_amount_satoshis": "0", + "change_amount_satoshis": "0", + "confirmation_height": 0 + } + ] + } + } + }, + { + "time_ms": 163, + "kind": "stdout", + "data": { + "text": "{\n \"withdrawals\": [\n {\n \"change_amount_satoshis\": \"0\",\n \"confirmation_height\": 0,\n \"deposits\": [\n {\n \"blocks_until_expiry\": \"0\",\n \"confirmation_height\": \"125\",\n \"id\": \"68262a104c9ec325de6bec37b8e31bd875bbd2f5f0b9ce2da20cf0bd636fc448\",\n \"outpoint\": \"edcdab8f0b1138d853a453b8b7a5ac3c694bd53ad38b7ccf062e45f99440e6e6:0\",\n \"state\": \"WITHDRAWING\",\n \"swap_hash\": \"\",\n \"value\": \"500000\"\n }\n ],\n \"total_deposit_amount_satoshis\": \"500000\",\n \"tx_id\": \"0000000000000000000000000000000000000000000000000000000000000000\",\n \"withdrawn_amount_satoshis\": \"0\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 164, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static/03_loop-static-listswaps.json b/cmd/loop/testdata/sessions/static/03_loop-static-listswaps.json new file mode 100644 index 000000000..d870ecf08 --- /dev/null +++ b/cmd/loop/testdata/sessions/static/03_loop-static-listswaps.json @@ -0,0 +1,52 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "listswaps", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 152223840 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressSwaps", + "event": "request", + "message_type": "looprpc.ListStaticAddressSwapsRequest", + "payload": {} + } + }, + { + "time_ms": 151, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListStaticAddressSwaps", + "event": "response", + "message_type": "looprpc.ListStaticAddressSwapsResponse", + "payload": { + "swaps": [] + } + } + }, + { + "time_ms": 151, + "kind": "stdout", + "data": { + "text": "{\n \"swaps\": []\n}\n" + } + }, + { + "time_ms": 152, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static/04_loop-static-withdraw-invalid-utxo.json b/cmd/loop/testdata/sessions/static/04_loop-static-withdraw-invalid-utxo.json new file mode 100644 index 000000000..668d08a39 --- /dev/null +++ b/cmd/loop/testdata/sessions/static/04_loop-static-withdraw-invalid-utxo.json @@ -0,0 +1,35 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "withdraw", + "--utxo", + "abc", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "outpoint should be of the form txid:index", + "duration": 8829122 + }, + "events": [ + { + "time_ms": 8, + "kind": "stderr", + "data": { + "text": "[loop] outpoint should be of the form txid:index\n" + } + }, + { + "time_ms": 8, + "kind": "exit", + "data": { + "run_error": "outpoint should be of the form txid:index" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/static/05_loop-static-withdraw-all.json b/cmd/loop/testdata/sessions/static/05_loop-static-withdraw-all.json new file mode 100644 index 000000000..e64870b9f --- /dev/null +++ b/cmd/loop/testdata/sessions/static/05_loop-static-withdraw-all.json @@ -0,0 +1,60 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "withdraw", + "--all", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 582593010 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/WithdrawDeposits", + "event": "request", + "message_type": "looprpc.WithdrawDepositsRequest", + "payload": { + "outpoints": [], + "all": true, + "dest_addr": "", + "sat_per_vbyte": "0", + "amount": "0" + } + } + }, + { + "time_ms": 582, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/WithdrawDeposits", + "event": "response", + "message_type": "looprpc.WithdrawDepositsResponse", + "payload": { + "withdrawal_tx_hash": "849b3e491dd45688fe66fc05fc0b7a89a147cad749486c46f515b1e815a16d31", + "address": "bcrt1pk2jdgms8l67x6mp2kjq45k2sd7mdpfcf988lckk774uguxzh0x5scddya7" + } + } + }, + { + "time_ms": 582, + "kind": "stdout", + "data": { + "text": "{\n \"address\": \"bcrt1pk2jdgms8l67x6mp2kjq45k2sd7mdpfcf988lckk774uguxzh0x5scddya7\",\n \"withdrawal_tx_hash\": \"849b3e491dd45688fe66fc05fc0b7a89a147cad749486c46f515b1e815a16d31\"\n}\n" + } + }, + { + "time_ms": 582, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/static/06_loop-static-withdraw-utxo-destaddr.json b/cmd/loop/testdata/sessions/static/06_loop-static-withdraw-utxo-destaddr.json new file mode 100644 index 000000000..39baee92d --- /dev/null +++ b/cmd/loop/testdata/sessions/static/06_loop-static-withdraw-utxo-destaddr.json @@ -0,0 +1,69 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "static", + "withdraw", + "--network", + "regtest", + "--utxo", + "56cd081a3a6eadf25b7d3fe0b61207389352ed69a622d2ec28c5d669bf6a5313:0", + "--dest_addr", + "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 308497131 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/WithdrawDeposits", + "event": "request", + "message_type": "looprpc.WithdrawDepositsRequest", + "payload": { + "outpoints": [ + { + "txid_bytes": "", + "txid_str": "56cd081a3a6eadf25b7d3fe0b61207389352ed69a622d2ec28c5d669bf6a5313", + "output_index": 0 + } + ], + "all": false, + "dest_addr": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw", + "sat_per_vbyte": "0", + "amount": "0" + } + } + }, + { + "time_ms": 308, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/WithdrawDeposits", + "event": "response", + "message_type": "looprpc.WithdrawDepositsResponse", + "payload": { + "withdrawal_tx_hash": "4578dde9139327e5122960b778fe09f426cf6c1df5fa276cca18d72ccb3d88ba", + "address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw" + } + } + }, + { + "time_ms": 308, + "kind": "stdout", + "data": { + "text": "{\n \"address\": \"bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw\",\n \"withdrawal_tx_hash\": \"4578dde9139327e5122960b778fe09f426cf6c1df5fa276cca18d72ccb3d88ba\"\n}\n" + } + }, + { + "time_ms": 308, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/01_loop-listswaps.json b/cmd/loop/testdata/sessions/swaps/01_loop-listswaps.json new file mode 100644 index 000000000..8e4ff695c --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/01_loop-listswaps.json @@ -0,0 +1,84 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "listswaps", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 150727157 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListSwaps", + "event": "request", + "message_type": "looprpc.ListSwapsRequest", + "payload": { + "list_swap_filter": { + "swap_type": "ANY", + "pending_only": false, + "outgoing_chan_set": [], + "label": "", + "loop_in_last_hop": "", + "asset_swap_only": false, + "start_timestamp_ns": "0" + }, + "max_swaps": "0" + } + } + }, + { + "time_ms": 149, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListSwaps", + "event": "response", + "message_type": "looprpc.ListSwapsResponse", + "payload": { + "swaps": [ + { + "amt": "500000", + "id": "46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b", + "id_bytes": "RrjbZBEKYAi9NrQjQ5y7oejnbAJk6KaPRC/CKjwrT2s=", + "type": "LOOP_OUT", + "state": "INITIATED", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1770081011767003660", + "last_update_time": "1770081011767003660", + "htlc_address": "bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv", + "cost_server": "0", + "cost_onchain": "0", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + ], + "next_start_time": "0" + } + } + }, + { + "time_ms": 150, + "kind": "stdout", + "data": { + "text": "{\n \"next_start_time\": \"0\",\n \"swaps\": [\n {\n \"amt\": \"500000\",\n \"asset_info\": null,\n \"cost_offchain\": \"0\",\n \"cost_onchain\": \"0\",\n \"cost_server\": \"0\",\n \"failure_reason\": \"FAILURE_REASON_NONE\",\n \"htlc_address\": \"bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv\",\n \"htlc_address_p2tr\": \"bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv\",\n \"htlc_address_p2wsh\": \"\",\n \"id\": \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\",\n \"id_bytes\": \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\",\n \"initiation_time\": \"1770081011767003660\",\n \"label\": \"\",\n \"last_hop\": \"\",\n \"last_update_time\": \"1770081011767003660\",\n \"outgoing_chan_set\": [],\n \"state\": \"INITIATED\",\n \"type\": \"LOOP_OUT\"\n }\n ]\n}\n" + } + }, + { + "time_ms": 150, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/02_loop-swapinfo.json b/cmd/loop/testdata/sessions/swaps/02_loop-swapinfo.json new file mode 100644 index 000000000..11f4f96db --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/02_loop-swapinfo.json @@ -0,0 +1,71 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "swapinfo", + "--network", + "regtest", + "46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 191339781 + }, + "events": [ + { + "time_ms": 1, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SwapInfo", + "event": "request", + "message_type": "looprpc.SwapInfoRequest", + "payload": { + "id": "RrjbZBEKYAi9NrQjQ5y7oejnbAJk6KaPRC/CKjwrT2s=" + } + } + }, + { + "time_ms": 191, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/SwapInfo", + "event": "response", + "message_type": "looprpc.SwapStatus", + "payload": { + "amt": "500000", + "id": "46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b", + "id_bytes": "RrjbZBEKYAi9NrQjQ5y7oejnbAJk6KaPRC/CKjwrT2s=", + "type": "LOOP_OUT", + "state": "INITIATED", + "failure_reason": "FAILURE_REASON_NONE", + "initiation_time": "1770081011767003660", + "last_update_time": "1770081011767003660", + "htlc_address": "bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv", + "htlc_address_p2wsh": "", + "htlc_address_p2tr": "bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv", + "cost_server": "0", + "cost_onchain": "0", + "cost_offchain": "0", + "last_hop": "", + "outgoing_chan_set": [], + "label": "", + "asset_info": null + } + } + }, + { + "time_ms": 191, + "kind": "stdout", + "data": { + "text": "{\n \"amt\": \"500000\",\n \"asset_info\": null,\n \"cost_offchain\": \"0\",\n \"cost_onchain\": \"0\",\n \"cost_server\": \"0\",\n \"failure_reason\": \"FAILURE_REASON_NONE\",\n \"htlc_address\": \"bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv\",\n \"htlc_address_p2tr\": \"bcrt1pj90ffd4j9hc2a58xpl3q77c6pf8ckhqhv9w9m2529kqsk77f6lksrca9pv\",\n \"htlc_address_p2wsh\": \"\",\n \"id\": \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\",\n \"id_bytes\": \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\",\n \"initiation_time\": \"1770081011767003660\",\n \"label\": \"\",\n \"last_hop\": \"\",\n \"last_update_time\": \"1770081011767003660\",\n \"outgoing_chan_set\": [],\n \"state\": \"INITIATED\",\n \"type\": \"LOOP_OUT\"\n}\n" + } + }, + { + "time_ms": 191, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/03_loop-abandonswap.json b/cmd/loop/testdata/sessions/swaps/03_loop-abandonswap.json new file mode 100644 index 000000000..c97ad9142 --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/03_loop-abandonswap.json @@ -0,0 +1,29 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "abandonswap", + "--network", + "regtest" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 2764352 + }, + "events": [ + { + "time_ms": 1, + "kind": "stdout", + "data": { + "text": "NAME:\n loop abandonswap - abandon a swap with a given swap hash\n\nUSAGE:\n loop abandonswap ID\n\nDESCRIPTION:\n This command overrides the database and abandons a swap with a given swap hash.\n\n !!! This command might potentially lead to loss of funds if it is applied to swaps that are still waiting for pending user funds. Before executing this command make sure that no funds are locked by the swap.\n\nOPTIONS:\n --i_know_what_i_am_doing Specify this flag if you made sure that you read and understood the following consequence of applying this command. (default: false)\n --help, -h show help\n" + } + }, + { + "time_ms": 2, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/04_loop-listswaps-conflicting-filters.json b/cmd/loop/testdata/sessions/swaps/04_loop-listswaps-conflicting-filters.json new file mode 100644 index 000000000..308243979 --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/04_loop-listswaps-conflicting-filters.json @@ -0,0 +1,34 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "listswaps", + "--network", + "regtest", + "--loop_out_only", + "--loop_in_only" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "only one of loop_out_only and loop_in_only can be set", + "duration": 1714263 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "[loop] only one of loop_out_only and loop_in_only can be set\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": { + "run_error": "only one of loop_out_only and loop_in_only can be set" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/05_loop-swapinfo-invalid-id.json b/cmd/loop/testdata/sessions/swaps/05_loop-swapinfo-invalid-id.json new file mode 100644 index 000000000..7a96c39e3 --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/05_loop-swapinfo-invalid-id.json @@ -0,0 +1,33 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "swapinfo", + "--network", + "regtest", + "deadbeef" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "invalid swap ID", + "duration": 1081414 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "[loop] invalid swap ID\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": { + "run_error": "invalid swap ID" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/06_loop-abandonswap-invalid-id.json b/cmd/loop/testdata/sessions/swaps/06_loop-abandonswap-invalid-id.json new file mode 100644 index 000000000..0d4095cf3 --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/06_loop-abandonswap-invalid-id.json @@ -0,0 +1,34 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "abandonswap", + "--network", + "regtest", + "--i_know_what_i_am_doing", + "deadbeef" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "invalid swap ID", + "duration": 1742129 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "[loop] invalid swap ID\n" + } + }, + { + "time_ms": 1, + "kind": "exit", + "data": { + "run_error": "invalid swap ID" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/07_loop-listswaps-loop-out-filtered.json b/cmd/loop/testdata/sessions/swaps/07_loop-listswaps-loop-out-filtered.json new file mode 100644 index 000000000..56f221652 --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/07_loop-listswaps-loop-out-filtered.json @@ -0,0 +1,76 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "listswaps", + "--network", + "regtest", + "--loop_out_only", + "--channel", + "125344325763072", + "--last_hop", + "0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7", + "--label", + "testlabel", + "--start_time_ns", + "1", + "--max_swaps", + "5" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 146940860 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListSwaps", + "event": "request", + "message_type": "looprpc.ListSwapsRequest", + "payload": { + "list_swap_filter": { + "swap_type": "LOOP_OUT", + "pending_only": false, + "outgoing_chan_set": [ + "125344325763072" + ], + "label": "testlabel", + "loop_in_last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3", + "asset_swap_only": false, + "start_timestamp_ns": "1" + }, + "max_swaps": "5" + } + } + }, + { + "time_ms": 146, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListSwaps", + "event": "response", + "message_type": "looprpc.ListSwapsResponse", + "payload": { + "swaps": [], + "next_start_time": "0" + } + } + }, + { + "time_ms": 146, + "kind": "stdout", + "data": { + "text": "{\n \"next_start_time\": \"0\",\n \"swaps\": []\n}\n" + } + }, + { + "time_ms": 146, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/08_loop-listswaps-loop-in-only.json b/cmd/loop/testdata/sessions/swaps/08_loop-listswaps-loop-in-only.json new file mode 100644 index 000000000..d324d66dd --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/08_loop-listswaps-loop-in-only.json @@ -0,0 +1,64 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "listswaps", + "--network", + "regtest", + "--loop_in_only" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 237970153 + }, + "events": [ + { + "time_ms": 3, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListSwaps", + "event": "request", + "message_type": "looprpc.ListSwapsRequest", + "payload": { + "list_swap_filter": { + "swap_type": "LOOP_IN", + "pending_only": false, + "outgoing_chan_set": [], + "label": "", + "loop_in_last_hop": "", + "asset_swap_only": false, + "start_timestamp_ns": "0" + }, + "max_swaps": "0" + } + } + }, + { + "time_ms": 236, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/ListSwaps", + "event": "response", + "message_type": "looprpc.ListSwapsResponse", + "payload": { + "swaps": [], + "next_start_time": "0" + } + } + }, + { + "time_ms": 236, + "kind": "stdout", + "data": { + "text": "{\n \"next_start_time\": \"0\",\n \"swaps\": []\n}\n" + } + }, + { + "time_ms": 237, + "kind": "exit", + "data": {} + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/09_loop-swapinfo-id-flag-parse-error.json b/cmd/loop/testdata/sessions/swaps/09_loop-swapinfo-id-flag-parse-error.json new file mode 100644 index 000000000..f314a4355 --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/09_loop-swapinfo-id-flag-parse-error.json @@ -0,0 +1,34 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "swapinfo", + "--network", + "regtest", + "--id", + "46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "invalid value \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\" for flag -id: strconv.ParseUint: parsing \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\": invalid syntax", + "duration": 2097605 + }, + "events": [ + { + "time_ms": 1, + "kind": "stderr", + "data": { + "text": "Incorrect Usage: invalid value \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\" for flag -id: strconv.ParseUint: parsing \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\": invalid syntax\n\n[loop] invalid value \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\" for flag -id: strconv.ParseUint: parsing \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\": invalid syntax\n" + } + }, + { + "time_ms": 2, + "kind": "exit", + "data": { + "run_error": "invalid value \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\" for flag -id: strconv.ParseUint: parsing \"46b8db64110a6008bd36b423439cbba1e8e76c0264e8a68f442fc22a3c2b4f6b\": invalid syntax" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/10_loop-swapinfo-id-flag.json b/cmd/loop/testdata/sessions/swaps/10_loop-swapinfo-id-flag.json new file mode 100644 index 000000000..b29dc25b1 --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/10_loop-swapinfo-id-flag.json @@ -0,0 +1,34 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "swapinfo", + "--network", + "regtest", + "--id", + "1" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "run_error": "invalid swap ID", + "duration": 6122492 + }, + "events": [ + { + "time_ms": 6, + "kind": "stderr", + "data": { + "text": "[loop] invalid swap ID\n" + } + }, + { + "time_ms": 6, + "kind": "exit", + "data": { + "run_error": "invalid swap ID" + } + } + ] +} diff --git a/cmd/loop/testdata/sessions/swaps/11_loop-abandonswap-success.json b/cmd/loop/testdata/sessions/swaps/11_loop-abandonswap-success.json new file mode 100644 index 000000000..5d75789a0 --- /dev/null +++ b/cmd/loop/testdata/sessions/swaps/11_loop-abandonswap-success.json @@ -0,0 +1,54 @@ +{ + "metadata": { + "args": [ + "/home/user/bin/loop", + "abandonswap", + "--network", + "regtest", + "--i_know_what_i_am_doing", + "2f46a232e0f584fadf2abc7e7aaeefab0176f21e0fba5344a10e21838ec390fe" + ], + "env": { + "HOME": "/home/user" + }, + "version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845", + "duration": 194305706 + }, + "events": [ + { + "time_ms": 2, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/AbandonSwap", + "event": "request", + "message_type": "looprpc.AbandonSwapRequest", + "payload": { + "id": "L0aiMuD1hPrfKrx+eq7vqwF28h4PulNEoQ4hg47DkP4=", + "i_know_what_i_am_doing": true + } + } + }, + { + "time_ms": 193, + "kind": "grpc", + "data": { + "method": "/looprpc.SwapClient/AbandonSwap", + "event": "response", + "message_type": "looprpc.AbandonSwapResponse", + "payload": {} + } + }, + { + "time_ms": 193, + "kind": "stdout", + "data": { + "text": "{}\n" + } + }, + { + "time_ms": 194, + "kind": "exit", + "data": {} + } + ] +}