diff --git a/cmd/wavecli/waveclicommands/cmd_channel.go b/cmd/wavecli/waveclicommands/cmd_channel.go new file mode 100644 index 000000000..c63ed06e3 --- /dev/null +++ b/cmd/wavecli/waveclicommands/cmd_channel.go @@ -0,0 +1,309 @@ +package waveclicommands + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + "strconv" + + "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" + "github.com/spf13/cobra" + "google.golang.org/grpc" +) + +// getArkChannelClient is replaceable by command wiring tests. +var getArkChannelClient = defaultGetArkChannelClient + +// defaultGetArkChannelClient connects to the local Ark channel service. +func defaultGetArkChannelClient(cmd *cobra.Command) ( + arkchannelrpc.ArkChannelServiceClient, *grpc.ClientConn, error) { + + conn, err := getDaemonConn(cmd) + if err != nil { + return nil, nil, err + } + + return arkchannelrpc.NewArkChannelServiceClient(conn), conn, nil +} + +// newChannelCmd builds the daemon-development Ark channel control surface. +func newChannelCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "channel", + Short: "Manage native Ark-backed Lightning channels", + } + cmd.AddCommand( + newChannelCreateCmd(), newChannelGetCmd(), newChannelSendCmd(), + newChannelReceiveCmd(), newChannelPayCmd(), + newChannelCloseCmd(), newChannelForceCloseCmd(), + ) + + return cmd +} + +// newChannelCreateCmd promotes one wallet VTXO into an OOR channel. +func newChannelCreateCmd() *cobra.Command { + return &cobra.Command{ + Use: "create ", + Short: "Promote wallet value into a channel", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + amount, err := parsePositiveChannelAmount(args[0]) + if err != nil { + return err + } + client, conn, err := getArkChannelClient(cmd) + if err != nil { + return err + } + defer conn.Close() + ctx, cancel := rpcContext(cmd) + defer cancel() + + resp, err := client.PromoteVTXO( + ctx, &arkchannelrpc.PromoteVTXORequest{ + AmountSat: amount, + }, + ) + if err != nil { + return err + } + + return printJSON(resp) + }, + } +} + +// newChannelGetCmd returns one durable channel snapshot. +func newChannelGetCmd() *cobra.Command { + return channelIDCommand( + "get ", "Show one channel", func(cmd *cobra.Command, + client arkchannelrpc.ArkChannelServiceClient, + channelID []byte) error { + + ctx, cancel := rpcContext(cmd) + defer cancel() + resp, err := client.GetChannel( + ctx, &arkchannelrpc.GetChannelRequest{ + ChannelId: channelID, + }, + ) + if err != nil { + return err + } + + return printJSON(resp) + }, + ) +} + +// newChannelSendCmd sends a local test payment over one channel. +func newChannelSendCmd() *cobra.Command { + return channelPaymentCommand("send", func( + ctxClient arkchannelrpc.ArkChannelServiceClient, + cmd *cobra.Command, + req *arkchannelrpc.ChannelPaymentRequest) error { + + ctx, cancel := rpcContext(cmd) + defer cancel() + resp, err := ctxClient.SendPayment(ctx, req) + if err != nil { + return err + } + + return printJSON(resp) + }) +} + +// newChannelReceiveCmd receives a local test payment over one channel. +func newChannelReceiveCmd() *cobra.Command { + return channelPaymentCommand("receive", func( + ctxClient arkchannelrpc.ArkChannelServiceClient, + cmd *cobra.Command, + req *arkchannelrpc.ChannelPaymentRequest) error { + + ctx, cancel := rpcContext(cmd) + defer cancel() + resp, err := ctxClient.ReceivePayment(ctx, req) + if err != nil { + return err + } + + return printJSON(resp) + }) +} + +// newChannelPayCmd bridges a private source HTLC to a public invoice. +func newChannelPayCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "pay ", + Short: "Pay a public Lightning invoice through a channel", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + maxFee, _ := cmd.Flags().GetUint64("max-fee-sat") + client, conn, err := getArkChannelClient(cmd) + if err != nil { + return err + } + defer conn.Close() + ctx, cancel := rpcContext(cmd) + defer cancel() + resp, err := client.PayLightningInvoice( + ctx, &arkchannelrpc.PayLightningInvoiceRequest{ + PaymentRequest: args[0], + MaxFeeSat: maxFee, + }, + ) + if err != nil { + return err + } + + return printJSON(resp) + }, + } + cmd.Flags().Uint64("max-fee-sat", 100_000, + "maximum public Lightning routing fee") + + return cmd +} + +// newChannelCloseCmd cooperatively closes one clean channel. +func newChannelCloseCmd() *cobra.Command { + return channelIDCommand( + "close ", "Cooperatively close one channel", func( + cmd *cobra.Command, + client arkchannelrpc.ArkChannelServiceClient, + channelID []byte) error { + + ctx, cancel := rpcContext(cmd) + defer cancel() + resp, err := client.RequestCooperativeClose( + ctx, + &arkchannelrpc.RequestCooperativeCloseRequest{ + ChannelId: channelID, + }, + ) + if err != nil { + return err + } + + return printJSON(resp) + }, + ) +} + +// newChannelForceCloseCmd materializes and force closes one channel. +func newChannelForceCloseCmd() *cobra.Command { + return channelIDCommand( + "force-close ", "Materialize and force close a "+ + "channel", + func(cmd *cobra.Command, + client arkchannelrpc.ArkChannelServiceClient, + channelID []byte) error { + + ctx, cancel := rpcContext(cmd) + defer cancel() + resp, err := client.MaterializeAndForceClose( + ctx, + &arkchannelrpc.MaterializeAndForceCloseRequest{ + ChannelId: channelID, + }, + ) + if err != nil { + return err + } + + return printJSON(resp) + }, + ) +} + +// channelPaymentDispatch executes one amount-bearing channel RPC. +type channelPaymentDispatch func( + arkchannelrpc.ArkChannelServiceClient, *cobra.Command, + *arkchannelrpc.ChannelPaymentRequest, +) error + +// channelPaymentCommand builds a two-positional-argument payment command. +func channelPaymentCommand(name string, + dispatch channelPaymentDispatch) *cobra.Command { + + return &cobra.Command{ + Use: name + " ", + Short: name + " over one active channel", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + channelID, err := parseChannelID(args[0]) + if err != nil { + return err + } + amount, err := parsePositiveChannelAmount(args[1]) + if err != nil { + return err + } + client, conn, err := getArkChannelClient(cmd) + if err != nil { + return err + } + defer conn.Close() + + return dispatch(client, cmd, + &arkchannelrpc.ChannelPaymentRequest{ + ChannelId: channelID, AmountSat: amount, + }) + }, + } +} + +// channelIDDispatch executes one channel-ID-bearing RPC. +type channelIDDispatch func( + *cobra.Command, arkchannelrpc.ArkChannelServiceClient, []byte, +) error + +// channelIDCommand builds a command whose sole argument is a channel ID. +func channelIDCommand(use, short string, + dispatch channelIDDispatch) *cobra.Command { + + return &cobra.Command{ + Use: use, + Short: short, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + channelID, err := parseChannelID(args[0]) + if err != nil { + return err + } + client, conn, err := getArkChannelClient(cmd) + if err != nil { + return err + } + defer conn.Close() + + return dispatch(cmd, client, channelID) + }, + } +} + +// parsePositiveChannelAmount parses one positive signed RPC amount. +func parsePositiveChannelAmount(value string) (int64, error) { + amount, err := strconv.ParseInt(value, 10, 64) + if err != nil || amount <= 0 { + return 0, fmt.Errorf("amount-sat must be a positive integer") + } + + return amount, nil +} + +// parseChannelID accepts either canonical hex or protobuf JSON base64. +func parseChannelID(value string) ([]byte, error) { + decoded, err := hex.DecodeString(value) + if err != nil || len(decoded) != 32 { + decoded, err = base64.StdEncoding.DecodeString(value) + } + if err != nil || len(decoded) != 32 { + return nil, fmt.Errorf("channel-id must encode exactly 32 " + + "bytes") + } + + return decoded, nil +} diff --git a/cmd/wavecli/waveclicommands/cmd_channel_test.go b/cmd/wavecli/waveclicommands/cmd_channel_test.go new file mode 100644 index 000000000..d32569f42 --- /dev/null +++ b/cmd/wavecli/waveclicommands/cmd_channel_test.go @@ -0,0 +1,52 @@ +package waveclicommands + +import ( + "encoding/base64" + "encoding/hex" + "testing" + + "github.com/stretchr/testify/require" +) + +// TestParseChannelIDAcceptsCLIEncodings verifies command chaining works with +// both the protobuf JSON response and the canonical hexadecimal identifier. +func TestParseChannelIDAcceptsCLIEncodings(t *testing.T) { + t.Parallel() + + id := make([]byte, 32) + for i := range id { + id[i] = byte(i + 1) + } + + for _, encoded := range []string{ + hex.EncodeToString(id), base64.StdEncoding.EncodeToString(id), + } { + decoded, err := parseChannelID(encoded) + require.NoError(t, err) + require.Equal(t, id, decoded) + } +} + +// TestParseChannelIDRejectsWrongLength verifies malformed identifiers fail +// before the CLI opens a daemon connection. +func TestParseChannelIDRejectsWrongLength(t *testing.T) { + t.Parallel() + + _, err := parseChannelID(hex.EncodeToString(make([]byte, 31))) + require.ErrorContains(t, err, "exactly 32 bytes") +} + +// TestParsePositiveChannelAmount keeps channel creation's public input to one +// positive amount instead of exposing internal funding-policy switches. +func TestParsePositiveChannelAmount(t *testing.T) { + t.Parallel() + + amount, err := parsePositiveChannelAmount("200000") + require.NoError(t, err) + require.EqualValues(t, 200_000, amount) + + for _, value := range []string{"0", "-1", "one"} { + _, err := parsePositiveChannelAmount(value) + require.ErrorContains(t, err, "positive integer") + } +} diff --git a/cmd/wavecli/waveclicommands/devrpc/registry_generated.go b/cmd/wavecli/waveclicommands/devrpc/registry_generated.go index 16a740331..ac33449de 100644 --- a/cmd/wavecli/waveclicommands/devrpc/registry_generated.go +++ b/cmd/wavecli/waveclicommands/devrpc/registry_generated.go @@ -121,6 +121,48 @@ func generatedRegistry() []serviceSpec { Output: "waverpc.GetIndexedOORSessionByTxidResponse", Comments: "GetIndexedOORSessionByTxid queries the authoritative indexer for one\nOOR session using a spent script proof and deterministic session txid.", }, + { + Name: "ExportOORRecoveryPackage", + Aliases: []string{"export-oor-recovery-package"}, + Input: "waverpc.ExportOORRecoveryPackageRequest", + Output: "waverpc.ExportOORRecoveryPackageResponse", + Comments: "ExportOORRecoveryPackage returns the immutable local OOR package and\nround ancestry for one exact output. The caller must already know the\noutput tuple; the daemon verifies it against its finalized artifacts.", + }, + { + Name: "PrepareArkChannelOOR", + Aliases: []string{"prepare-ark-channel-oor"}, + Input: "waverpc.PrepareArkChannelOORRequest", + Output: "waverpc.PrepareArkChannelOORResponse", + Comments: "PrepareArkChannelOOR reserves daemon-owned liquidity and builds the\nexact channel-policy output without releasing OOR signatures.", + }, + { + Name: "LookupPreparedArkChannelOOR", + Aliases: []string{"lookup-prepared-ark-channel-oor"}, + Input: "waverpc.LookupPreparedArkChannelOORRequest", + Output: "waverpc.LookupPreparedArkChannelOORResponse", + Comments: "LookupPreparedArkChannelOOR reconciles the deterministic channel OOR\nkey without selecting or locking new wallet inputs.", + }, + { + Name: "ValidatePreparedArkChannelOOR", + Aliases: []string{"validate-prepared-ark-channel-oor"}, + Input: "waverpc.ValidatePreparedArkChannelOORRequest", + Output: "waverpc.ValidatePreparedArkChannelOORResponse", + Comments: "ValidatePreparedArkChannelOOR verifies that a binding still names the\nexact prepared daemon OOR session.", + }, + { + Name: "CommitPreparedArkChannelOOR", + Aliases: []string{"commit-prepared-ark-channel-oor"}, + Input: "waverpc.CommitPreparedArkChannelOORRequest", + Output: "waverpc.CommitPreparedArkChannelOORResponse", + Comments: "CommitPreparedArkChannelOOR releases the prepared OOR only after both\nlnd endpoints have persisted the fully signed channel backing.", + }, + { + Name: "AbortPreparedArkChannelOOR", + Aliases: []string{"abort-prepared-ark-channel-oor"}, + Input: "waverpc.AbortPreparedArkChannelOORRequest", + Output: "waverpc.AbortPreparedArkChannelOORResponse", + Comments: "AbortPreparedArkChannelOOR releases a pre-signing channel reservation.", + }, { Name: "SendVTXO", Aliases: []string{"send-vtxo"}, diff --git a/cmd/wavecli/waveclicommands/root.go b/cmd/wavecli/waveclicommands/root.go index a5aa838a8..0310a6cbf 100644 --- a/cmd/wavecli/waveclicommands/root.go +++ b/cmd/wavecli/waveclicommands/root.go @@ -25,8 +25,8 @@ const ( groupIntrospection = "introspection" groupAdvanced = "advanced" - // devModeEnvVar, when set to "1", reveals the advanced subtrees - // (ark / dev / recovery) under an Advanced group in --help. It only + // devModeEnvVar, when set to "1", reveals the advanced subtrees (ark / + // channel / dev / recovery) under an Advanced group in --help. It only // changes visibility; it never gates execution. devModeEnvVar = "WAVELENGTH_DEV" ) @@ -35,9 +35,9 @@ const ( // flags (--rpcserver, --timeout, --tlscertpath, --macaroonpath, --no-tls) are // registered here and made available to all subcommands via PersistentFlags. // -// The advanced subtrees (ark / dev / recovery) are hidden from the default -// --help unless WAVELENGTH_DEV=1 is set; execution is never gated on the env -// var. +// The advanced subtrees (ark / channel / dev / recovery) are hidden from the +// default --help unless WAVELENGTH_DEV=1 is set; execution is never gated on +// the env var. func NewRootCmd() *cobra.Command { return newRootCmd(os.Getenv(devModeEnvVar) == "1") } @@ -157,6 +157,7 @@ func newRootCmd(devMode bool) *cobra.Command { // on a GroupID naming a group that was never registered. advancedCmds := []*cobra.Command{ newArkCmd(), + newChannelCmd(), newRecoveryCmd(), devrpc.NewDevCmd( devrpc.Config{ diff --git a/cmd/wavecli/waveclicommands/root_groups_test.go b/cmd/wavecli/waveclicommands/root_groups_test.go index ddfb9b408..788c33f19 100644 --- a/cmd/wavecli/waveclicommands/root_groups_test.go +++ b/cmd/wavecli/waveclicommands/root_groups_test.go @@ -94,7 +94,7 @@ func TestAdvancedCommandsHiddenByDefault(t *testing.T) { t.Parallel() root := newRootCmd(false) - for _, name := range []string{"ark", "dev", "recovery"} { + for _, name := range []string{"ark", "channel", "dev", "recovery"} { sub := findRootCommand(t, root, name) require.Truef(t, sub.Hidden, "%q should be hidden", name) require.Emptyf( @@ -113,7 +113,7 @@ func TestAdvancedCommandsGroupedUnderDevMode(t *testing.T) { root := newRootCmd(true) require.Contains(t, rootGroupIDs(root), groupAdvanced) - for _, name := range []string{"ark", "dev", "recovery"} { + for _, name := range []string{"ark", "channel", "dev", "recovery"} { sub := findRootCommand(t, root, name) require.Falsef(t, sub.Hidden, "%q should be visible", name) require.Equalf( diff --git a/docs/daemon_cli_guide.md b/docs/daemon_cli_guide.md index 084a0f403..192910d03 100644 --- a/docs/daemon_cli_guide.md +++ b/docs/daemon_cli_guide.md @@ -281,11 +281,10 @@ alias wave='wavecli --no-tls --no-macaroons' ### Command tree The everyday wallet verbs and daemon introspection make up the default -`--help` face. The advanced `ark`, `recovery`, and `dev` subtrees are +`--help` face. The advanced `ark`, `channel`, `recovery`, and `dev` subtrees are hidden from `--help` (set `WAVELENGTH_DEV=1` to reveal them under an "Advanced" -group) but stay fully runnable in every build — `wavecli ark …` works -with or without the env var. `WAVELENGTH_DEV` only changes visibility; it never -gates execution. +group) but stay fully runnable in every build. `WAVELENGTH_DEV` only changes +visibility; it never gates execution. The `swap` subtree was retired — `send`/`recv --offchain` and `activity` cover it, and a stale `wavecli swap …` fails with a hint toward @@ -313,6 +312,10 @@ wavecli │ ├── sweep [list] — broadcast requires approval │ ├── fees {estimate|history} │ └── listtransactions +├── channel — Ark-backed native Lightning channels (hidden) +│ ├── create / get +│ ├── send / receive / pay +│ └── close / force-close ├── recovery {list|status|escalate|cancel} — daemon-owned vHTLC recovery rows (hidden) └── dev — generated low-level RPC (hidden; no wavewalletrpc) └── daemon — call any waverpc.DaemonService method @@ -383,6 +386,37 @@ wavecli recv --offchain --amt 5000 --memo coffee wavecli dev daemon NewAddress ``` +### `channel` (development) + +Promote wallet VTXO value into an unpublished native Lightning channel, use it +for private or public payments, and choose cooperative or unilateral closure. +Creation intentionally takes only the desired channel capacity; the daemon +owns OOR preparation, backing reserve, private-channel policy, and activation. +Channel IDs accept either the base64 value printed by protobuf JSON or 32-byte +hex. + +```bash +wavecli channel create 100000 +wavecli channel get +wavecli channel send 10000 +wavecli channel receive 5000 +wavecli channel pay --max-fee-sat 1000 +wavecli channel close +wavecli channel force-close +``` + +`recv --offchain` uses an active channel directly when it has enough inbound +liquidity. Otherwise an eligible single-part payment can manifest an +overfunded, hub-owned channel before the same payment hash is delivered over +it. After completion, `activity inspect --format json` reports +the manifested `channel_id` and reserved alias SCID. A receive that reused an +existing channel has an empty `channel_id`. + +Payments that use the ordinary vHTLC fallback still settle into the wallet; +they are not implicitly converted into channels. Any ordinary wallet VTXO, +including value received through that fallback, can later be promoted with +`wavecli channel create `. + ### `ark board` / `dev daemon Board` Trigger the client to join the next round with any confirmed boarding diff --git a/harness/harness.go b/harness/harness.go index ac0dc791a..c42535046 100644 --- a/harness/harness.go +++ b/harness/harness.go @@ -2810,6 +2810,7 @@ func (h *Harness) SetupChannelBetween(local *LndInstance, peer *LndInstance, NodePubkey: peerInfo.IdentityPubkey[:], LocalFundingAmount: capacitySat, PushSat: pushAmt, + Private: false, }) require.NoError( t, err, "OpenChannel failed for %s -> %s", local.Name, diff --git a/rpc/restclient/clients.go b/rpc/restclient/clients.go index 5a0eb9def..4336f9a0f 100644 --- a/rpc/restclient/clients.go +++ b/rpc/restclient/clients.go @@ -499,6 +499,86 @@ func (c *DaemonServiceClient) GetIndexedOORSessionByTxid(ctx context.Context, return out, err } +// ExportOORRecoveryPackage returns immutable recovery data for one exact OOR +// output created by this daemon. +func (c *DaemonServiceClient) ExportOORRecoveryPackage(ctx context.Context, + in *waverpc.ExportOORRecoveryPackageRequest, _ ...grpc.CallOption) ( + *waverpc.ExportOORRecoveryPackageResponse, error) { + + out := new(waverpc.ExportOORRecoveryPackageResponse) + err := c.client.Post( + ctx, "/v1/daemon/export-oor-recovery-package", in, out, + ) + + return out, err +} + +// PrepareArkChannelOOR reserves daemon liquidity for a channel-policy output. +func (c *DaemonServiceClient) PrepareArkChannelOOR(ctx context.Context, + in *waverpc.PrepareArkChannelOORRequest, _ ...grpc.CallOption) ( + *waverpc.PrepareArkChannelOORResponse, error) { + + out := new(waverpc.PrepareArkChannelOORResponse) + err := c.client.Post( + ctx, "/v1/daemon/prepare-ark-channel-oor", in, out, + ) + + return out, err +} + +// LookupPreparedArkChannelOOR reconciles a deterministic daemon reservation. +func (c *DaemonServiceClient) LookupPreparedArkChannelOOR(ctx context.Context, + in *waverpc.LookupPreparedArkChannelOORRequest, _ ...grpc.CallOption) ( + *waverpc.LookupPreparedArkChannelOORResponse, error) { + + out := new(waverpc.LookupPreparedArkChannelOORResponse) + err := c.client.Post( + ctx, "/v1/daemon/lookup-prepared-ark-channel-oor", in, out, + ) + + return out, err +} + +// ValidatePreparedArkChannelOOR checks an existing daemon reservation. +func (c *DaemonServiceClient) ValidatePreparedArkChannelOOR(ctx context.Context, + in *waverpc.ValidatePreparedArkChannelOORRequest, + _ ...grpc.CallOption) (*waverpc.ValidatePreparedArkChannelOORResponse, + error) { + + out := new(waverpc.ValidatePreparedArkChannelOORResponse) + err := c.client.Post( + ctx, "/v1/daemon/validate-prepared-ark-channel-oor", in, out, + ) + + return out, err +} + +// CommitPreparedArkChannelOOR releases a safely backed channel OOR. +func (c *DaemonServiceClient) CommitPreparedArkChannelOOR(ctx context.Context, + in *waverpc.CommitPreparedArkChannelOORRequest, _ ...grpc.CallOption) ( + *waverpc.CommitPreparedArkChannelOORResponse, error) { + + out := new(waverpc.CommitPreparedArkChannelOORResponse) + err := c.client.Post( + ctx, "/v1/daemon/commit-prepared-ark-channel-oor", in, out, + ) + + return out, err +} + +// AbortPreparedArkChannelOOR releases a channel reservation before PONR. +func (c *DaemonServiceClient) AbortPreparedArkChannelOOR(ctx context.Context, + in *waverpc.AbortPreparedArkChannelOORRequest, _ ...grpc.CallOption) ( + *waverpc.AbortPreparedArkChannelOORResponse, error) { + + out := new(waverpc.AbortPreparedArkChannelOORResponse) + err := c.client.Post( + ctx, "/v1/daemon/abort-prepared-ark-channel-oor", in, out, + ) + + return out, err +} + // SendVTXO initiates an in-round VTXO transfer. func (c *DaemonServiceClient) SendVTXO(ctx context.Context, in *waverpc.SendVTXORequest, _ ...grpc.CallOption) ( diff --git a/waved/ark_channel_expiry.go b/waved/ark_channel_expiry.go new file mode 100644 index 000000000..2a55b356d --- /dev/null +++ b/waved/ark_channel_expiry.go @@ -0,0 +1,277 @@ +package waved + +import ( + "context" + "fmt" + "time" + + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/arkchannel/oorbridge" + "github.com/lightningnetwork/lnd/clock" +) + +const ( + defaultArkChannelPrePONRTimeout = 10 * time.Minute + defaultArkChannelPrePONRScanInterval = 30 * time.Second + arkChannelPrePONRExpiryReason = "channel preparation expired " + + "before OOR commit" +) + +// prePONRResultController exposes the result-bearing abort used to distinguish +// a released reservation from an OOR whose commit already won the durable gate. +type prePONRResultController interface { + ValidatePreparedOOR(context.Context, arkchannel.Terms, + arkchannel.VTXOBinding) error + + AbortPreparedOORResult(context.Context, arkchannel.ID, arkchannel.Terms, + arkchannel.VTXOBinding, + string) (oorbridge.TerminalResult, error) +} + +// withArkChannelControllerDefaults installs process-owned clocks. +func withArkChannelControllerDefaults( + cfg ArkChannelControllerConfig) ArkChannelControllerConfig { + + if cfg.Clock == nil { + cfg.Clock = clock.NewDefaultClock() + } + + return cfg +} + +// startPrePONRReaper starts one controller-lifetime maintenance loop. Client +// controllers start this before lnd or the hub is available so an abandoned +// local wallet reservation can still expire autonomously. +func (c *NativeArkChannelController) startPrePONRReaper( + parent context.Context) { + + if c.reaperCancel != nil { + return + } + ctx, cancel := context.WithCancel(context.WithoutCancel(parent)) + c.reaperCancel = cancel + c.reaperWG.Add(1) + go func() { + defer c.reaperWG.Done() + + for { + c.mu.RLock() + service := c.service + c.mu.RUnlock() + err := c.maintainPrePONRChannels( + ctx, service, c.cfg.Clock.Now(), + ) + _ = tolerateNativeArkChannelFailures( + ctx, err, c.cfg.Log, + "Ark channel pre-PONR maintenance failed", + ) + + select { + case <-ctx.Done(): + return + + case <-c.cfg.Clock.TickAfter( + defaultArkChannelPrePONRScanInterval, + ): + } + } + }() +} + +// maintainPrePONRChannels reconciles only deterministic OOR keys, then expires +// local-funder work whose commit action has not become durable. It never calls +// the wallet input-selection path. +func (c *NativeArkChannelController) maintainPrePONRChannels( + ctx context.Context, service *arkchannel.Service, now time.Time) error { + + records, err := c.coordinator.ListNonTerminal(ctx) + if err != nil { + return err + } + failures := make([]arkchannel.ResumeFailure, 0) + for _, record := range records { + if err := c.maintainPrePONRChannel( + ctx, service, record, now, + ); err != nil { + + failures = append(failures, arkchannel.ResumeFailure{ + ChannelID: record.Snapshot.Terms.ID, + Err: err, + }) + } + } + if len(failures) != 0 { + return &arkchannel.ResumeFailures{Failures: failures} + } + + return nil +} + +// maintainPrePONRChannel repairs the crash windows around one local OOR +// preparation and records a definitive abort before lnd cleanup is resumed. +func (c *NativeArkChannelController) maintainPrePONRChannel(ctx context.Context, + service *arkchannel.Service, record arkchannel.Record, + now time.Time) error { + + snapshot := record.Snapshot + if snapshot.Terms.Funder != c.party || + (!snapshot.OORPreparationStarted && snapshot.Source == nil) { + return nil + } + if snapshot.Phase != arkchannel.PhaseRequested && + snapshot.Phase != arkchannel.PhaseNegotiating && + snapshot.Phase != arkchannel.PhaseCancelling { + return nil + } + + controller, err := c.prePONRController() + if err != nil { + return err + } + if snapshot.Source == nil { + if c.cfg.LookupOOR == nil { + return fmt.Errorf("Ark channel OOR lookup is " + + "unavailable") + } + lookup, err := c.cfg.LookupOOR( + ctx, snapshot.Terms, arkchannel.DefaultBackingFee, + ) + if err != nil { + return err + } + switch lookup.Status { + case oorbridge.PreparationAbsent: + if !prePONRExpired(record, now) { + return nil + } + expiry := &arkchannel.ExpirePrePONR{ + Reason: arkChannelPrePONRExpiryReason, + } + _, _, err := c.coordinator.Apply( + ctx, snapshot.Terms.ID, expiry, + ) + + return err + + case oorbridge.PreparationPending: + return nil + + case oorbridge.PreparationAccepted: + return fmt.Errorf("channel OOR advanced without a " + + "durable source binding") + + case oorbridge.PreparationPrepared: + if err := controller.ValidatePreparedOOR( + ctx, snapshot.Terms, lookup.Binding, + ); err != nil { + return err + } + record, _, err = c.coordinator.Apply( + ctx, snapshot.Terms.ID, &arkchannel.BindVTXO{ + Binding: lookup.Binding, + }, + ) + if err != nil { + return err + } + snapshot = record.Snapshot + + default: + return fmt.Errorf("unknown channel OOR preparation "+ + "status %d", lookup.Status) + } + } + + // A client-funded promotion records the recovered source locally before + // replaying the idempotent peer binding. This prevents a second local + // OOR selection if the peer is temporarily unavailable. + if c.party == arkchannel.PartyClient && c.remote != nil && + snapshot.Source != nil && + (snapshot.Phase == arkchannel.PhaseRequested || + snapshot.Phase == arkchannel.PhaseNegotiating) { + + if _, err := c.remote.BindPreparedOOR( + ctx, snapshot.Terms.ID, *snapshot.Source, + ); err != nil { + return err + } + } + + if snapshot.Phase != arkchannel.PhaseCancelling { + if !prePONRExpired(record, now) { + return nil + } + record, _, err = c.coordinator.Apply( + ctx, snapshot.Terms.ID, &arkchannel.ExpirePrePONR{ + Reason: arkChannelPrePONRExpiryReason, + }, + ) + if err != nil { + return err + } + snapshot = record.Snapshot + if snapshot.Phase != arkchannel.PhaseCancelling { + return nil + } + } + + result, err := controller.AbortPreparedOORResult( + ctx, snapshot.Terms.ID, snapshot.Terms, *snapshot.Source, + snapshot.Failure, + ) + if err != nil { + return err + } + if result.Finalized { + return fmt.Errorf("channel OOR commit won while pre-PONR " + + "cancellation was pending") + } + if err := result.Validate(); err != nil { + return err + } + _, _, err = c.coordinator.Apply( + ctx, snapshot.Terms.ID, &arkchannel.OORAborted{ + SessionID: snapshot.Source.OORSessionID, + Reason: result.Reason, + }, + ) + if err != nil { + return err + } + if service == nil { + return nil + } + _, err = service.ResumeChannelAction(ctx, snapshot.Terms.ID) + + return err +} + +// prePONRController returns the OOR controller owned by this endpoint's funder. +func (c *NativeArkChannelController) prePONRController() ( + prePONRResultController, error) { + + var candidate arkchannel.OORTransferController + if c.cfg.FundingOOR != nil { + candidate = c.cfg.FundingOOR + } else if c.cfg.OOR != nil { + candidate = c.cfg.OOR + } + controller, ok := candidate.(prePONRResultController) + if !ok { + return nil, fmt.Errorf("result-bearing Ark channel OOR " + + "controller is required") + } + + return controller, nil +} + +// prePONRExpired reports whether the durable preparation lease elapsed. +func prePONRExpired(record arkchannel.Record, now time.Time) bool { + if record.PrePONRStartedAt.IsZero() || + now.Before(record.PrePONRStartedAt) { + return false + } + + return now.Sub(record.PrePONRStartedAt) >= + defaultArkChannelPrePONRTimeout +} diff --git a/waved/ark_channel_expiry_test.go b/waved/ark_channel_expiry_test.go new file mode 100644 index 000000000..a52a28531 --- /dev/null +++ b/waved/ark_channel_expiry_test.go @@ -0,0 +1,245 @@ +package waved + +import ( + "bytes" + "context" + "testing" + "time" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil/v2" + "github.com/btcsuite/btcd/chainhash/v2" + "github.com/btcsuite/btcd/wire/v2" + "github.com/btcsuite/btclog/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/arkchannel/oorbridge" + "github.com/lightninglabs/wavelength/db" + "github.com/lightningnetwork/lnd/clock" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/stretchr/testify/require" +) + +// testPrePONROORController returns one configured abort result. +type testPrePONROORController struct { + aborts int + result oorbridge.TerminalResult +} + +// ValidatePreparedOOR accepts a fixture already validated by the FSM. +func (*testPrePONROORController) ValidatePreparedOOR(context.Context, + arkchannel.Terms, arkchannel.VTXOBinding) error { + + return nil +} + +// CommitPreparedOOR is unused by maintenance tests. +func (*testPrePONROORController) CommitPreparedOOR(context.Context, + arkchannel.ID, arkchannel.Terms, arkchannel.VTXOBinding) error { + + return nil +} + +// AbortPreparedOOR is unused by the result-bearing maintenance path. +func (*testPrePONROORController) AbortPreparedOOR(context.Context, + arkchannel.ID, arkchannel.Terms, arkchannel.VTXOBinding, string) error { + + return nil +} + +// AbortPreparedOORResult records one definitive pre-PONR abort. +func (c *testPrePONROORController) AbortPreparedOORResult(context.Context, + arkchannel.ID, arkchannel.Terms, arkchannel.VTXOBinding, string) ( + oorbridge.TerminalResult, error) { + + c.aborts++ + + return c.result, nil +} + +// TestMaintainPrePONRExpiresAbsentPreparation proves an armed request releases +// its durable FSM reservation without selecting replacement wallet inputs. +func TestMaintainPrePONRExpiresAbsentPreparation(t *testing.T) { + t.Parallel() + + now := time.Unix(10_000, 0).UTC() + controller, coordinator, terms, closeStore := testPrePONRController( + t, now, oorbridge.PreparationLookup{ + Status: oorbridge.PreparationAbsent, + }, + ) + defer closeStore() + + record, err := coordinator.Request(t.Context(), terms) + require.NoError(t, err) + _, _, err = coordinator.Apply( + t.Context(), terms.ID, &arkchannel.OORPreparationStarted{}, + ) + require.NoError(t, err) + require.True(t, record.PrePONRStartedAt.IsZero()) + + err = controller.maintainPrePONRChannels( + t.Context(), nil, now.Add(defaultArkChannelPrePONRTimeout), + ) + require.NoError(t, err) + record, err = coordinator.Get(t.Context(), terms.ID) + require.NoError(t, err) + require.Equal(t, arkchannel.PhaseFailed, record.Snapshot.Phase) + require.Equal(t, arkChannelPrePONRExpiryReason, + record.Snapshot.Failure) +} + +// TestMaintainPrePONRRecoversThenAbortsPreparedOOR proves restart maintenance +// binds the deterministic winner before recording its authoritative abort. +func TestMaintainPrePONRRecoversThenAbortsPreparedOOR(t *testing.T) { + t.Parallel() + + now := time.Unix(20_000, 0).UTC() + terms := testPrePONRTerms(t) + binding := testPrePONRBinding(t, terms) + controller, coordinator, _, closeStore := testPrePONRController( + t, now, oorbridge.PreparationLookup{ + Status: oorbridge.PreparationPrepared, Binding: binding, + }, + ) + defer closeStore() + resultController, ok := + controller.cfg.FundingOOR.(*testPrePONROORController) + require.True(t, ok) + + _, err := coordinator.Request(t.Context(), terms) + require.NoError(t, err) + _, _, err = coordinator.Apply( + t.Context(), terms.ID, &arkchannel.OORPreparationStarted{}, + ) + require.NoError(t, err) + + err = controller.maintainPrePONRChannels( + t.Context(), nil, now.Add(defaultArkChannelPrePONRTimeout), + ) + require.NoError(t, err) + record, err := coordinator.Get(t.Context(), terms.ID) + require.NoError(t, err) + require.Equal(t, arkchannel.PhaseCancelling, record.Snapshot.Phase) + require.NotNil(t, record.Snapshot.Source) + require.True(t, record.Snapshot.OORAborted) + require.Equal(t, 1, resultController.aborts) +} + +// testPrePONRController constructs a SQL-backed coordinator at a stable time. +func testPrePONRController(t *testing.T, now time.Time, + lookup oorbridge.PreparationLookup) (*NativeArkChannelController, + *arkchannel.Coordinator, arkchannel.Terms, func()) { + + t.Helper() + raw, err := db.NewStoreFromConfig( + db.DefaultConfig( + t.TempDir(), + ), + btclog.Disabled, + ) + require.NoError(t, err) + testClock := clock.NewTestClock(now) + channelStore := raw.NewArkChannelStore(testClock) + coordinator, err := arkchannel.NewCoordinator(channelStore) + require.NoError(t, err) + resultController := &testPrePONROORController{ + result: oorbridge.TerminalResult{ + Aborted: true, Reason: arkChannelPrePONRExpiryReason, + }, + } + controller := &NativeArkChannelController{ + party: arkchannel.PartyHub, + cfg: ArkChannelControllerConfig{ + FundingOOR: resultController, + LookupOOR: func(context.Context, arkchannel.Terms, + btcutil.Amount) (oorbridge.PreparationLookup, + error) { + + return lookup, nil + }, + Clock: testClock, Log: btclog.Disabled, + }, + coordinator: coordinator, + } + + return controller, coordinator, testPrePONRTerms(t), func() { + require.NoError(t, raw.Close()) + } +} + +// testPrePONRTerms creates valid hub-funded receive terms. +func testPrePONRTerms(t *testing.T) arkchannel.Terms { + t.Helper() + + newKey := func() [33]byte { + privateKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + var key [33]byte + copy(key[:], privateKey.PubKey().SerializeCompressed()) + + return key + } + + return arkchannel.Terms{ + ID: arkchannel.ID{ + 1, + 2, + 3, + }, Kind: arkchannel.KindReceiveIntent, + Funder: arkchannel.PartyHub, + PendingChannelID: [32]byte{ + 4, + 5, + 6, + }, + ReservedSCID: lnwire.ShortChannelID{ + BlockHeight: 16_000_000, TxIndex: 1, + }.ToUint64(), + Capacity: 100_000, + ClientNodeKey: newKey(), + HubNodeKey: newKey(), + PaymentHash: [32]byte{ + 9, + 9, + 9, + }, + VTXO: arkchannel.VTXOTerms{ + ClientArkKey: newKey(), HubArkKey: newKey(), + ArkOperatorKey: newKey(), ClientChannelKey: newKey(), + HubChannelKey: newKey(), FunderKey: newKey(), + ChannelDelay: 144, FunderDelay: 576, MinExitDelay: 144, + }, + } +} + +// testPrePONRBinding creates the exact prepared channel-policy output. +func testPrePONRBinding(t *testing.T, + terms arkchannel.Terms) arkchannel.VTXOBinding { + + t.Helper() + policy, pkScript, err := terms.VTXO.Artifacts() + require.NoError(t, err) + tx := wire.NewMsgTx(2) + tx.AddTxIn(&wire.TxIn{PreviousOutPoint: wire.OutPoint{ + Hash: chainhash.Hash{10}, + }}) + tx.AddTxOut(&wire.TxOut{Value: int64( + terms.Capacity + arkchannel.DefaultBackingFee, + ), PkScript: pkScript}) + var raw bytes.Buffer + require.NoError(t, tx.Serialize(&raw)) + sessionID := [32]byte(tx.TxHash()) + + return arkchannel.VTXOBinding{ + OORSessionID: sessionID, + OutPoint: wire.OutPoint{ + Hash: chainhash.Hash(sessionID), + }, + Amount: terms.Capacity + arkchannel.DefaultBackingFee, + ArkTransaction: raw.Bytes(), PolicyTemplate: policy, + PkScript: pkScript, + } +} + +var _ arkchannel.OORTransferController = (*testPrePONROORController)(nil) +var _ prePONRResultController = (*testPrePONROORController)(nil) diff --git a/waved/ark_channel_oor.go b/waved/ark_channel_oor.go new file mode 100644 index 000000000..2fa7cf483 --- /dev/null +++ b/waved/ark_channel_oor.go @@ -0,0 +1,307 @@ +package waved + +import ( + "context" + "errors" + "fmt" + "math" + "time" + + "github.com/btcsuite/btcd/btcutil/v2" + "github.com/btcsuite/btcd/wire/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/arkchannel/oorbridge" + "github.com/lightninglabs/wavelength/lib/arkscript" + oortx "github.com/lightninglabs/wavelength/lib/tx/oor" + "github.com/lightninglabs/wavelength/wallet" +) + +// lookupArkChannelOOR reconciles one deterministic channel transfer without +// selecting or locking fresh VTXOs. Startup maintenance must use this path. +func (s *Server) lookupArkChannelOOR(ctx context.Context, + terms arkchannel.Terms, backingFee btcutil.Amount) ( + oorbridge.PreparationLookup, error) { + + controller, err := oorbridge.New(s.actorSystem) + if err != nil { + return oorbridge.PreparationLookup{}, err + } + + return controller.LookupChannelPreparation(ctx, terms, backingFee) +} + +// prepareArkChannelOOR reserves ordinary wallet VTXOs and prepares the exact +// transfer that creates one channel-policy VTXO. The channel FSM commits or +// aborts the prepared OOR after native lnd funding reaches its durable gate. +func (s *Server) prepareArkChannelOOR(ctx context.Context, + terms arkchannel.Terms, backingFee btcutil.Amount) ( + arkchannel.VTXOBinding, error) { + + if !s.walletRef.IsSome() { + return arkchannel.VTXOBinding{}, fmt.Errorf("Ark channel " + + "wallet actor is not initialized") + } + if s.vtxoStore == nil { + return arkchannel.VTXOBinding{}, fmt.Errorf("Ark channel " + + "VTXO store is not initialized") + } + if backingFee <= 0 || terms.Capacity > + btcutil.Amount(math.MaxInt64)-backingFee { + return arkchannel.VTXOBinding{}, fmt.Errorf("invalid Ark " + + "channel backing amount") + } + controller, err := oorbridge.New(s.actorSystem) + if err != nil { + return arkchannel.VTXOBinding{}, err + } + recovered, found, err := controller.LookupPreparedChannel( + ctx, terms, backingFee, + ) + if err != nil { + return arkchannel.VTXOBinding{}, err + } + if found { + return recovered, nil + } + operatorTerms, err := s.fetchOperatorTerms(ctx) + if err != nil { + return arkchannel.VTXOBinding{}, err + } + target := terms.Capacity + backingFee + walletRef := s.walletRef.UnsafeFromSome() + result := walletRef.Ask(ctx, &wallet.SelectAndLockVTXOsRequest{ + TargetAmount: target, + MinChangeAmount: operatorTerms.MinVTXOAmountFloor(), + }).Await(ctx) + response, err := result.Unpack() + if err != nil { + return arkchannel.VTXOBinding{}, fmt.Errorf("select Ark "+ + "channel VTXOs: %w", err) + } + locked, ok := response.(*wallet.SelectAndLockVTXOsResponse) + if !ok { + return arkchannel.VTXOBinding{}, fmt.Errorf("unexpected VTXO "+ + "selection response %T", response) + } + rpcServer := &RPCServer{server: s} + fail := func(err error) (arkchannel.VTXOBinding, error) { + rpcServer.unlockSelectedVTXOsBestEffort(ctx, locked) + + return arkchannel.VTXOBinding{}, err + } + + outpoints := make([]wire.OutPoint, 0, len(locked.SelectedVTXOs)) + for _, selected := range locked.SelectedVTXOs { + outpoints = append(outpoints, selected.Outpoint) + } + inputs, err := BuildTransferInputs(ctx, s.vtxoStore, outpoints) + if err != nil { + return fail(fmt.Errorf("build Ark channel inputs: %w", err)) + } + inputTotal, err := sumOORInputAmounts(inputs) + if err != nil { + return fail(fmt.Errorf("sum Ark channel inputs: %w", err)) + } + if inputTotal < target { + return fail( + fmt.Errorf("selected Ark channel inputs total "+ + "%d, need %d", inputTotal, target), + ) + } + + var changeOutput *oortx.RecipientOutput + change := inputTotal - target + if change > 0 { + if change < operatorTerms.MinVTXOAmountFloor() { + return fail( + fmt.Errorf("Ark channel change %d is below "+ + "the VTXO floor", change), + ) + } + output, err := rpcServer.buildOORChangeRecipient( + ctx, operatorTerms.PubKey, operatorTerms.VTXOExitDelay, + change, + ) + if err != nil { + return fail(err) + } + changeOutput = &output + } + + prepared, err := controller.PrepareChannel( + ctx, oorbridge.PrepareRequest{ + Terms: terms, + CheckpointPolicy: arkscript.CheckpointPolicy{ + OperatorKey: operatorTerms.PubKey, + CSVDelay: operatorTerms.VTXOExitDelay, + }, + Inputs: inputs, + BackingFee: backingFee, + ChangeOutput: changeOutput, + }, + ) + if err != nil { + if errors.Is(err, arkchannel.ErrOORPreparationAmbiguous) { + lookupCtx, cancel := context.WithTimeout( + context.WithoutCancel(ctx), + submittedOORUnlockTimeout, + ) + lookup, lookupErr := + controller.LookupChannelPreparation( + lookupCtx, terms, backingFee, + ) + cancel() + if lookupErr != nil { + s.reconcileArkChannelPreparation( + ctx, controller, terms, backingFee, + locked, outpoints, + ) + + return arkchannel.VTXOBinding{}, errors.Join( + err, lookupErr, + ) + } + + switch lookup.Status { + case oorbridge.PreparationAbsent: + return fail(err) + + case oorbridge.PreparationPrepared: + if !sameChannelPreparationInputs( + lookup.InputOutpoints, outpoints, + ) { + + rpcServer.unlockSelectedVTXOsBestEffort( + context.WithoutCancel(ctx), + locked, + ) + } + + return lookup.Binding, nil + + case oorbridge.PreparationPending: + s.reconcileArkChannelPreparation( + ctx, controller, terms, backingFee, + locked, outpoints, + ) + + return arkchannel.VTXOBinding{}, err + + case oorbridge.PreparationAccepted: + if len(lookup.InputOutpoints) > 0 && + !sameChannelPreparationInputs( + lookup.InputOutpoints, + outpoints, + ) { + + rpcServer.unlockSelectedVTXOsBestEffort( + context.WithoutCancel(ctx), + locked, + ) + } + + return arkchannel.VTXOBinding{}, err + } + } + + return fail(err) + } + if prepared.Existing { + rpcServer.unlockSelectedVTXOsBestEffort(ctx, locked) + } + + return prepared.Binding, nil +} + +// reconcileArkChannelPreparation owns a canceled caller's selected locks until +// the registry proves either a durable owner or a failed/no-session admission. +func (s *Server) reconcileArkChannelPreparation(ctx context.Context, + controller *oorbridge.Controller, terms arkchannel.Terms, + backingFee btcutil.Amount, locked *wallet.SelectAndLockVTXOsResponse, + selected []wire.OutPoint) { + + rpcServer := &RPCServer{server: s} + unlockVTXOs := rpcServer.unlockSelectedVTXOsBestEffort + cleanupCtx, cancel := context.WithTimeout( + context.WithoutCancel(ctx), submittedOORCleanupTimeout, + ) + go func() { + defer cancel() + + ticker := time.NewTicker(50 * time.Millisecond) + defer ticker.Stop() + for { + lookup, err := controller.LookupChannelPreparation( + cleanupCtx, terms, backingFee, + ) + if err == nil { + switch lookup.Status { + case oorbridge.PreparationAbsent: + unlockVTXOs( + cleanupCtx, locked, + ) + + return + + case oorbridge.PreparationPending: + // The accepted registry request may + // still create the durable session that + // owns these locks. + + case oorbridge.PreparationPrepared: + if !sameChannelPreparationInputs( + lookup.InputOutpoints, selected, + ) { + + unlockVTXOs( + cleanupCtx, locked, + ) + } + + return + + case oorbridge.PreparationAccepted: + if len(lookup.InputOutpoints) > 0 && + !sameChannelPreparationInputs( + lookup.InputOutpoints, + selected, + ) { + + unlockVTXOs( + cleanupCtx, locked, + ) + } + + return + } + } + + select { + case <-cleanupCtx.Done(): + return + + case <-ticker.C: + } + } + }() +} + +// sameChannelPreparationInputs compares selections as sets so an idempotent +// winner with different inputs cannot retain a retry's fresh wallet locks. +func sameChannelPreparationInputs(first, second []wire.OutPoint) bool { + if len(first) != len(second) { + return false + } + counts := make(map[wire.OutPoint]int, len(first)) + for _, outpoint := range first { + counts[outpoint]++ + } + for _, outpoint := range second { + if counts[outpoint] == 0 { + return false + } + counts[outpoint]-- + } + + return true +} diff --git a/waved/ark_channel_process.go b/waved/ark_channel_process.go new file mode 100644 index 000000000..43b2c8cfd --- /dev/null +++ b/waved/ark_channel_process.go @@ -0,0 +1,706 @@ +package waved + +import ( + "context" + "fmt" + "path/filepath" + "time" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil/v2" + "github.com/btcsuite/btcd/chaincfg/v2" + "github.com/btcsuite/btcd/chainhash/v2" + "github.com/btcsuite/btclog/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/arkchannel/oorbridge" + "github.com/lightninglabs/wavelength/arkchannel/unrollbridge" + "github.com/lightninglabs/wavelength/chainbackends" + "github.com/lightninglabs/wavelength/chainfees" + "github.com/lightninglabs/wavelength/chainsource" + "github.com/lightninglabs/wavelength/db" + "github.com/lightninglabs/wavelength/lib/types" + "github.com/lightninglabs/wavelength/lnruntime" + "github.com/lightninglabs/wavelength/lwwallet" + mailboxrpc "github.com/lightninglabs/wavelength/mailbox/rpc" + "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" + "github.com/lightninglabs/wavelength/serverconn" + "github.com/lightningnetwork/lnd/clock" + fn "github.com/lightningnetwork/lnd/fn/v2" + "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const arkChannelMailboxRuntimePrefix = "arkchannel-serverconn-" + +const arkChannelPeerIngressPrefix = "arkchannel-peer-ingress-" + +const arkChannelControllerPollInterval = 25 * time.Millisecond + +const arkChannelCloseReceiveScriptLabel = "ark channel cooperative close" + +// ArkChannelLifecycleController owns channel creation, inspection, and close. +type ArkChannelLifecycleController interface { + PromoteVTXO(context.Context, btcutil.Amount) (arkchannel.Record, error) + + MaterializeAndForceClose(context.Context, arkchannel.ID) ( + arkchannel.Record, chainhash.Hash, chainhash.Hash, error) + + RequestCooperativeClose(context.Context, + arkchannel.ID) (arkchannel.Record, error) + + GetChannel(context.Context, arkchannel.ID) (arkchannel.Record, error) + + PeerMessageHandler() lnruntime.PeerEventHandler + + Stop() error +} + +// ArkChannelPaymentController owns the private/public payment bridge surface. +type ArkChannelPaymentController interface { + SendPayment(context.Context, arkchannel.ID, + btcutil.Amount) (lntypes.Hash, error) + + ReceivePayment(context.Context, arkchannel.ID, + btcutil.Amount) (lntypes.Hash, error) + + PayLightningInvoice(context.Context, string, + btcutil.Amount) (LightningPaymentResult, error) + + PrepareIncomingPayment(context.Context, lntypes.Preimage, + btcutil.Amount) error + + RegisterIncomingPayment(context.Context, lntypes.Hash, btcutil.Amount, + uint64) error + + WaitIncomingPayment(context.Context, + lntypes.Hash) (arkchannel.ID, error) +} + +// ArkChannelController is the complete local process boundary exposed through +// the daemon's ArkChannelService. +type ArkChannelController interface { + ArkChannelLifecycleController + ArkChannelPaymentController +} + +// ArkChannelRecoveryController is the complete endpoint-local source archive, +// watcher, and unroll preparation boundary. +type ArkChannelRecoveryController interface { + lnruntime.ChannelRecoveryManager + arkchannel.ChannelEventSinkBinder + unrollbridge.SourcePreparer + + RestoreWatches(context.Context, []arkchannel.Record) error + + Stop() +} + +// ArkChannelOORPreparer reserves wallet VTXOs and prepares the exact OOR +// transfer that creates a channel-policy VTXO. +type ArkChannelOORPreparer func(context.Context, arkchannel.Terms, + btcutil.Amount) (arkchannel.VTXOBinding, error) + +// ArkChannelOORLookup reconciles a deterministic channel OOR key without +// selecting or locking fresh wallet inputs. +type ArkChannelOORLookup func(context.Context, arkchannel.Terms, + btcutil.Amount) (oorbridge.PreparationLookup, error) + +// ArkChannelReceiveCapitalReserver durably reserves global hub capital before +// an armed receive intent is allowed to select funding inputs. +type ArkChannelReceiveCapitalReserver func(context.Context, + arkchannel.Terms) error + +// ArkChannelControllerConfig contains the process-owned dependencies supplied +// after wallet, database, and authenticated swap-server transport startup. +type ArkChannelControllerConfig struct { + Log btclog.Logger + Store *db.ArkChannelStoreDB + Peer lnruntime.ProcessCooperativeClosePeer + PeerRPC mailboxrpc.RPCClient + PeerSender lnruntime.PeerEventSender + Wallet *lwwallet.Wallet + ChainBackend chainsource.ChainBackend + ChainNotifier *chainbackends.BackendChainNotifier + FeeEstimator *chainfees.BackendEstimator + OOR *oorbridge.Controller + FundingOOR arkchannel.OORTransferController + Materializer *unrollbridge.Controller + Recovery ArkChannelRecoveryController + OperatorTerms *types.OperatorTerms + IdentityKey keychain.KeyDescriptor + OORDestination *btcec.PublicKey + KeyIndex uint32 + NetParams *chaincfg.Params + ChannelDataDir string + PrepareOOR ArkChannelOORPreparer + LookupOOR ArkChannelOORLookup + ReserveReceiveCapital ArkChannelReceiveCapitalReserver + Clock clock.Clock + RecordObserver arkchannel.RecordObserver +} + +// arkChannelRPCServer exposes the configured controller on waved's existing +// authenticated local gRPC listener. +type arkChannelRPCServer struct { + arkchannelrpc.UnimplementedArkChannelServiceServer + + server *Server +} + +// PromoteVTXO creates an OOR-backed native channel from existing wallet +// liquidity using daemon-derived protocol parameters. +func (s *arkChannelRPCServer) PromoteVTXO(ctx context.Context, + req *arkchannelrpc.PromoteVTXORequest) ( + *arkchannelrpc.PromoteVTXOResponse, error) { + + amount, err := arkChannelAmount(req.GetAmountSat()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + controller := s.server.getArkChannelController() + if controller == nil { + return nil, status.Error( + codes.Unavailable, "Ark channel runtime is not ready", + ) + } + record, err := controller.PromoteVTXO(ctx, amount) + if err != nil { + return nil, status.Errorf(codes.FailedPrecondition, "promote "+ + "VTXO: %v", err) + } + + return &arkchannelrpc.PromoteVTXOResponse{ + Channel: lnruntime.ArkChannelRecordToRPC(record), + }, nil +} + +// SendPayment pays a hub invoice over one active native channel. +func (s *arkChannelRPCServer) SendPayment(ctx context.Context, + req *arkchannelrpc.ChannelPaymentRequest) ( + *arkchannelrpc.ChannelPaymentResponse, error) { + + return s.channelPayment(ctx, req, false) +} + +// ReceivePayment creates and settles a client invoice over one active native +// channel. +func (s *arkChannelRPCServer) ReceivePayment(ctx context.Context, + req *arkchannelrpc.ChannelPaymentRequest) ( + *arkchannelrpc.ChannelPaymentResponse, error) { + + return s.channelPayment(ctx, req, true) +} + +// PayLightningInvoice bridges a private source HTLC into the operator's +// public Lightning payment lifecycle with one shared payment hash. +func (s *arkChannelRPCServer) PayLightningInvoice(ctx context.Context, + req *arkchannelrpc.PayLightningInvoiceRequest) ( + *arkchannelrpc.PayLightningInvoiceResponse, error) { + + if req.GetPaymentRequest() == "" { + return nil, status.Error( + codes.InvalidArgument, "payment request is required", + ) + } + if req.GetMaxFeeSat() > uint64(btcutil.MaxSatoshi) { + return nil, status.Error( + codes.InvalidArgument, + "maximum fee exceeds maximum money", + ) + } + controller := s.server.getArkChannelController() + if controller == nil { + return nil, status.Error( + codes.Unavailable, "Ark channel runtime is not ready", + ) + } + result, err := controller.PayLightningInvoice( + ctx, req.GetPaymentRequest(), + btcutil.Amount( + req.GetMaxFeeSat(), + ), + ) + if err != nil { + return nil, status.Errorf(codes.FailedPrecondition, "pay "+ + "Lightning invoice: %v", err) + } + + return &arkchannelrpc.PayLightningInvoiceResponse{ + PaymentHash: result.PaymentHash[:], + Preimage: result.Preimage[:], + PrivateAmountSat: int64(result.PrivateAmount), + FeeSat: int64(result.Fee), + ChannelId: result.ChannelID[:], + }, nil +} + +// channelPayment validates a local payment request and dispatches it through +// the process-owned native channel controller. +func (s *arkChannelRPCServer) channelPayment(ctx context.Context, + req *arkchannelrpc.ChannelPaymentRequest, receive bool) ( + *arkchannelrpc.ChannelPaymentResponse, error) { + + id, err := arkChannelID(req.GetChannelId()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + amount, err := arkChannelAmount(req.GetAmountSat()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + controller := s.server.getArkChannelController() + if controller == nil { + return nil, status.Error( + codes.Unavailable, "Ark channel runtime is not ready", + ) + } + var hash lntypes.Hash + if receive { + hash, err = controller.ReceivePayment(ctx, id, amount) + } else { + hash, err = controller.SendPayment(ctx, id, amount) + } + if err != nil { + return nil, status.Errorf(codes.FailedPrecondition, "channel "+ + "payment: %v", err) + } + + return &arkchannelrpc.ChannelPaymentResponse{ + PaymentHash: hash[:], Settled: true, + }, nil +} + +// MaterializeAndForceClose publishes the Ark ancestry, signed backing, and +// latest native lnd commitment transaction. +func (s *arkChannelRPCServer) MaterializeAndForceClose(ctx context.Context, + req *arkchannelrpc.MaterializeAndForceCloseRequest) ( + *arkchannelrpc.MaterializeAndForceCloseResponse, error) { + + id, err := arkChannelID(req.GetChannelId()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + controller := s.server.getArkChannelController() + if controller == nil { + return nil, status.Error( + codes.Unavailable, "Ark channel runtime is not ready", + ) + } + record, backingTxID, commitmentTxID, err := + controller.MaterializeAndForceClose(ctx, id) + if err != nil { + return nil, status.Errorf(codes.FailedPrecondition, + "materialize and force close: %v", err) + } + + return &arkchannelrpc.MaterializeAndForceCloseResponse{ + Channel: lnruntime.ArkChannelRecordToRPC(record), + BackingTxid: backingTxID[:], + CommitmentTxid: commitmentTxID[:], + }, nil +} + +// RequestCooperativeClose starts or resumes the client-owned close process. +func (s *arkChannelRPCServer) RequestCooperativeClose(ctx context.Context, + req *arkchannelrpc.RequestCooperativeCloseRequest) ( + *arkchannelrpc.RequestCooperativeCloseResponse, error) { + + id, err := arkChannelID(req.GetChannelId()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + controller := s.server.getArkChannelController() + if controller == nil { + return nil, status.Error( + codes.Unavailable, "Ark channel runtime is not ready", + ) + } + record, err := controller.RequestCooperativeClose(ctx, id) + if err != nil { + return nil, status.Errorf(codes.FailedPrecondition, "request "+ + "cooperative close: %v", err) + } + + return &arkchannelrpc.RequestCooperativeCloseResponse{ + Channel: lnruntime.ArkChannelRecordToRPC(record), + }, nil +} + +// GetChannel returns one local durable Ark channel summary. +func (s *arkChannelRPCServer) GetChannel(ctx context.Context, + req *arkchannelrpc.GetChannelRequest) ( + *arkchannelrpc.GetChannelResponse, error) { + + id, err := arkChannelID(req.GetChannelId()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + controller := s.server.getArkChannelController() + if controller == nil { + return nil, status.Error( + codes.Unavailable, "Ark channel runtime is not ready", + ) + } + record, err := controller.GetChannel(ctx, id) + if err != nil { + return nil, status.Errorf(codes.NotFound, "get Ark channel: %v", + err) + } + + return &arkchannelrpc.GetChannelResponse{ + Channel: lnruntime.ArkChannelRecordToRPC(record), + }, nil +} + +// initArkChannelProcess builds the client channel runtime whenever the swap +// runtime has installed its authenticated mailbox edge. +func (s *Server) initArkChannelProcess(ctx context.Context) error { + if s.cfg.Swap == nil || s.cfg.Swap.ArkChannelMailbox == nil { + return nil + } + if s.clientKeyDesc.PubKey == nil { + return fmt.Errorf("Ark channel runtime requires client " + + "identity") + } + if s.arkChannelStore == nil { + return fmt.Errorf("Ark channel store is not initialized") + } + + localMailbox := serverconn.PubKeyMailboxID(s.clientKeyDesc.PubKey) + replyMailbox := lnruntime.ArkChannelClientMailboxID(localMailbox) + remoteMailbox := lnruntime.ArkChannelHubMailboxID(localMailbox) + connCfg := serverconn.DefaultConnectorConfig() + connCfg.RuntimeID = arkChannelMailboxRuntimePrefix + localMailbox + connCfg.Edge = s.cfg.Swap.ArkChannelMailbox + connCfg.LocalMailboxID = localMailbox + connCfg.ReplyMailboxID = replyMailbox + connCfg.RemoteMailboxID = remoteMailbox + connCfg.ArkProtocolVersion = s.arkProtocolVersion + connCfg.Store = s.deliveryStore + connCfg.Dispatchers = make( + map[mailboxrpc.ServiceMethod]serverconn.EnvelopeDispatcher, + ) + connCfg.Log = fn.Some(s.subLogger(serverconn.Subsystem)) + + //nolint:contextcheck // Start binds the runtime to the process context. + runtime, err := serverconn.NewRuntime(connCfg) + if err != nil { + return fmt.Errorf("create Ark channel mailbox runtime: %w", err) + } + // The mailbox runtime owns its worker context and cancels it in Stop. + //nolint:contextcheck + runtime.StartEgress() + peer, err := lnruntime.NewMailboxCooperativeClosePeer(runtime.Unary()) + if err != nil { + runtime.Stop() + + return err + } + peerSender, err := lnruntime.NewServerConnPeerSender(runtime.TellRef()) + if err != nil { + runtime.Stop() + + return err + } + controller, err := s.newClientArkChannelController( + ctx, peer, runtime.Unary(), peerSender, + ) + if err != nil { + runtime.Stop() + + return err + } + // The actor owns a process-lifetime context and is stopped by + // Server.Stop. + //nolint:contextcheck + peerIngress, err := lnruntime.NewPeerMessageIngress( + lnruntime.PeerMessageIngressConfig{ + ActorID: arkChannelPeerIngressPrefix + localMailbox, + Store: s.deliveryStore, + Handler: controller.PeerMessageHandler(), + Log: s.subLogger(Subsystem), + }, + ) + if err != nil { + _ = controller.Stop() + runtime.Stop() + + return fmt.Errorf("create Ark channel peer ingress: %w", err) + } + connCfg.Dispatchers[lnruntime.PeerMessageRoute()] = + peerIngress.Dispatcher() + if err := runtime.StartIngress(ctx); err != nil { + peerIngress.Stop() + _ = controller.Stop() + runtime.Stop() + + return fmt.Errorf("start Ark channel mailbox ingress: %w", err) + } + + s.setArkChannelProcess(runtime, controller, peerIngress) + + return nil +} + +// newClientArkChannelController composes the wallet, chain, OOR, and recovery +// dependencies behind the client channel controller. +func (s *Server) newClientArkChannelController(ctx context.Context, + peer lnruntime.ProcessCooperativeClosePeer, + peerRPC mailboxrpc.RPCClient, peerSender lnruntime.PeerEventSender) ( + *NativeArkChannelController, error) { + + if !s.lwWallet.IsSome() { + return nil, fmt.Errorf("Ark channel runtime requires lwwallet") + } + if s.chainBackend == nil { + return nil, fmt.Errorf("Ark channel runtime requires a chain " + + "backend") + } + if !s.unrollRegistryRef.IsSome() { + return nil, fmt.Errorf("Ark channel runtime requires the " + + "unroller") + } + chainNotifier, err := chainbackends.NewBackendChainNotifier( + s.chainBackend, + ) + if err != nil { + return nil, err + } + feeEstimator, err := chainfees.NewBackendEstimator( + s.chainBackend, chainfee.FeePerKwFloor, + ) + if err != nil { + return nil, err + } + oorController, err := oorbridge.New(s.actorSystem) + if err != nil { + return nil, err + } + recovery, err := newArkChannelRecoveryArchive( + s.vtxoStore, (&RPCServer{server: s}).newLocalOORArtifactStore(), + s.chainBackend, s.subLogger(Subsystem), + ) + if err != nil { + return nil, err + } + materializer, err := unrollbridge.NewController( + s.unrollRegistryRef.UnsafeFromSome(), recovery, + ) + if err != nil { + return nil, err + } + controller, err := NewClientArkChannelController( + ctx, ArkChannelControllerConfig{ + Log: s.subLogger(Subsystem), + Store: s.arkChannelStore, + Peer: peer, + PeerRPC: peerRPC, + PeerSender: peerSender, + Wallet: s.lwWallet.UnsafeFromSome(), + ChainBackend: s.chainBackend, + ChainNotifier: chainNotifier, + FeeEstimator: feeEstimator, + OOR: oorController, + Materializer: materializer, + Recovery: recovery, + IdentityKey: s.clientKeyDesc, + OORDestination: s.clientKeyDesc.PubKey, + NetParams: s.chainParams, + ChannelDataDir: filepath.Join( + s.cfg.DataDir, "ark-channels", + ), + PrepareOOR: s.prepareArkChannelOOR, + LookupOOR: s.lookupArkChannelOOR, + }, + ) + if err != nil { + return nil, fmt.Errorf("construct Ark channel controller: %w", + err) + } + if controller == nil { + return nil, fmt.Errorf("Ark channel controller factory " + + "returned nil") + } + + return controller, nil +} + +// ensureConfiguredArkChannelCloseDelivery registers the close destination +// once the main mailbox ingress is running. Registration is an indexer RPC and +// therefore cannot run while wallet-dependent actors are still being built. +func (s *Server) ensureConfiguredArkChannelCloseDelivery( + ctx context.Context) error { + + if s.cfg.Swap == nil || s.cfg.Swap.ArkChannelMailbox == nil { + return nil + } + operatorTerms, err := s.fetchOperatorTerms(ctx) + if err != nil { + return fmt.Errorf("fetch Ark channel close terms: %w", err) + } + + return s.ensureArkChannelCloseDelivery(ctx, operatorTerms) +} + +// ensureArkChannelCloseDelivery registers the durable identity-backed VTXO +// script before a close request can advertise it. The ordinary incoming OOR +// actor then owns materialization and fraud recovery for the replacement. +func (s *Server) ensureArkChannelCloseDelivery(ctx context.Context, + operatorTerms *types.OperatorTerms) error { + + if s.indexer == nil { + return fmt.Errorf("Ark channel close requires the indexer") + } + if operatorTerms == nil || operatorTerms.PubKey == nil { + return fmt.Errorf("Ark channel close requires operator terms") + } + store, err := (&RPCServer{server: s}).newOORReceiveScriptStore() + if err != nil { + return fmt.Errorf("initialize Ark channel close receive "+ + "store: %w", err) + } + signerFactory, err := s.indexerProofSignerFactory() + if err != nil { + return fmt.Errorf("initialize Ark channel close signer: %w", + err) + } + _, err = RegisterOwnedOORReceiveScript( + ctx, s.indexer, store, s.clientKeyDesc, signerFactory, + operatorTerms.PubKey, operatorTerms.VTXOExitDelay, + arkChannelCloseReceiveScriptLabel, + ) + if err != nil { + return fmt.Errorf("register Ark channel close destination: %w", + err) + } + + return nil +} + +// setArkChannelProcess publishes the controller and its transport together. +func (s *Server) setArkChannelProcess(runtime *serverconn.Runtime, + controller ArkChannelController, + peerIngress *lnruntime.PeerMessageIngress) { + + s.arkChannelMu.Lock() + defer s.arkChannelMu.Unlock() + + s.arkChannelMailboxRuntime = runtime + s.arkChannelController = controller + s.arkChannelPeerIngress = peerIngress +} + +// getArkChannelPeerIngress returns the durable BOLT ingress boundary. +func (s *Server) getArkChannelPeerIngress() *lnruntime.PeerMessageIngress { + s.arkChannelMu.RLock() + defer s.arkChannelMu.RUnlock() + + return s.arkChannelPeerIngress +} + +// getArkChannelController returns the initialized local controller. +func (s *Server) getArkChannelController() ArkChannelController { + s.arkChannelMu.RLock() + defer s.arkChannelMu.RUnlock() + + return s.arkChannelController +} + +// getArkChannelMailboxRuntime returns the initialized swap-server transport. +func (s *Server) getArkChannelMailboxRuntime() *serverconn.Runtime { + s.arkChannelMu.RLock() + defer s.arkChannelMu.RUnlock() + + return s.arkChannelMailboxRuntime +} + +// PrepareArkChannelIncomingPayment installs the deterministic native invoice +// before a public route hint is exposed. +func (r *RPCServer) PrepareArkChannelIncomingPayment(ctx context.Context, + preimage lntypes.Preimage, amount btcutil.Amount) error { + + controller, err := r.waitArkChannelController(ctx) + if err != nil { + return err + } + + return controller.PrepareIncomingPayment(ctx, preimage, amount) +} + +// RegisterArkChannelIncomingPayment binds a public future SCID to the +// authenticated client endpoint after its private invoice is durable. +func (r *RPCServer) RegisterArkChannelIncomingPayment(ctx context.Context, + hash lntypes.Hash, amount btcutil.Amount, reservedSCID uint64) error { + + controller, err := r.waitArkChannelController(ctx) + if err != nil { + return err + } + + return controller.RegisterIncomingPayment( + ctx, hash, amount, reservedSCID, + ) +} + +// WaitArkChannelIncomingPayment waits on lnd's durable private invoice. +func (r *RPCServer) WaitArkChannelIncomingPayment(ctx context.Context, + hash lntypes.Hash) (arkchannel.ID, error) { + + controller, err := r.waitArkChannelController(ctx) + if err != nil { + return arkchannel.ID{}, err + } + + return controller.WaitIncomingPayment(ctx, hash) +} + +// waitArkChannelController bridges optional subserver construction, which +// occurs before the mailbox-backed channel process is published at startup. +func (r *RPCServer) waitArkChannelController(ctx context.Context) ( + ArkChannelController, error) { + + if r == nil || r.server == nil { + return nil, fmt.Errorf("Ark channel daemon is not initialized") + } + ticker := time.NewTicker(arkChannelControllerPollInterval) + defer ticker.Stop() + for { + controller := r.server.getArkChannelController() + if controller != nil { + return controller, nil + } + + select { + case <-ctx.Done(): + return nil, ctx.Err() + + case <-ticker.C: + } + } +} + +// arkChannelID parses one fixed-width durable channel identifier. +func arkChannelID(raw []byte) (arkchannel.ID, error) { + var id arkchannel.ID + if len(raw) != len(id) { + return id, fmt.Errorf("channel id must be %d bytes, got %d", + len(id), len(raw)) + } + copy(id[:], raw) + + return id, nil +} + +// arkChannelAmount parses a strictly positive channel amount. +func arkChannelAmount(value int64) (btcutil.Amount, error) { + if value <= 0 { + return 0, fmt.Errorf("amount must be positive") + } + + return btcutil.Amount(value), nil +} + +var _ arkchannelrpc.ArkChannelServiceServer = (*arkChannelRPCServer)(nil) diff --git a/waved/ark_channel_process_test.go b/waved/ark_channel_process_test.go new file mode 100644 index 000000000..4dcf2342d --- /dev/null +++ b/waved/ark_channel_process_test.go @@ -0,0 +1,170 @@ +package waved + +import ( + "context" + "testing" + + "github.com/btcsuite/btcd/btcutil/v2" + "github.com/btcsuite/btcd/chainhash/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/lnruntime" + "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// arkChannelControllerStub records local RPC calls and returns a configured +// durable channel record. +type arkChannelControllerStub struct { + record arkchannel.Record + err error + id arkchannel.ID +} + +// PromoteVTXO is not used by close RPC tests. +func (s *arkChannelControllerStub) PromoteVTXO(context.Context, + btcutil.Amount) (arkchannel.Record, error) { + + return s.record, s.err +} + +// SendPayment is not used by close RPC tests. +func (s *arkChannelControllerStub) SendPayment(context.Context, arkchannel.ID, + btcutil.Amount) (lntypes.Hash, error) { + + return lntypes.Hash{}, s.err +} + +// ReceivePayment is not used by close RPC tests. +func (s *arkChannelControllerStub) ReceivePayment(context.Context, + arkchannel.ID, btcutil.Amount) (lntypes.Hash, error) { + + return lntypes.Hash{}, s.err +} + +// PayLightningInvoice is not used by close RPC tests. +func (s *arkChannelControllerStub) PayLightningInvoice(context.Context, string, + btcutil.Amount) (LightningPaymentResult, error) { + + return LightningPaymentResult{}, s.err +} + +// PrepareIncomingPayment is not used by close RPC tests. +func (s *arkChannelControllerStub) PrepareIncomingPayment(context.Context, + lntypes.Preimage, btcutil.Amount) error { + + return s.err +} + +// RegisterIncomingPayment is not used by close RPC tests. +func (s *arkChannelControllerStub) RegisterIncomingPayment(context.Context, + lntypes.Hash, btcutil.Amount, uint64) error { + + return s.err +} + +// WaitIncomingPayment is not used by close RPC tests. +func (s *arkChannelControllerStub) WaitIncomingPayment(context.Context, + lntypes.Hash) (arkchannel.ID, error) { + + return arkchannel.ID{}, s.err +} + +// MaterializeAndForceClose is not used by close RPC tests. +func (s *arkChannelControllerStub) MaterializeAndForceClose(context.Context, + arkchannel.ID) (arkchannel.Record, chainhash.Hash, chainhash.Hash, + error) { + + return s.record, chainhash.Hash{}, chainhash.Hash{}, s.err +} + +// RequestCooperativeClose records the parsed public request. +func (s *arkChannelControllerStub) RequestCooperativeClose(_ context.Context, + id arkchannel.ID) (arkchannel.Record, error) { + + s.id = id + + return s.record, s.err +} + +// GetChannel returns the configured channel record. +func (s *arkChannelControllerStub) GetChannel(_ context.Context, + id arkchannel.ID) (arkchannel.Record, error) { + + s.id = id + + return s.record, s.err +} + +// PeerMessageHandler returns an inert native peer handler for RPC-only tests. +// +//nolint:ll // The concrete method name and interface type are both significant. +func (*arkChannelControllerStub) PeerMessageHandler() lnruntime.PeerEventHandler { + return func(context.Context, lnwire.Message) error { + return nil + } +} + +// Stop is inert for the RPC-only controller stub. +func (*arkChannelControllerStub) Stop() error { + return nil +} + +// TestArkChannelRPCRequestCooperativeClose verifies fixed-width ID parsing and +// controller dispatch on the local authenticated RPC surface. +func TestArkChannelRPCRequestCooperativeClose(t *testing.T) { + t.Parallel() + + id := arkchannel.ID{1, 2, 3} + controller := &arkChannelControllerStub{ + record: arkchannel.Record{ + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: id, + }, + Phase: arkchannel.PhaseCoopClosing, + }, + Revision: 4, + }, + } + server := &Server{arkChannelController: controller} + rpcServer := &arkChannelRPCServer{server: server} + + response, err := rpcServer.RequestCooperativeClose( + t.Context(), &arkchannelrpc.RequestCooperativeCloseRequest{ + ChannelId: id[:], + }, + ) + require.NoError(t, err) + require.Equal(t, id, controller.id) + require.Equal(t, id[:], response.GetChannel().GetChannelId()) + require.Equal(t, uint64(4), response.GetChannel().GetRevision()) + + _, err = rpcServer.RequestCooperativeClose( + t.Context(), &arkchannelrpc.RequestCooperativeCloseRequest{ + ChannelId: []byte{1}, + }, + ) + require.Equal(t, codes.InvalidArgument, status.Code(err)) +} + +// TestArkChannelRPCUnavailable verifies the local service remains registered +// but fails explicitly when no compiled-in channel runtime was installed. +func TestArkChannelRPCUnavailable(t *testing.T) { + t.Parallel() + + id := arkchannel.ID{1} + rpcServer := &arkChannelRPCServer{server: &Server{}} + + _, err := rpcServer.GetChannel( + t.Context(), &arkchannelrpc.GetChannelRequest{ + ChannelId: id[:], + }, + ) + require.Equal(t, codes.Unavailable, status.Code(err)) +} + +var _ ArkChannelController = (*arkChannelControllerStub)(nil) diff --git a/waved/ark_channel_recovery_runtime.go b/waved/ark_channel_recovery_runtime.go new file mode 100644 index 000000000..b2dcb00ba --- /dev/null +++ b/waved/ark_channel_recovery_runtime.go @@ -0,0 +1,204 @@ +package waved + +import ( + "context" + "fmt" + "time" + + "github.com/btcsuite/btclog/v2" + "github.com/lightninglabs/lndclient" + "github.com/lightninglabs/wavelength/arkchannel/unrollbridge" + "github.com/lightninglabs/wavelength/baselib/actor" + "github.com/lightninglabs/wavelength/chainsource" + "github.com/lightninglabs/wavelength/db" + "github.com/lightninglabs/wavelength/db/actordelivery" + "github.com/lightninglabs/wavelength/ledger" + "github.com/lightninglabs/wavelength/lndbackend" + "github.com/lightninglabs/wavelength/txconfirm" + "github.com/lightninglabs/wavelength/unroll" + "github.com/lightningnetwork/lnd/clock" + fn "github.com/lightningnetwork/lnd/fn/v2" +) + +// ArkChannelUnrollWallet is the fee-input and sweep wallet surface shared by +// txconfirm and the ordinary VTXO unroller. +type ArkChannelUnrollWallet interface { + txconfirm.Wallet + unroll.SweepWallet +} + +// NewLNDArkChannelUnrollWallet adapts swapd's existing LND wallet for channel +// source recovery and CPFP fee management. +func NewLNDArkChannelUnrollWallet(signer lndclient.SignerClient, + walletKit lndclient.WalletKitClient, + chainKit lndclient.ChainKitClient) ArkChannelUnrollWallet { + + return &lndUnrollWallet{ + ClientWallet: lndbackend.NewClientWallet(signer, walletKit), + boardingBackend: lndbackend.NewBoardingBackend( + walletKit, chainKit, + ), + } +} + +// ArkChannelRecoveryRuntimeConfig contains the per-client durable store and +// process-owned chain dependencies needed by the common unroller. +type ArkChannelRecoveryRuntimeConfig struct { + Store *db.Store + ChannelStore *db.ArkChannelStoreDB + ChainBackend chainsource.ChainBackend + Wallet ArkChannelUnrollWallet + Log btclog.Logger +} + +// ArkChannelRecoveryRuntime owns the hub endpoint's unroll actors, package +// archive, source watches, and channel materializer. +type ArkChannelRecoveryRuntime struct { + actorSystem *actor.ActorSystem + registry *unroll.UnrollRegistryActor + recovery *arkChannelRecoveryArchive + materializer *unrollbridge.Controller +} + +// NewArkChannelRecoveryRuntime composes the same unroller used by waved while +// leaving ownership of the database, chain backend, and wallet with swapd. +// +//nolint:contextcheck // recovery actors own lifecycle until runtime Stop +func NewArkChannelRecoveryRuntime(ctx context.Context, + cfg ArkChannelRecoveryRuntimeConfig) (*ArkChannelRecoveryRuntime, + error) { + + switch { + case cfg.Store == nil || cfg.ChannelStore == nil: + return nil, fmt.Errorf("Ark channel recovery store is required") + + case cfg.ChainBackend == nil: + return nil, fmt.Errorf("Ark channel recovery chain backend " + + "is required") + + case cfg.Wallet == nil: + return nil, fmt.Errorf("Ark channel recovery wallet is " + + "required") + } + log := cfg.Log + if log == nil { + log = btclog.Disabled + } + actorSystem := actor.NewActorSystemWithConfig(actor.SystemConfig{ + MailboxCapacity: 100, Log: fn.Some(log), + }) + cleanup := true + defer func() { + if cleanup { + shutdownCtx, cancel := context.WithTimeout( + context.Background(), 5*time.Second, + ) + defer cancel() + _ = actorSystem.Shutdown(shutdownCtx) + } + }() + chainActor := chainsource.NewChainSourceActor( + chainsource.ChainSourceConfig{ + Backend: cfg.ChainBackend, System: actorSystem, + FinalityDepth: chainsource.DefaultFinalityDepth, + }, + ) + chainSource := actor.RegisterWithSystem( + actorSystem, "ark-channel-chain-source", + chainsource.ChainSourceKey, chainActor, + ) + deliveryStore, err := actordelivery.NewTxAwareDeliveryStoreFromDB( + cfg.Store.DB(), cfg.Store.Backend(), clock.NewDefaultClock(), + log, + ) + if err != nil { + return nil, err + } + txConfirm := txconfirm.NewTxBroadcasterActor(txconfirm.Config{ + ChainSource: chainSource, Wallet: cfg.Wallet, + Log: fn.Some(log), + }) + txConfirmRef := actor.RegisterWithSystem( + actorSystem, txconfirm.ServiceKeyName, + txconfirm.NewServiceKey(), txConfirm, + ) + txConfirm.SetSelfRef(txConfirmRef) + vtxoStore := cfg.Store.NewVTXOStore(clock.NewDefaultClock()) + oorStore := cfg.Store.NewOORArtifactStore(clock.NewDefaultClock()) + recovery, err := newArkChannelRecoveryArchive( + vtxoStore, oorStore, cfg.ChainBackend, log, + ) + if err != nil { + return nil, err + } + registry := unroll.NewUnrollRegistryActor(unroll.RegistryConfig{ + Store: &unroll.DBRegistryStore{ + UEStore: cfg.Store.NewUnilateralExitStore( + clock.NewDefaultClock(), + ), + }, + DeliveryStore: deliveryStore, + ProofAssembler: &unroll.LocalProofAssembler{ + VTXOStore: vtxoStore, ArtifactStore: oorStore, + }, + VTXOStore: vtxoStore, TxConfirmRef: txConfirmRef, + ChainSource: chainSource, Wallet: cfg.Wallet, + LedgerSink: fn.None[ledger.Sink](), + Log: fn.Some(log), + ExitSpendPolicyResolver: unroll.PolicyResolvers{ + unrollbridge.Resolver{Channels: cfg.ChannelStore}, + }, + }) + if err := registry.RestoreNonTerminal(ctx); err != nil { + registry.Stop() + recovery.Stop() + + return nil, fmt.Errorf("restore Ark channel unrolls: %w", err) + } + materializer, err := unrollbridge.NewController( + registry.Ref(), recovery, + ) + if err != nil { + registry.Stop() + recovery.Stop() + + return nil, err + } + cleanup = false + + return &ArkChannelRecoveryRuntime{ + actorSystem: actorSystem, registry: registry, + recovery: recovery, materializer: materializer, + }, nil +} + +// Recovery returns the package archive and source watcher. +func (r *ArkChannelRecoveryRuntime) Recovery() ArkChannelRecoveryController { + return r.recovery +} + +// Materializer returns the common-unroller channel adapter. +func (r *ArkChannelRecoveryRuntime) Materializer() *unrollbridge.Controller { + return r.materializer +} + +// Stop releases watches and actors without stopping externally owned chain or +// wallet backends. +func (r *ArkChannelRecoveryRuntime) Stop() error { + if r == nil { + return nil + } + if r.recovery != nil { + r.recovery.Stop() + } + if r.registry != nil { + r.registry.Stop() + } + if r.actorSystem == nil { + return nil + } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + return r.actorSystem.Shutdown(ctx) +} diff --git a/waved/ark_channel_source.go b/waved/ark_channel_source.go new file mode 100644 index 000000000..02e73405b --- /dev/null +++ b/waved/ark_channel_source.go @@ -0,0 +1,672 @@ +package waved + +import ( + "bytes" + "context" + "errors" + "fmt" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/psbt/v2" + "github.com/btcsuite/btcd/wire/v2" + "github.com/btcsuite/btclog/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/arkchannel/unrollbridge" + "github.com/lightninglabs/wavelength/arkrpc" + "github.com/lightninglabs/wavelength/chainsource" + "github.com/lightninglabs/wavelength/db" + "github.com/lightninglabs/wavelength/lib/tx/psbtutil" + "github.com/lightninglabs/wavelength/unroll" + "github.com/lightninglabs/wavelength/vtxo" + "github.com/lightningnetwork/lnd/keychain" +) + +// arkChannelRecoveryArchive exports and installs the exact finalized source +// package. The channel-policy VTXO is recovery-only, so it never appears in +// wallet balance, coin selection, refresh, or ordinary VTXO actor recovery. +type arkChannelRecoveryArchive struct { + vtxos *db.VTXOPersistenceStore + packages *db.OORArtifactPersistenceStore + watcher *arkChannelSourceWatcher +} + +// newArkChannelRecoveryArchive constructs one endpoint-local recovery store. +func newArkChannelRecoveryArchive(vtxos *db.VTXOPersistenceStore, + packages *db.OORArtifactPersistenceStore, + backend chainsource.ChainBackend, + log btclog.Logger) (*arkChannelRecoveryArchive, error) { + + switch { + case vtxos == nil: + return nil, fmt.Errorf("Ark channel VTXO store is required") + + case packages == nil: + return nil, fmt.Errorf("Ark channel OOR package store is " + + "required") + + case backend == nil: + return nil, fmt.Errorf("Ark channel chain backend is required") + } + + return &arkChannelRecoveryArchive{ + vtxos: vtxos, packages: packages, + watcher: newArkChannelSourceWatcher(backend, log), + }, nil +} + +// BindChannelEventSink connects confirmed ancestry spends to the channel FSM. +func (a *arkChannelRecoveryArchive) BindChannelEventSink( + sink arkchannel.ChannelEventSink) error { + + return a.watcher.BindChannelEventSink(sink) +} + +// ExportRecoveryPackage builds the endpoint-neutral package only after the +// funder's finalized OOR artifacts are durable. +func (a *arkChannelRecoveryArchive) ExportRecoveryPackage(ctx context.Context, + id arkchannel.ID, terms arkchannel.Terms, + source arkchannel.VTXOBinding) (arkchannel.RecoveryPackage, error) { + + if err := validateArkChannelRecoveryRequest( + id, terms, source, + ); err != nil { + return arkchannel.RecoveryPackage{}, err + } + recoverySource := arkchannel.OORRecoverySource{ + OutPoint: source.OutPoint, Amount: source.Amount, + PkScript: source.PkScript, + } + recovery, err := a.buildRecoveryPackage( + ctx, terms.VTXO.ArkOperatorKey, recoverySource, + ) + if err != nil { + return arkchannel.RecoveryPackage{}, err + } + desc, err := recoveryDescriptor(terms, source, recovery.Descriptor) + if err != nil { + return arkchannel.RecoveryPackage{}, err + } + if err := a.vtxos.SaveRecoveryOnlyVTXO(ctx, desc); err != nil { + return arkchannel.RecoveryPackage{}, fmt.Errorf("save Ark "+ + "channel recovery source: %w", err) + } + if err := a.packages.UpsertBinding( + ctx, source.OutPoint, source.OORSessionID, + source.OutPoint.Index, db.OORPackageLinkKindCreatedOutput, + ); err != nil { + return arkchannel.RecoveryPackage{}, fmt.Errorf("bind Ark "+ + "channel recovery source: %w", err) + } + if err := a.verifySourceLineage(ctx, source.OutPoint); err != nil { + return arkchannel.RecoveryPackage{}, fmt.Errorf("verify "+ + "exported Ark channel lineage: %w", err) + } + + return recovery, nil +} + +// ExportOORRecoveryPackage exports one exact sender-owned finalized OOR +// package. The expected operator key binds its round ancestry to the daemon's +// current Ark operator rather than to caller-provided channel terms. +func (a *arkChannelRecoveryArchive) ExportOORRecoveryPackage( + ctx context.Context, source arkchannel.OORRecoverySource, + operatorKey *btcec.PublicKey) (arkchannel.RecoveryPackage, error) { + + if err := source.Validate(); err != nil { + return arkchannel.RecoveryPackage{}, err + } + if operatorKey == nil { + return arkchannel.RecoveryPackage{}, fmt.Errorf("Ark " + + "operator key is required") + } + var serializedOperator [33]byte + copy(serializedOperator[:], operatorKey.SerializeCompressed()) + + return a.buildRecoveryPackage(ctx, serializedOperator, source) +} + +// buildRecoveryPackage resolves one sender-owned finalized OOR package and +// all locally known ancestors into endpoint-neutral recovery data. +func (a *arkChannelRecoveryArchive) buildRecoveryPackage(ctx context.Context, + expectedOperator [33]byte, source arkchannel.OORRecoverySource) ( + arkchannel.RecoveryPackage, error) { + + target, err := a.loadSourcePackage(ctx, source) + if err != nil { + return arkchannel.RecoveryPackage{}, err + } + roots, err := a.loadSourceRoots( + ctx, recoveryCheckpointInputs(target), + ) + if err != nil { + return arkchannel.RecoveryPackage{}, err + } + ancestry, err := recoveryAncestry(roots) + if err != nil { + return arkchannel.RecoveryPackage{}, err + } + roundID, commitmentTxID, batchExpiry, createdHeight := + recoveryRootMeta(roots) + if roundID == "" || commitmentTxID == ([32]byte{}) || + batchExpiry == 0 || createdHeight == 0 { + return arkchannel.RecoveryPackage{}, fmt.Errorf("Ark channel " + + "source root metadata incomplete") + } + if _, err := channelOperatorKey(expectedOperator, roots); err != nil { + return arkchannel.RecoveryPackage{}, err + } + // A sender persists the finalized package by session ID but does not + // normally own or bind the output it created for the recipient. Resolve + // from that immutable package identity before installing the output as + // shared recovery state. + resolved, err := a.packages.ResolveUnrollPackagesBySessionID( + ctx, source.OutPoint, source.OutPoint.Hash, + ) + if err != nil { + return arkchannel.RecoveryPackage{}, fmt.Errorf("resolve Ark "+ + "channel OOR lineage: %w", err) + } + if err := validateRecoveryPackageRoots( + ancestry, resolved.UnresolvedCheckpointInputs, + ); err != nil { + return arkchannel.RecoveryPackage{}, err + } + constructionVersion, err := recoveryConstructionVersion(roots) + if err != nil { + return arkchannel.RecoveryPackage{}, err + } + recovery := arkchannel.RecoveryPackage{ + Descriptor: arkchannel.RecoveryDescriptor{ + RoundID: roundID, CommitmentTxID: commitmentTxID, + BatchExpiry: batchExpiry, + ChainDepth: recoveryChainDepth( + roots, len(resolved.Packages), + ), + CreatedHeight: createdHeight, + ConstructionVersion: int32(constructionVersion), + }, + Packages: make( + []arkchannel.RecoveryOORPackage, 0, + len(resolved.Packages), + ), + } + for i := range ancestry { + treePath, err := db.SerializeTree(ancestry[i].TreePath) + if err != nil { + return arkchannel.RecoveryPackage{}, fmt.Errorf( + "serialize Ark channel ancestry %d: %w", i, err) + } + recovery.Descriptor.Ancestry = append( + recovery.Descriptor.Ancestry, + arkchannel.RecoveryAncestry{ + TreePath: treePath, + CommitmentTxID: ancestry[i].CommitmentTxID, + InputIndices: append( + []uint32(nil), + ancestry[i].InputIndices..., + ), + TreeDepth: ancestry[i].TreeDepth, + CommitmentHeight: ancestry[i].CommitmentHeight, + }, + ) + } + for i := range resolved.Packages { + entry, err := recoveryOORPackage(resolved.Packages[i]) + if err != nil { + return arkchannel.RecoveryPackage{}, fmt.Errorf( + "serialize Ark channel OOR package %d: %w", i, + err) + } + recovery.Packages = append(recovery.Packages, entry) + } + if err := recovery.ValidateOORSource(source); err != nil { + return arkchannel.RecoveryPackage{}, err + } + + return recovery, nil +} + +// InstallRecoveryPackage writes every artifact, validates local resolution, +// and arms all ancestry watches before returning the activation barrier. +func (a *arkChannelRecoveryArchive) InstallRecoveryPackage(ctx context.Context, + id arkchannel.ID, terms arkchannel.Terms, source arkchannel.VTXOBinding, + recovery arkchannel.RecoveryPackage) error { + + if err := validateArkChannelRecoveryRequest( + id, terms, source, + ); err != nil { + return err + } + if err := recovery.Validate(source); err != nil { + return err + } + for i := range recovery.Packages { + entry := recovery.Packages[i] + arkPSBT, checkpoints, err := parseRecoveryOORPackage(entry) + if err != nil { + return fmt.Errorf("parse Ark channel OOR package "+ + "%d: %w", i, err) + } + if err := a.packages.UpsertPackage( + ctx, db.OORPackageDirection(entry.Direction), + entry.SessionID, arkPSBT, checkpoints, + ); err != nil { + return fmt.Errorf("store Ark channel OOR package "+ + "%d: %w", i, err) + } + } + desc, err := recoveryDescriptor(terms, source, recovery.Descriptor) + if err != nil { + return err + } + existing, err := a.vtxos.GetVTXO(ctx, source.OutPoint) + switch { + case err == nil: + // Recovery installation is replayable after a close path has + // selected its final CSV delay. Preserve that mutable field + // while SaveRecoveryOnlyVTXO verifies every immutable + // descriptor field. + desc.RelativeExpiry = existing.RelativeExpiry + + case !errors.Is(err, vtxo.ErrVTXONotFound): + return fmt.Errorf("load Ark channel recovery source: %w", err) + } + if err := a.vtxos.SaveRecoveryOnlyVTXO(ctx, desc); err != nil { + return fmt.Errorf("save Ark channel recovery source: %w", err) + } + if err := a.packages.UpsertBinding( + ctx, source.OutPoint, source.OORSessionID, + source.OutPoint.Index, db.OORPackageLinkKindCreatedOutput, + ); err != nil { + return fmt.Errorf("bind Ark channel OOR source: %w", err) + } + if err := a.verifySourceLineage(ctx, source.OutPoint); err != nil { + return fmt.Errorf("verify installed Ark channel lineage: %w", + err) + } + if err := a.watcher.Track(ctx, id, desc); err != nil { + return fmt.Errorf("watch Ark channel source: %w", err) + } + + return nil +} + +// RestoreWatches re-arms every channel whose Ark source still secures either +// an open channel or the replacement VTXOs from a cooperative close. +func (a *arkChannelRecoveryArchive) RestoreWatches(ctx context.Context, + records []arkchannel.Record) error { + + for i := range records { + snapshot := records[i].Snapshot + if !shouldRestoreArkChannelSourceWatch(snapshot) { + continue + } + desc, err := a.vtxos.GetVTXO(ctx, snapshot.Source.OutPoint) + if err != nil { + return fmt.Errorf("restore Ark channel recovery "+ + "source %x: %w", snapshot.Terms.ID[:4], err) + } + if err := a.watcher.Track( + ctx, snapshot.Terms.ID, desc, + ); err != nil { + return err + } + } + + return nil +} + +// shouldRestoreArkChannelSourceWatch reports whether confirmed ancestry can +// still require a durable channel action. Once conflict evidence is stored, +// Service.Resume owns retries and another chain registration is unnecessary. +func shouldRestoreArkChannelSourceWatch(snapshot arkchannel.Snapshot) bool { + if !snapshot.RecoveryReady || snapshot.Source == nil || + snapshot.SourceConflict != nil { + return false + } + if !snapshot.Phase.IsTerminal() { + return true + } + + return snapshot.Phase == arkchannel.PhaseClosed && + snapshot.CooperativeClose != nil +} + +// EnsureChannelSource selects the final-spend delay and verifies that the +// pre-activation recovery package remains complete for the common unroller. +func (a *arkChannelRecoveryArchive) EnsureChannelSource(ctx context.Context, + id arkchannel.ID, terms arkchannel.Terms, source arkchannel.VTXOBinding, + kind unroll.ExitPolicyKind) error { + + if err := validateArkChannelRecoveryRequest( + id, terms, source, + ); err != nil { + return err + } + csvDelay, err := channelSourceCSVDelay(terms, kind) + if err != nil { + return err + } + if err := a.vtxos.SetRecoveryOnlyVTXORelativeExpiry( + ctx, source.OutPoint, csvDelay, + ); err != nil { + return fmt.Errorf("set Ark channel recovery delay: %w", err) + } + if err := a.verifySourceLineage(ctx, source.OutPoint); err != nil { + return fmt.Errorf("verify Ark channel lineage: %w", err) + } + + return nil +} + +// verifySourceLineage runs the common production resolver against the exact +// recovery-only descriptor that a later unroll job will consume. +func (a *arkChannelRecoveryArchive) verifySourceLineage(ctx context.Context, + outpoint wire.OutPoint) error { + + resolver := unroll.DescriptorLineageResolver{ + VTXOStore: a.vtxos, + ArtifactStore: a.packages, + } + _, err := resolver.ResolveLineage(ctx, outpoint) + + return err +} + +// validateRecoveryPackageRoots accepts package traversal endpoints only when +// the transported round ancestry supplies the transaction they spend. +func validateRecoveryPackageRoots(ancestry []vtxo.Ancestry, + unresolved []wire.OutPoint) error { + + if len(unresolved) == 0 { + return nil + } + treeOutputs := make(map[wire.OutPoint]struct{}) + for i := range ancestry { + fragment := ancestry[i] + if fragment.TreePath == nil || fragment.TreePath.Root == nil { + return fmt.Errorf("Ark channel ancestry %d has no tree", + i) + } + for node := range fragment.TreePath.Root.NodesIter() { + tx, err := node.ToTx() + if err != nil { + return fmt.Errorf("build Ark channel ancestry "+ + "%d: %w", i, err) + } + txID := tx.TxHash() + for outputIndex := range tx.TxOut { + treeOutputs[wire.OutPoint{ + Hash: txID, Index: uint32(outputIndex), + }] = struct{}{} + } + } + } + for _, outpoint := range unresolved { + if _, ok := treeOutputs[outpoint]; !ok { + return fmt.Errorf("Ark channel OOR lineage is "+ + "missing root %s", outpoint) + } + } + + return nil +} + +// Stop releases all passive source watches. +func (a *arkChannelRecoveryArchive) Stop() { + if a != nil && a.watcher != nil { + a.watcher.Stop() + } +} + +// loadSourcePackage verifies that the finalized target package creates the +// exact channel-policy output committed by the FSM. +func (a *arkChannelRecoveryArchive) loadSourcePackage(ctx context.Context, + source arkchannel.OORRecoverySource) (*db.OORPackageBundle, error) { + + pkg, err := a.packages.GetPackage(ctx, source.OutPoint.Hash) + if err != nil { + return nil, fmt.Errorf("load Ark channel OOR package: %w", err) + } + if pkg.ArkPSBT == nil || pkg.ArkPSBT.UnsignedTx == nil { + return nil, fmt.Errorf("Ark channel OOR package has no " + + "transaction") + } + tx := pkg.ArkPSBT.UnsignedTx + if pkg.SessionID != source.OutPoint.Hash || + tx.TxHash() != source.OutPoint.Hash { + return nil, fmt.Errorf("Ark channel OOR package ID mismatch") + } + if int(source.OutPoint.Index) >= len(tx.TxOut) { + return nil, fmt.Errorf("Ark channel OOR output is out of range") + } + output := tx.TxOut[source.OutPoint.Index] + if output.Value != int64(source.Amount) || + !bytes.Equal(output.PkScript, source.PkScript) { + return nil, fmt.Errorf("Ark channel OOR output mismatch") + } + if len(pkg.FinalCheckpointPSBTs) == 0 { + return nil, fmt.Errorf("Ark channel OOR package has no " + + "checkpoints") + } + + return pkg, nil +} + +// loadSourceRoots loads the wallet VTXOs consumed by the channel OOR package. +func (a *arkChannelRecoveryArchive) loadSourceRoots(ctx context.Context, + outpoints []wire.OutPoint) ([]*vtxo.Descriptor, error) { + + if len(outpoints) == 0 { + return nil, fmt.Errorf("Ark channel OOR package has no roots") + } + roots := make([]*vtxo.Descriptor, 0, len(outpoints)) + for _, outpoint := range outpoints { + desc, err := a.vtxos.GetVTXO(ctx, outpoint) + if err != nil { + return nil, fmt.Errorf("load Ark channel root %s: %w", + outpoint, err) + } + if len(desc.Ancestry) == 0 { + return nil, fmt.Errorf("Ark channel root %s has no "+ + "ancestry", outpoint) + } + roots = append(roots, desc) + } + + return roots, nil +} + +// channelOperatorKey verifies that the channel and all roots share one Ark +// operator under BIP-340 x-only key semantics. +func channelOperatorKey(expectedOperator [33]byte, + roots []*vtxo.Descriptor) (*btcec.PublicKey, error) { + + operatorKey, err := btcec.ParsePubKey(expectedOperator[:]) + if err != nil { + return nil, fmt.Errorf("parse Ark channel operator key: %w", + err) + } + rootOperatorKey, err := recoveryOperatorKey(roots) + if err != nil { + return nil, err + } + if !bytes.Equal( + schnorr.SerializePubKey(operatorKey), + schnorr.SerializePubKey(rootOperatorKey), + ) { + return nil, fmt.Errorf("Ark channel operator does not match " + + "roots") + } + + return operatorKey, nil +} + +// recoveryConstructionVersion requires every contributing root to use the +// same Ark construction rules. +func recoveryConstructionVersion(roots []*vtxo.Descriptor) ( + arkrpc.ConstructionVersion, error) { + + if len(roots) == 0 || roots[0] == nil { + return 0, fmt.Errorf("Ark channel recovery roots are empty") + } + version := roots[0].ConstructionVersion + for i := 1; i < len(roots); i++ { + if roots[i] == nil || roots[i].ConstructionVersion != version { + return 0, fmt.Errorf("Ark channel roots use multiple " + + "construction versions") + } + } + + return version, nil +} + +// recoveryOORPackage serializes one persisted OOR package for transport. +func recoveryOORPackage(pkg *db.OORPackageBundle) ( + arkchannel.RecoveryOORPackage, error) { + + if pkg == nil || pkg.ArkPSBT == nil { + return arkchannel.RecoveryOORPackage{}, fmt.Errorf("package " + + "is nil") + } + arkPSBT, err := psbtutil.Serialize(pkg.ArkPSBT) + if err != nil { + return arkchannel.RecoveryOORPackage{}, err + } + entry := arkchannel.RecoveryOORPackage{ + SessionID: pkg.SessionID, Direction: int32(pkg.Direction), + ArkPSBT: arkPSBT, + Checkpoints: make([][]byte, len(pkg.FinalCheckpointPSBTs)), + } + for i := range pkg.FinalCheckpointPSBTs { + entry.Checkpoints[i], err = psbtutil.Serialize( + pkg.FinalCheckpointPSBTs[i], + ) + if err != nil { + return arkchannel.RecoveryOORPackage{}, err + } + } + + return entry, nil +} + +// parseRecoveryOORPackage decodes and verifies one transported package. +func parseRecoveryOORPackage(entry arkchannel.RecoveryOORPackage) (*psbt.Packet, + []*psbt.Packet, error) { + + arkPSBT, err := psbt.NewFromRawBytes( + bytes.NewReader(entry.ArkPSBT), false, + ) + if err != nil { + return nil, nil, err + } + if arkPSBT.UnsignedTx == nil || + arkPSBT.UnsignedTx.TxHash() != entry.SessionID { + return nil, nil, fmt.Errorf("OOR session ID does not match " + + "Ark tx") + } + checkpoints := make([]*psbt.Packet, len(entry.Checkpoints)) + for i := range entry.Checkpoints { + checkpoints[i], err = psbt.NewFromRawBytes( + bytes.NewReader(entry.Checkpoints[i]), false, + ) + if err != nil { + return nil, nil, fmt.Errorf("checkpoint %d: %w", i, err) + } + if checkpoints[i].UnsignedTx == nil { + return nil, nil, fmt.Errorf("checkpoint %d has no tx", + i) + } + } + + return arkPSBT, checkpoints, nil +} + +// recoveryDescriptor reconstructs the local recovery-only VTXO descriptor. +func recoveryDescriptor(terms arkchannel.Terms, source arkchannel.VTXOBinding, + recovery arkchannel.RecoveryDescriptor) (*vtxo.Descriptor, error) { + + clientKey, err := btcec.ParsePubKey(terms.VTXO.ClientArkKey[:]) + if err != nil { + return nil, err + } + operatorKey, err := btcec.ParsePubKey(terms.VTXO.ArkOperatorKey[:]) + if err != nil { + return nil, err + } + ancestry := make([]vtxo.Ancestry, len(recovery.Ancestry)) + for i := range recovery.Ancestry { + treePath, err := db.DeserializeTree( + recovery.Ancestry[i].TreePath, + ) + if err != nil { + return nil, fmt.Errorf("decode Ark channel ancestry "+ + "%d: %w", i, err) + } + ancestry[i] = vtxo.Ancestry{ + TreePath: treePath, + CommitmentTxID: recovery.Ancestry[i].CommitmentTxID, + InputIndices: append( + []uint32(nil), + recovery.Ancestry[i].InputIndices..., + ), + TreeDepth: recovery.Ancestry[i].TreeDepth, + CommitmentHeight: recovery.Ancestry[i].CommitmentHeight, + } + } + + return &vtxo.Descriptor{ + Outpoint: source.OutPoint, Amount: source.Amount, + PolicyTemplate: append([]byte(nil), source.PolicyTemplate...), + PkScript: append([]byte(nil), source.PkScript...), + ClientKey: keychain.KeyDescriptor{ + PubKey: clientKey, + }, + OperatorKey: operatorKey, Ancestry: ancestry, + RoundID: recovery.RoundID, + CommitmentTxID: recovery.CommitmentTxID, + BatchExpiry: recovery.BatchExpiry, + // The non-interactive fallback is the pre-signed client+hub + // channel path. Persist its delay before watches are armed so a + // confirmed ancestor cannot race proof assembly against a later + // mutable update. Cooperative close uses the ordinary OOR actor + // and never enters the unroller. + RelativeExpiry: terms.VTXO.ChannelDelay, + ChainDepth: recovery.ChainDepth, + CreatedHeight: recovery.CreatedHeight, + Status: vtxo.VTXOStatusRecoveryOnly, + ConstructionVersion: arkrpc.ConstructionVersion( + recovery.ConstructionVersion, + ), + }, nil +} + +// validateArkChannelRecoveryRequest binds all archive operations to one FSM. +func validateArkChannelRecoveryRequest(id arkchannel.ID, terms arkchannel.Terms, + source arkchannel.VTXOBinding) error { + + if id != terms.ID { + return fmt.Errorf("Ark channel ID does not match terms") + } + if err := terms.Validate(); err != nil { + return err + } + + return source.Validate(terms) +} + +// channelSourceCSVDelay selects the delay of the exact final spend policy. +func channelSourceCSVDelay(terms arkchannel.Terms, + kind unroll.ExitPolicyKind) (uint32, error) { + + if kind != unrollbridge.ExitPolicyKind { + return 0, fmt.Errorf("unsupported Ark channel exit policy %q", + kind) + } + + return terms.VTXO.ChannelDelay, nil +} + +var _ unrollbridge.SourcePreparer = (*arkChannelRecoveryArchive)(nil) +var _ arkchannel.ChannelEventSinkBinder = (*arkChannelRecoveryArchive)(nil) diff --git a/waved/ark_channel_source_test.go b/waved/ark_channel_source_test.go new file mode 100644 index 000000000..efa51b68f --- /dev/null +++ b/waved/ark_channel_source_test.go @@ -0,0 +1,295 @@ +package waved + +import ( + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil/v2" + "github.com/btcsuite/btcd/wire/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/arkchannel/unrollbridge" + "github.com/lightninglabs/wavelength/db" + "github.com/lightninglabs/wavelength/lnruntime" + "github.com/lightninglabs/wavelength/vtxo" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/stretchr/testify/require" +) + +// TestValidateRecoveryPackageRoots distinguishes an expected package boundary +// at a transported round tree from an actually missing OOR ancestor. +func TestValidateRecoveryPackageRoots(t *testing.T) { + t.Parallel() + + treePath, treeOutput := sourceWatcherTree(t, 42) + ancestry := []vtxo.Ancestry{ + { + TreePath: treePath, + }, + } + require.NoError( + t, + validateRecoveryPackageRoots( + ancestry, []wire.OutPoint{treeOutput}, + ), + ) + wrongIndex := treeOutput + wrongIndex.Index++ + require.ErrorContains( + t, + validateRecoveryPackageRoots( + ancestry, []wire.OutPoint{wrongIndex}, + ), + "missing root", + ) + require.ErrorContains( + t, + validateRecoveryPackageRoots( + ancestry, []wire.OutPoint{sourceWatcherOutpoint(43)}, + ), + "missing root", + ) +} + +// TestRecoveryDescriptorUsesBackingDelay proves a parent spend cannot race +// recovery proof assembly against selection of the pre-signed channel path. +func TestRecoveryDescriptorUsesBackingDelay(t *testing.T) { + t.Parallel() + + clientKey := testKeyDescriptor(t, 31) + operatorKey := testKeyDescriptor(t, 32) + terms := arkchannel.Terms{ + VTXO: arkchannel.VTXOTerms{ + ChannelDelay: 144, + }, + } + copy( + terms.VTXO.ClientArkKey[:], + clientKey.PubKey.SerializeCompressed(), + ) + copy( + terms.VTXO.ArkOperatorKey[:], + operatorKey.PubKey.SerializeCompressed(), + ) + treePath, target := sourceWatcherTree(t, 33) + rawTree, err := db.SerializeTree(treePath) + require.NoError(t, err) + + desc, err := recoveryDescriptor( + terms, arkchannel.VTXOBinding{ + OutPoint: target, + Amount: 100_000, + }, arkchannel.RecoveryDescriptor{ + Ancestry: []arkchannel.RecoveryAncestry{ + {TreePath: rawTree}, + }, + }, + ) + require.NoError(t, err) + require.Equal(t, terms.VTXO.ChannelDelay, desc.RelativeExpiry) + require.Equal(t, vtxo.VTXOStatusRecoveryOnly, desc.Status) + + backingDelay, err := channelSourceCSVDelay( + terms, unrollbridge.ExitPolicyKind, + ) + require.NoError(t, err) + require.Equal(t, terms.VTXO.ChannelDelay, backingDelay) + _, err = channelSourceCSVDelay(terms, "cooperative_close") + require.ErrorContains(t, err, "unsupported") +} + +// TestShouldRestoreArkChannelSourceWatch verifies a cooperative close remains +// protected after its lnd channel has been archived. +func TestShouldRestoreArkChannelSourceWatch(t *testing.T) { + t.Parallel() + + source := &arkchannel.VTXOBinding{ + OutPoint: wire.OutPoint{ + Index: 1, + }, + } + cooperativeClose := &arkchannel.CooperativeClose{} + tests := []struct { + name string + snapshot arkchannel.Snapshot + restore bool + }{ + { + name: "active", + snapshot: arkchannel.Snapshot{ + Phase: arkchannel.PhaseActive, + Source: source, RecoveryReady: true, + }, + restore: true, + }, + { + name: "cooperatively closed", + snapshot: arkchannel.Snapshot{ + Phase: arkchannel.PhaseClosed, + Source: source, RecoveryReady: true, + CooperativeClose: cooperativeClose, + }, + restore: true, + }, + { + name: "ordinary closed", + snapshot: arkchannel.Snapshot{ + Phase: arkchannel.PhaseClosed, + Source: source, RecoveryReady: true, + }, + }, + { + name: "conflict already durable", + snapshot: arkchannel.Snapshot{ + Phase: arkchannel.PhaseClosed, + Source: source, RecoveryReady: true, + CooperativeClose: cooperativeClose, + SourceConflict: &arkchannel.SourceConflict{ + OutPoint: wire.OutPoint{ + Index: 2, + }, + }, + }, + }, + { + name: "recovery not installed", + snapshot: arkchannel.Snapshot{ + Phase: arkchannel.PhaseActive, Source: source, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + require.Equal( + t, test.restore, + shouldRestoreArkChannelSourceWatch( + test.snapshot, + ), + ) + }) + } +} + +// TestReceiveIntentTermsAreDeterministic proves invoice replay derives the same +// channel identity without consulting chain height or random state. +func TestReceiveIntentTermsAreDeterministic(t *testing.T) { + identity := testKeyDescriptor(t, 1) + arkKey := testKeyDescriptor(t, 2) + backingKey := testKeyDescriptor(t, 3) + funderKey := testKeyDescriptor(t, 4) + hubNode := testKeyDescriptor(t, 5) + hubArk := testKeyDescriptor(t, 6) + hubBacking := testKeyDescriptor(t, 7) + operator := testKeyDescriptor(t, 8) + hubFunder := testKeyDescriptor(t, 9) + controller := &NativeArkChannelController{ + cfg: ArkChannelControllerConfig{ + IdentityKey: identity, + }, + keys: nativeArkChannelKeys{ + ark: arkKey, backing: backingKey, funder: funderKey, + }, + peerInfo: lnruntime.FundingPeerInfo{ + ChannelDelay: 144, FunderDelay: 576, + MinimumExitDelay: 144, + }, + } + copy( + controller.peerInfo.HubNodeKey[:], + hubNode.PubKey.SerializeCompressed(), + ) + copy( + controller.peerInfo.HubArkKey[:], + hubArk.PubKey.SerializeCompressed(), + ) + copy( + controller.peerInfo.HubChannelKey[:], + hubBacking.PubKey.SerializeCompressed(), + ) + copy( + controller.peerInfo.ArkOperatorKey[:], + operator.PubKey.SerializeCompressed(), + ) + copy( + controller.peerInfo.HubFunderKey[:], + hubFunder.PubKey.SerializeCompressed(), + ) + + hash := lntypes.Hash{9} + first, err := controller.newReceiveIntentTerms( + hash, 1<<63|42, btcutil.Amount(50_000), + ) + require.NoError(t, err) + second, err := controller.newReceiveIntentTerms( + hash, 1<<63|42, btcutil.Amount(50_000), + ) + require.NoError(t, err) + require.Equal(t, first, second) + require.Equal(t, arkchannel.KindReceiveIntent, first.Kind) + require.Equal(t, arkchannel.PartyHub, first.Funder) + require.Equal(t, controller.peerInfo.HubFunderKey, first.VTXO.FunderKey) + require.Equal(t, hash, lntypes.Hash(first.PaymentHash)) + require.Equal(t, uint64(1<<63|42), first.ReservedSCID) + + other, err := controller.newReceiveIntentTerms( + lntypes.Hash{10}, 1<<63|43, btcutil.Amount(50_000), + ) + require.NoError(t, err) + require.NotEqual(t, first.ID, other.ID) + require.NotEqual(t, first.PendingChannelID, other.PendingChannelID) +} + +// TestChannelOperatorKeyAcceptsOppositeParity verifies that Ark operator +// identity follows the x-only script key rather than compressed-key parity. +func TestChannelOperatorKeyAcceptsOppositeParity(t *testing.T) { + privKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + + terms := arkchannel.Terms{} + copy( + terms.VTXO.ArkOperatorKey[:], + privKey.PubKey().SerializeCompressed(), + ) + + oppositeBytes := privKey.PubKey().SerializeCompressed() + if oppositeBytes[0] == 0x02 { + oppositeBytes[0] = 0x03 + } else { + oppositeBytes[0] = 0x02 + } + oppositeKey, err := btcec.ParsePubKey(oppositeBytes) + require.NoError(t, err) + require.False(t, privKey.PubKey().IsEqual(oppositeKey)) + + operatorKey, err := channelOperatorKey( + terms.VTXO.ArkOperatorKey, []*vtxo.Descriptor{ + {OperatorKey: oppositeKey}, + }, + ) + require.NoError(t, err) + require.True(t, operatorKey.IsEqual(privKey.PubKey())) +} + +// TestChannelOperatorKeyRejectsDifferentKey verifies that unrelated Ark +// operator keys cannot reuse the persisted ancestry. +func TestChannelOperatorKeyRejectsDifferentKey(t *testing.T) { + operatorKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + rootKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + + terms := arkchannel.Terms{} + copy( + terms.VTXO.ArkOperatorKey[:], + operatorKey.PubKey().SerializeCompressed(), + ) + + _, err = channelOperatorKey( + terms.VTXO.ArkOperatorKey, []*vtxo.Descriptor{ + {OperatorKey: rootKey.PubKey()}, + }, + ) + require.ErrorContains(t, err, "operator does not match roots") +} diff --git a/waved/ark_channel_source_watcher.go b/waved/ark_channel_source_watcher.go new file mode 100644 index 000000000..ca9054b2e --- /dev/null +++ b/waved/ark_channel_source_watcher.go @@ -0,0 +1,236 @@ +package waved + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/btcsuite/btclog/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/chainsource" + "github.com/lightninglabs/wavelength/fraud" + "github.com/lightninglabs/wavelength/vtxo" +) + +// arkChannelSourceWatcher passively watches every on-path source ancestor and +// turns the first confirmed spend into a durable channel event. +type arkChannelSourceWatcher struct { + backend chainsource.ChainBackend + log btclog.Logger + ctx context.Context //nolint:containedctx // owned until Stop + cancel context.CancelFunc + + mu sync.Mutex + sink arkchannel.ChannelEventSink + registrations map[arkchannel.ID][]*chainsource.SpendRegistration + retryDelay time.Duration + wg sync.WaitGroup +} + +// newArkChannelSourceWatcher constructs an endpoint-local passive watcher. +func newArkChannelSourceWatcher(backend chainsource.ChainBackend, + log btclog.Logger) *arkChannelSourceWatcher { + + ctx, cancel := context.WithCancel(context.Background()) + if log == nil { + log = btclog.Disabled + } + + return &arkChannelSourceWatcher{ + backend: backend, log: log, ctx: ctx, cancel: cancel, + registrations: make( + map[arkchannel.ID][]*chainsource.SpendRegistration, + ), + retryDelay: time.Second, + } +} + +// BindChannelEventSink attaches the durable channel service. +func (w *arkChannelSourceWatcher) BindChannelEventSink( + sink arkchannel.ChannelEventSink) error { + + if sink == nil { + return fmt.Errorf("channel event sink is required") + } + w.mu.Lock() + defer w.mu.Unlock() + if w.sink == nil { + w.sink = sink + } + + return nil +} + +// Track atomically arms all watches for one channel. A duplicate install is +// idempotent and reuses the already active registrations. +func (w *arkChannelSourceWatcher) Track(ctx context.Context, id arkchannel.ID, + desc *vtxo.Descriptor) error { + + plan, err := fraud.BuildWatchPlan(desc) + if err != nil { + return err + } + w.mu.Lock() + if w.sink == nil { + w.mu.Unlock() + + return fmt.Errorf("channel event sink is not bound") + } + if _, ok := w.registrations[id]; ok { + w.mu.Unlock() + + return nil + } + w.mu.Unlock() + + registrations := make( + []*chainsource.SpendRegistration, 0, len(plan.Watches), + ) + for i := range plan.Watches { + watch := plan.Watches[i] + outpoint := watch.Outpoint + //nolint:contextcheck // watcher root owns registration lifetime + registration, err := w.backend.RegisterSpend( + w.ctx, &outpoint, watch.PkScript, watch.HeightHint, + ) + if err != nil { + cancelSpendRegistrations(registrations) + + return fmt.Errorf("register channel source spend "+ + "%s: %w", outpoint, err) + } + registrations = append(registrations, registration) + } + + w.mu.Lock() + if _, ok := w.registrations[id]; ok { + w.mu.Unlock() + cancelSpendRegistrations(registrations) + + return nil + } + w.registrations[id] = registrations + w.mu.Unlock() + + for i := range registrations { + w.wg.Add(1) + go w.waitForSpend(id, registrations[i]) + } + + return nil +} + +// waitForSpend waits for one confirmed ancestor spend or shutdown. +func (w *arkChannelSourceWatcher) waitForSpend(id arkchannel.ID, + registration *chainsource.SpendRegistration) { + + defer w.wg.Done() + select { + case detail, ok := <-registration.Spend: + if !ok || detail == nil || detail.SpentOutPoint == nil || + detail.SpenderTxHash == nil { + return + } + w.handleSpend(id, &arkchannel.SourceSpent{ + OutPoint: *detail.SpentOutPoint, + SpendingTxID: *detail.SpenderTxHash, + }) + + case <-registration.Done: + case <-w.ctx.Done(): + } +} + +// handleSpend cancels sibling watches and retries the durable event until the +// FSM accepts it. The chain notifier delivers a confirmed spend once, so a +// transient database or side-effect failure must not discard that evidence. +func (w *arkChannelSourceWatcher) handleSpend(id arkchannel.ID, + event *arkchannel.SourceSpent) { + + w.mu.Lock() + registrations, ok := w.registrations[id] + if ok { + delete(w.registrations, id) + } + sink := w.sink + w.mu.Unlock() + if !ok || sink == nil { + return + } + cancelSpendRegistrations(registrations) + attempts := 0 + for { + _, err := sink.Apply(w.ctx, id, event) + if err == nil { + if attempts > 0 { + w.log.InfoS( + w.ctx, + "Recovered Ark channel after source "+ + "spend", + btclog.Fmt("channel_id", "%x", id[:]), + btclog.Fmt("attempts", + "%d", attempts+1), + ) + } + + return + } + attempts++ + if attempts == 1 || attempts%30 == 0 { + w.log.WarnS( + w.ctx, + "Failed to recover Ark channel after source "+ + "spend", + err, + btclog.Fmt("channel_id", "%x", id[:]), + btclog.Fmt( + "spent_outpoint", "%v", event.OutPoint, + ), + btclog.Fmt( + "spending_txid", "%v", + event.SpendingTxID, + ), + btclog.Fmt("attempts", "%d", attempts), + ) + } + + timer := time.NewTimer(w.retryDelay) + select { + case <-timer.C: + case <-w.ctx.Done(): + if !timer.Stop() { + select { + case <-timer.C: + default: + } + } + + return + } + } +} + +// Stop cancels all registrations and waits for their goroutines. +func (w *arkChannelSourceWatcher) Stop() { + if w == nil { + return + } + w.cancel() + w.mu.Lock() + for id, registrations := range w.registrations { + cancelSpendRegistrations(registrations) + delete(w.registrations, id) + } + w.mu.Unlock() + w.wg.Wait() +} + +// cancelSpendRegistrations releases backend resources for a watch set. +func cancelSpendRegistrations(registrations []*chainsource.SpendRegistration) { + for _, registration := range registrations { + if registration != nil && registration.Cancel != nil { + registration.Cancel() + } + } +} diff --git a/waved/ark_channel_source_watcher_test.go b/waved/ark_channel_source_watcher_test.go new file mode 100644 index 000000000..1491051a3 --- /dev/null +++ b/waved/ark_channel_source_watcher_test.go @@ -0,0 +1,225 @@ +package waved + +import ( + "context" + "fmt" + "sync" + "testing" + "time" + + "github.com/btcsuite/btcd/chainhash/v2" + "github.com/btcsuite/btcd/wire/v2" + "github.com/btcsuite/btclog/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/chainsource" + "github.com/lightninglabs/wavelength/fraud" + "github.com/lightninglabs/wavelength/lib/tree" + "github.com/lightninglabs/wavelength/vtxo" + "github.com/stretchr/testify/require" +) + +type sourceWatcherRegistration struct { + spend chan *chainsource.SpendDetail + done chan struct{} + once sync.Once + cancel bool +} + +type sourceWatcherBackend struct { + chainsource.ChainBackend + + mu sync.Mutex + registrations map[wire.OutPoint]*sourceWatcherRegistration +} + +type sourceWatcherSink struct { + mu sync.Mutex + failures int + calls int + channelID arkchannel.ID + event *arkchannel.SourceSpent +} + +// RegisterSpend records one passive spend registration. +func (b *sourceWatcherBackend) RegisterSpend(_ context.Context, + outpoint *wire.OutPoint, _ []byte, _ uint32) ( + *chainsource.SpendRegistration, error) { + + b.mu.Lock() + defer b.mu.Unlock() + registration := &sourceWatcherRegistration{ + spend: make(chan *chainsource.SpendDetail, 1), + done: make(chan struct{}), + } + b.registrations[*outpoint] = registration + + return &chainsource.SpendRegistration{ + Spend: registration.spend, + Reorged: make(chan uint64), + Done: registration.done, + Cancel: func() { + registration.once.Do(func() { + b.mu.Lock() + registration.cancel = true + b.mu.Unlock() + close(registration.done) + }) + }, + }, nil +} + +// Apply records one watcher event and injects transient failures when asked. +func (s *sourceWatcherSink) Apply(_ context.Context, id arkchannel.ID, + event arkchannel.Event) (arkchannel.Record, error) { + + s.mu.Lock() + defer s.mu.Unlock() + s.calls++ + s.channelID = id + sourceSpent, ok := event.(*arkchannel.SourceSpent) + if !ok { + return arkchannel.Record{}, fmt.Errorf("unexpected source "+ + "watcher event %T", event) + } + s.event = sourceSpent + if s.failures > 0 { + s.failures-- + + return arkchannel.Record{}, context.DeadlineExceeded + } + + return arkchannel.Record{}, nil +} + +// TestArkChannelSourceWatcherCoversAllAncestry verifies every path in a +// multi-input OOR proof is armed and the first spend is retried durably. +func TestArkChannelSourceWatcherCoversAllAncestry(t *testing.T) { + t.Parallel() + + treeOne, sourceOne := sourceWatcherTree(t, 10) + treeTwo, sourceTwo := sourceWatcherTree(t, 20) + desc := &vtxo.Descriptor{ + Outpoint: sourceWatcherOutpoint(30), + Ancestry: []vtxo.Ancestry{ + { + TreePath: treeOne, + CommitmentTxID: treeOne.Root.Input.Hash, + InputIndices: []uint32{ + 0, + }, + TreeDepth: 1, + }, + { + TreePath: treeTwo, + CommitmentTxID: treeTwo.Root.Input.Hash, + InputIndices: []uint32{ + 1, + }, + TreeDepth: 1, + }, + }, + CreatedHeight: 7, + } + plan, err := fraud.BuildWatchPlan(desc) + require.NoError(t, err) + + backend := &sourceWatcherBackend{ + registrations: make( + map[wire.OutPoint]*sourceWatcherRegistration, + ), + } + sink := &sourceWatcherSink{failures: 1} + watcher := newArkChannelSourceWatcher(backend, btclog.Disabled) + watcher.retryDelay = 5 * time.Millisecond + require.NoError(t, watcher.BindChannelEventSink(sink)) + t.Cleanup(watcher.Stop) + + id := arkchannel.ID{1, 2, 3} + require.NoError(t, watcher.Track(t.Context(), id, desc)) + backend.mu.Lock() + require.Len(t, backend.registrations, len(plan.Watches)) + require.Contains(t, backend.registrations, treeOne.Root.Input) + require.Contains(t, backend.registrations, sourceOne) + require.Contains(t, backend.registrations, treeTwo.Root.Input) + require.Contains(t, backend.registrations, sourceTwo) + registration := backend.registrations[treeTwo.Root.Input] + backend.mu.Unlock() + + spendingTx := wire.NewMsgTx(2) + spendingTx.AddTxIn(wire.NewTxIn( + &treeTwo.Root.Input, nil, nil, + )) + spendingTx.AddTxOut(&wire.TxOut{Value: 1, PkScript: []byte{0x51}}) + spendingTxID := spendingTx.TxHash() + registration.spend <- &chainsource.SpendDetail{ + SpentOutPoint: &treeTwo.Root.Input, + SpenderTxHash: &spendingTxID, + SpendingTx: spendingTx, + SpenderInputIndex: 0, + SpendingHeight: 8, + } + + require.Eventually(t, func() bool { + sink.mu.Lock() + defer sink.mu.Unlock() + + return sink.calls == 2 + }, time.Second, time.Millisecond) + sink.mu.Lock() + require.Equal(t, id, sink.channelID) + require.Equal(t, treeTwo.Root.Input, sink.event.OutPoint) + require.Equal(t, spendingTxID, sink.event.SpendingTxID) + sink.mu.Unlock() + + require.Eventually(t, func() bool { + backend.mu.Lock() + defer backend.mu.Unlock() + for _, item := range backend.registrations { + if !item.cancel { + return false + } + } + + return true + }, time.Second, time.Millisecond) +} + +// sourceWatcherTree creates a one-node ancestry tree and its VTXO leaf. +func sourceWatcherTree(t *testing.T, seed byte) (*tree.Tree, wire.OutPoint) { + t.Helper() + root := &tree.Node{ + Input: sourceWatcherOutpoint(seed), + Outputs: []*wire.TxOut{ + { + Value: 1_000, + PkScript: []byte{ + 0x51, + seed, + }, + }, + }, + Children: make(map[uint32]*tree.Node), + } + source, err := root.GetNonAnchorOutpoint() + require.NoError(t, err) + + return &tree.Tree{ + Root: root, + BatchOutput: &wire.TxOut{ + Value: 1_000, + PkScript: []byte{ + 0x51, + seed, + 0, + }, + }, + }, *source +} + +// sourceWatcherOutpoint returns one deterministic test outpoint. +func sourceWatcherOutpoint(seed byte) wire.OutPoint { + var hash chainhash.Hash + hash[0] = seed + + return wire.OutPoint{Hash: hash} +} diff --git a/waved/config.go b/waved/config.go index 5558a1212..a31c17368 100644 --- a/waved/config.go +++ b/waved/config.go @@ -740,6 +740,11 @@ type SwapConfig struct { // pending credit-backed send is about to spend. Nil in builds without // the credit subsystem; set programmatically, never from config files. CreditEarmarkSetter func(credit.EarmarkFunc) `mapstructure:"-"` + + // ArkChannelMailbox is the authenticated swapdk-server mailbox edge + // published by swapclientserver for the channel control runtime. It is + // process wiring, never user configuration. + ArkChannelMailbox mailboxpb.MailboxServiceClient `mapstructure:"-"` } // CreditConfig configures the daemon-owned credit subsystem. diff --git a/waved/logging.go b/waved/logging.go index 368c5b653..ebcf7b377 100644 --- a/waved/logging.go +++ b/waved/logging.go @@ -17,6 +17,16 @@ import ( "github.com/lightninglabs/wavelength/vtxo" "github.com/lightninglabs/wavelength/wallet" lndbuild "github.com/lightningnetwork/lnd/build" + "github.com/lightningnetwork/lnd/chainio" + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/contractcourt" + "github.com/lightningnetwork/lnd/funding" + "github.com/lightningnetwork/lnd/htlcswitch" + "github.com/lightningnetwork/lnd/invoices" + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwallet/chanfunding" + "github.com/lightningnetwork/lnd/routing" + "github.com/lightningnetwork/lnd/sweep" ) // SubLoggers maps subsystem tags to their registered btclog instances. @@ -48,6 +58,18 @@ var allSubsystems = []string{ "TXCF", "UNRL", VHTLCRecoverySubsystem, + funding.Subsystem, + "CHFD", + "LNWL", + "HSWC", + "INVC", + routing.Subsystem, + "CNCT", + "BRAR", + "UTXN", + "SWPR", + "CHDB", + chainio.Subsystem, } const ( @@ -100,5 +122,18 @@ func setupLoggers(root *lndbuild.SubLoggerManager, loggers[sub] = logger } + funding.UseLogger(loggers[funding.Subsystem]) + chanfunding.UseLogger(loggers["CHFD"]) + lnwallet.UseLogger(loggers["LNWL"]) + htlcswitch.UseLogger(loggers["HSWC"]) + invoices.UseLogger(loggers["INVC"]) + routing.UseLogger(loggers[routing.Subsystem]) + contractcourt.UseLogger(loggers["CNCT"]) + contractcourt.UseBreachLogger(loggers["BRAR"]) + contractcourt.UseNurseryLogger(loggers["UTXN"]) + sweep.UseLogger(loggers["SWPR"]) + channeldb.UseLogger(loggers["CHDB"]) + chainio.UseLogger(loggers[chainio.Subsystem]) + return loggers } diff --git a/waved/native_ark_channel_controller.go b/waved/native_ark_channel_controller.go new file mode 100644 index 000000000..8f7a0040b --- /dev/null +++ b/waved/native_ark_channel_controller.go @@ -0,0 +1,2142 @@ +package waved + +import ( + "bytes" + "context" + "crypto/rand" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "sync" + "time" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil/v2" + "github.com/btcsuite/btcd/chainhash/v2" + "github.com/btcsuite/btcd/wire/v2" + "github.com/btcsuite/btclog/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/lib/arkscript" + "github.com/lightninglabs/wavelength/lnruntime" + "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" + "github.com/lightningnetwork/lnd/htlcswitch" + "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwire" +) + +var ( + // ErrInsufficientArkChannelLiquidity means no active private channel + // has enough balance on the requested sending side. + ErrInsufficientArkChannelLiquidity = fmt.Errorf("insufficient active " + + "Ark channel liquidity") + + // ErrReceiveChannelFallback means channel creation was abandoned before + // the hub's prepared OOR crossed its signing point of no return. + ErrReceiveChannelFallback = fmt.Errorf("receive channel can safely " + + "fall back to vHTLC") +) + +const ( + arkChannelArkKeyFamily keychain.KeyFamily = 220 + arkChannelBackingKeyFamily keychain.KeyFamily = 221 + arkChannelFunderKeyFamily keychain.KeyFamily = 223 +) + +// HubArkChannelControllerConfig contains the hub-only signer, publisher, and +// authenticated client transport needed to compose one native endpoint. +type HubArkChannelControllerConfig struct { + Process ArkChannelControllerConfig + + RemoteNode [33]byte + PeerSender lnruntime.PeerEventSender + Info lnruntime.FundingPeerInfo + CloseObserver lnruntime.CooperativeCloseObserver + CloseDefender lnruntime.CooperativeCloseDefender + PaymentBridge lnruntime.PaymentBridgeCoordinator +} + +// NativeArkChannelController owns one Ark FSM and one modular lnd endpoint. +type NativeArkChannelController struct { + party arkchannel.Party + cfg ArkChannelControllerConfig + + coordinator *arkchannel.Coordinator + remote lnruntime.ProcessFundingPeer + fundingPeer lnruntime.FundingCounterparty + paymentPeer lnruntime.ProcessPaymentPeer + peerInfo lnruntime.FundingPeerInfo + remoteNode [33]byte + keys nativeArkChannelKeys + + mu sync.RWMutex + node *lnruntime.NativeNode + service *arkchannel.Service + clientClose *lnruntime.ClientCooperativeCloseProcess + hubClose *lnruntime.HubCooperativeCloseProcess + fundingWire *lnruntime.FundingWire + paymentBridge lnruntime.PaymentBridgeCoordinator + reaperCancel context.CancelFunc + reaperWG sync.WaitGroup +} + +// nativeArkChannelKeys are fixed wallet roles restored by locator on restart. +type nativeArkChannelKeys struct { + ark keychain.KeyDescriptor + backing keychain.KeyDescriptor + funder keychain.KeyDescriptor +} + +// loggedArkChannelForceCloser makes the irreversible lnd handoff observable +// while preserving lnd's idempotent close API as the implementation boundary. +type loggedArkChannelForceCloser struct { + node *lnruntime.NativeNode + log btclog.Logger +} + +// ResumeForceCloseChannel records entry and completion around lnd's durable +// commitment-publication edge. +func (c *loggedArkChannelForceCloser) ResumeForceCloseChannel( + channelPoint wire.OutPoint) error { + + ctx := context.Background() + c.log.InfoS(ctx, "Resuming Ark channel force close", + btclog.Fmt("channel_point", "%v", channelPoint), + ) + err := c.node.ResumeForceCloseChannel(channelPoint) + if err != nil { + c.log.WarnS(ctx, "Ark channel force close failed", + err, + btclog.Fmt("channel_point", "%v", channelPoint), + ) + + return err + } + c.log.InfoS(ctx, "Ark channel force close resumed", + btclog.Fmt("channel_point", "%v", channelPoint), + ) + + return nil +} + +// LightningPaymentResult is the atomic public-payment result returned after +// the private source settled with the same preimage. +type LightningPaymentResult struct { + PaymentHash lntypes.Hash + Preimage lntypes.Preimage + PrivateAmount btcutil.Amount + Fee btcutil.Amount + ChannelID arkchannel.ID +} + +// NewHubFundingPeerInfo derives the immutable channel policy advertised by a +// real operator Wavelength process. The key roles share the same deterministic +// locators used when the hub endpoint is restored after restart. +func NewHubFundingPeerInfo(ctx context.Context, + cfg ArkChannelControllerConfig) (lnruntime.FundingPeerInfo, error) { + + if err := validateArkChannelProcessConfig(cfg); err != nil { + return lnruntime.FundingPeerInfo{}, err + } + if cfg.OperatorTerms == nil || cfg.OperatorTerms.PubKey == nil { + return lnruntime.FundingPeerInfo{}, fmt.Errorf("Ark operator " + + "terms are required") + } + keys, err := deriveNativeArkChannelKeys(ctx, cfg) + if err != nil { + return lnruntime.FundingPeerInfo{}, err + } + channelDelay := cfg.OperatorTerms.VTXOExitDelay + if channelDelay > ^uint32(0)-arkscript.DefaultChannelReactionWindow { + return lnruntime.FundingPeerInfo{}, fmt.Errorf("Ark channel " + + "delay exceeds sequence range") + } + info := lnruntime.FundingPeerInfo{ + ChannelDelay: channelDelay, + FunderDelay: channelDelay + + arkscript.DefaultChannelReactionWindow, + MinimumExitDelay: channelDelay, + } + copy(info.HubNodeKey[:], cfg.IdentityKey.PubKey.SerializeCompressed()) + copy(info.HubArkKey[:], keys.ark.PubKey.SerializeCompressed()) + copy(info.HubChannelKey[:], keys.backing.PubKey.SerializeCompressed()) + copy(info.HubFunderKey[:], keys.funder.PubKey.SerializeCompressed()) + copy( + info.ArkOperatorKey[:], + cfg.OperatorTerms.PubKey.SerializeCompressed(), + ) + + return info, info.Validate() +} + +// NewClientArkChannelController constructs a lazy client endpoint. The first +// lifecycle request loads hub policy over the already-running mailbox and +// starts the native lnd components. +func NewClientArkChannelController(ctx context.Context, + cfg ArkChannelControllerConfig) (*NativeArkChannelController, error) { + + cfg = withArkChannelControllerDefaults(cfg) + + if err := validateClientArkChannelProcessConfig(cfg); err != nil { + return nil, err + } + var observers []arkchannel.RecordObserver + if cfg.RecordObserver != nil { + observers = append(observers, cfg.RecordObserver) + } + coordinator, err := arkchannel.NewCoordinator(cfg.Store, observers...) + if err != nil { + return nil, err + } + remote, err := lnruntime.NewMailboxFundingPeer(cfg.PeerRPC) + if err != nil { + return nil, err + } + keys, err := deriveNativeArkChannelKeys(ctx, cfg) + if err != nil { + return nil, err + } + + controller := &NativeArkChannelController{ + party: arkchannel.PartyClient, cfg: cfg, + coordinator: coordinator, remote: remote, + fundingPeer: remote, paymentPeer: remote, keys: keys, + } + controller.startPrePONRReaper(ctx) + + return controller, nil +} + +// NewHubArkChannelController eagerly composes one authenticated client +// endpoint for swapserver's channel directory. +func NewHubArkChannelController(ctx context.Context, + cfg HubArkChannelControllerConfig) (*NativeArkChannelController, + error) { + + cfg.Process = withArkChannelControllerDefaults(cfg.Process) + + if err := validateArkChannelProcessConfig(cfg.Process); err != nil { + return nil, err + } + if cfg.Process.FundingOOR == nil || cfg.Process.PrepareOOR == nil || + cfg.Process.LookupOOR == nil || + cfg.Process.ReserveReceiveCapital == nil { + return nil, fmt.Errorf("complete hub OOR and capital control " + + "is required") + } + if _, ok := cfg.Process.FundingOOR.(prePONRResultController); !ok { + return nil, fmt.Errorf("result-bearing hub OOR controller is " + + "required") + } + if _, err := btcec.ParsePubKey(cfg.RemoteNode[:]); err != nil { + return nil, fmt.Errorf("parse client channel node: %w", err) + } + if cfg.PeerSender == nil || cfg.CloseObserver == nil || + cfg.CloseDefender == nil { + return nil, fmt.Errorf("complete hub channel process is " + + "required") + } + if err := cfg.Info.Validate(); err != nil { + return nil, err + } + var observers []arkchannel.RecordObserver + if cfg.Process.RecordObserver != nil { + observers = append(observers, cfg.Process.RecordObserver) + } + coordinator, err := arkchannel.NewCoordinator( + cfg.Process.Store, observers..., + ) + if err != nil { + return nil, err + } + keys, err := deriveNativeArkChannelKeys(ctx, cfg.Process) + if err != nil { + return nil, err + } + controller := &NativeArkChannelController{ + party: arkchannel.PartyHub, cfg: cfg.Process, + coordinator: coordinator, peerInfo: cfg.Info, keys: keys, + paymentBridge: cfg.PaymentBridge, remoteNode: cfg.RemoteNode, + } + if err := controller.startHub( + ctx, cfg.RemoteNode, cfg.PeerSender, cfg.CloseObserver, + cfg.CloseDefender, + ); err != nil { + return nil, err + } + controller.startPrePONRReaper(ctx) + + return controller, nil +} + +// validateArkChannelProcessConfig rejects incomplete process composition. +func validateArkChannelProcessConfig(cfg ArkChannelControllerConfig) error { + switch { + case cfg.Store == nil: + return fmt.Errorf("Ark channel store is required") + + case cfg.Wallet == nil: + return fmt.Errorf("Ark channel wallet is required") + + case cfg.ChainBackend == nil || cfg.ChainNotifier == nil: + return fmt.Errorf("Ark channel chain backend is required") + + case cfg.FeeEstimator == nil: + return fmt.Errorf("Ark channel fee estimator is required") + + case cfg.Materializer == nil || cfg.Recovery == nil: + return fmt.Errorf("Ark channel recovery runtime is required") + + case cfg.IdentityKey.PubKey == nil: + return fmt.Errorf("Ark channel identity key is required") + + case cfg.OORDestination == nil: + return fmt.Errorf("Ark channel OOR destination key is required") + + case cfg.NetParams == nil: + return fmt.Errorf("Ark channel network is required") + + case cfg.ChannelDataDir == "": + return fmt.Errorf("Ark channel data directory is required") + + default: + return nil + } +} + +// validateClientArkChannelProcessConfig checks the funding and publication +// dependencies that only the client-owned promotion process may execute. +func validateClientArkChannelProcessConfig( + cfg ArkChannelControllerConfig) error { + + if err := validateArkChannelProcessConfig(cfg); err != nil { + return err + } + switch { + case cfg.Peer == nil || cfg.PeerRPC == nil || cfg.PeerSender == nil: + return fmt.Errorf("Ark channel peer transport is required") + + case cfg.OOR == nil || cfg.Materializer == nil: + return fmt.Errorf("Ark channel OOR and unroller are required") + + case cfg.PrepareOOR == nil: + return fmt.Errorf("Ark channel OOR preparer is required") + + case cfg.LookupOOR == nil: + return fmt.Errorf("Ark channel OOR lookup is required") + + default: + return nil + } +} + +// deriveNativeArkChannelKeys restores stable process-owned policy roles. +func deriveNativeArkChannelKeys(ctx context.Context, + cfg ArkChannelControllerConfig) (nativeArkChannelKeys, error) { + + derive := func(family keychain.KeyFamily) (keychain.KeyDescriptor, + error) { + + desc, err := cfg.Wallet.DeriveKey( + ctx, + keychain.KeyLocator{ + Family: family, Index: cfg.KeyIndex, + }, + ) + if err != nil { + return keychain.KeyDescriptor{}, err + } + + return *desc, nil + } + arkKey, err := derive(arkChannelArkKeyFamily) + if err != nil { + return nativeArkChannelKeys{}, err + } + backingKey, err := derive(arkChannelBackingKeyFamily) + if err != nil { + return nativeArkChannelKeys{}, err + } + funderKey, err := derive(arkChannelFunderKeyFamily) + if err != nil { + return nativeArkChannelKeys{}, err + } + + return nativeArkChannelKeys{ + ark: arkKey, backing: backingKey, funder: funderKey, + }, nil +} + +// ensureClientStarted loads hub policy and starts the local native endpoint. +func (c *NativeArkChannelController) ensureClientStarted( + ctx context.Context) error { + + c.mu.Lock() + defer c.mu.Unlock() + if c.node != nil { + return nil + } + peerInfo, err := c.remote.GetPeerInfo(ctx) + if err != nil { + return fmt.Errorf("load Ark channel hub policy: %w", err) + } + remoteKey, err := btcec.ParsePubKey(peerInfo.HubNodeKey[:]) + if err != nil { + return err + } + node, err := c.newNode( + ctx, arkchannel.PartyClient, remoteKey, c.cfg.PeerSender, + ) + if err != nil { + return err + } + fundingWire, err := lnruntime.NewFundingWire(node.Peer()) + if err != nil { + _ = node.Stop() + + return err + } + negotiator, err := node.NewNegotiator(c.fundingPeer, c.cfg.Recovery) + if err != nil { + fundingWire.Close() + _ = node.Stop() + + return err + } + delivery := newArkChannelCloseDelivery(c.cfg.OORDestination) + closeEndpoint, err := lnruntime.NewNativeCooperativeCloseEndpoint( + arkchannel.PartyClient, node.Runtime(), nil, + keychain.KeyDescriptor{}, delivery, + ) + if err != nil { + fundingWire.Close() + _ = node.Stop() + + return err + } + publisher := lnruntime.CooperativeClosePublisherFunc(func( + ctx context.Context, id arkchannel.ID, terms arkchannel.Terms, + source arkchannel.VTXOBinding, + request arkchannel.CooperativeCloseRequest, + settlement arkchannel.CooperativeClose) error { + + return c.cfg.OOR.SettleCooperativeClose( + ctx, id, terms, source, request, settlement, c.keys.ark, + ) + }) + clientClose, err := lnruntime.NewClientCooperativeCloseProcess( + closeEndpoint, c.cfg.Peer, publisher, delivery, + ) + if err != nil { + fundingWire.Close() + _ = node.Stop() + + return err + } + service, err := c.newService(node, negotiator, clientClose) + if err != nil { + fundingWire.Close() + _ = node.Stop() + + return err + } + if err := fundingWire.BindServer(lnruntime.FundingWireServerConfig{ + Service: service, Funding: node.FundingEndpoint(), + }); err != nil { + + fundingWire.Close() + _ = node.Stop() + + return err + } + c.service = service + c.fundingWire = fundingWire + cleanup := func() { + c.service = nil + c.fundingWire = nil + fundingWire.Close() + _ = node.Stop() + } + if err := tolerateNativeArkChannelFailures( + ctx, restoreNativeArkChannelBackings(ctx, node, service), + c.cfg.Log, "Ark channel backing restore failed", + ); err != nil { + + cleanup() + + return err + } + if err := node.Start(); err != nil { + cleanup() + + return err + } + if err := c.restoreRecoveryWatches(ctx, service); err != nil { + cleanup() + + return err + } + if err := tolerateNativeArkChannelFailures( + ctx, + c.maintainPrePONRChannels( + ctx, service, c.cfg.Clock.Now(), + ), + c.cfg.Log, "Ark channel pre-PONR maintenance failed", + ); err != nil { + + cleanup() + + return err + } + if err := resumeNativeArkChannels(ctx, service, c.cfg.Log); err != nil { + cleanup() + + return err + } + if err := tolerateNativeArkChannelFailures( + ctx, resumeOnchainArkChannels(ctx, node, service), c.cfg.Log, + "Ark channel force-close resume failed", + ); err != nil { + + cleanup() + + return err + } + c.peerInfo = peerInfo + c.node = node + c.clientClose = clientClose + + return nil +} + +// startHub starts one operator endpoint for an authenticated client. +func (c *NativeArkChannelController) startHub(ctx context.Context, + remoteNode [33]byte, sender lnruntime.PeerEventSender, + closeObserver lnruntime.CooperativeCloseObserver, + closeDefender lnruntime.CooperativeCloseDefender) error { + + remoteKey, err := btcec.ParsePubKey(remoteNode[:]) + if err != nil { + return err + } + node, err := c.newNode( + ctx, arkchannel.PartyHub, remoteKey, sender, + ) + if err != nil { + return err + } + fundingWire, err := lnruntime.NewFundingWire(node.Peer()) + if err != nil { + _ = node.Stop() + + return err + } + negotiator, err := node.NewNegotiator( + fundingWire.Counterparty(), c.cfg.Recovery, + ) + if err != nil { + fundingWire.Close() + _ = node.Stop() + + return err + } + delivery := newArkChannelCloseDelivery(c.cfg.OORDestination) + closeEndpoint, err := lnruntime.NewNativeCooperativeCloseEndpoint( + arkchannel.PartyHub, node.Runtime(), c.cfg.Wallet.BtcWallet, + c.keys.ark, delivery, + ) + if err != nil { + fundingWire.Close() + _ = node.Stop() + + return err + } + hubClose, err := lnruntime.NewHubCooperativeCloseProcess( + closeEndpoint, delivery, closeObserver, closeDefender, + ) + if err != nil { + fundingWire.Close() + _ = node.Stop() + + return err + } + service, err := c.newService( + node, negotiator, &lnruntime.HubCooperativeCloseExecutor{ + HubCooperativeCloseProcess: hubClose, + }, + ) + if err != nil { + fundingWire.Close() + _ = node.Stop() + + return err + } + c.service = service + c.fundingWire = fundingWire + cleanup := func() { + c.service = nil + c.fundingWire = nil + fundingWire.Close() + _ = node.Stop() + } + if err := tolerateNativeArkChannelFailures( + ctx, restoreNativeArkChannelBackings(ctx, node, service), + c.cfg.Log, "Ark channel backing restore failed", + ); err != nil { + + cleanup() + + return err + } + if err := node.Start(); err != nil { + cleanup() + + return err + } + if err := c.restoreRecoveryWatches(ctx, service); err != nil { + cleanup() + + return err + } + if err := tolerateNativeArkChannelFailures( + ctx, + c.maintainPrePONRChannels( + ctx, service, c.cfg.Clock.Now(), + ), + c.cfg.Log, "Ark channel pre-PONR maintenance failed", + ); err != nil { + + cleanup() + + return err + } + if err := resumeNativeArkChannels(ctx, service, c.cfg.Log); err != nil { + cleanup() + + return err + } + if err := tolerateNativeArkChannelFailures( + ctx, resumeOnchainArkChannels(ctx, node, service), c.cfg.Log, + "Ark channel force-close resume failed", + ); err != nil { + + cleanup() + + return err + } + c.node = node + c.hubClose = hubClose + + return nil +} + +// arkChannelBackingRestorer registers virtual funding before lnd restores its +// pending funding manager state. +type arkChannelBackingRestorer interface { + RestoreBacking(arkchannel.Terms, arkchannel.Backing) error +} + +// restoreNativeArkChannelBackings reconstructs the notifier's in-memory map +// from durable FSM records before any lnd subsystem starts. +func restoreNativeArkChannelBackings(ctx context.Context, + restorer arkChannelBackingRestorer, service *arkchannel.Service) error { + + records, err := service.ListChannels(ctx) + if err != nil { + return err + } + + return restoreNativeArkChannelBackingRecords(restorer, records) +} + +// restoreNativeArkChannelBackingRecords registers every signed backing in one +// pre-start snapshot of the durable channel store. +func restoreNativeArkChannelBackingRecords(restorer arkChannelBackingRestorer, + records []arkchannel.Record) error { + + failures := make([]arkchannel.ResumeFailure, 0) + for _, record := range records { + backing := record.Snapshot.Backing + if backing == nil || + record.Snapshot.Phase == arkchannel.PhaseClosed { + + continue + } + if err := restorer.RestoreBacking( + record.Snapshot.Terms, *backing, + ); err != nil { + + failures = append(failures, arkchannel.ResumeFailure{ + ChannelID: record.Snapshot.Terms.ID, + Err: fmt.Errorf( + "restore backing: %w", err, + ), + }) + } + } + if len(failures) > 0 { + return &arkchannel.ResumeFailures{Failures: failures} + } + + return nil +} + +// resumeNativeArkChannels logs isolated channel failures while preserving a +// functioning endpoint for every channel that recovered successfully. +func resumeNativeArkChannels(ctx context.Context, service *arkchannel.Service, + log btclog.Logger) error { + + return tolerateNativeArkChannelFailures( + ctx, service.Resume(ctx), log, + "Ark channel action resume failed", + ) +} + +// tolerateNativeArkChannelFailures reports durable per-channel failures without +// tearing down independent links that recovered successfully. +func tolerateNativeArkChannelFailures(ctx context.Context, err error, + log btclog.Logger, message string) error { + + if err == nil { + return nil + } + var failures *arkchannel.ResumeFailures + if !errors.As(err, &failures) { + return err + } + if log == nil { + log = btclog.Disabled + } + for _, failure := range failures.Failures { + log.WarnS( + ctx, message, failure.Err, btclog.Fmt( + "channel_id", "%x", failure.ChannelID[:], + ), + ) + } + + return nil +} + +// arkChannelForceCloseResumer reconciles one materialized channel with lnd's +// durable commitment-broadcast state. +type arkChannelForceCloseResumer interface { + ResumeForceCloseChannel(wire.OutPoint) error +} + +// resumeOnchainArkChannels closes the crash window between durable backing +// publication and lnd's commitment-broadcast marker. +func resumeOnchainArkChannels(ctx context.Context, + node arkChannelForceCloseResumer, service *arkchannel.Service) error { + + records, err := service.ListChannels(ctx) + if err != nil { + return err + } + + return resumeOnchainArkChannelRecords(node, records) +} + +// resumeOnchainArkChannelRecords attempts every materialized channel and +// returns only isolated failures after the complete recovery pass. +func resumeOnchainArkChannelRecords(node arkChannelForceCloseResumer, + records []arkchannel.Record) error { + + failures := make([]arkchannel.ResumeFailure, 0) + for _, record := range records { + if !shouldResumeOnchainArkChannel(record.Snapshot) { + continue + } + if record.Snapshot.Backing == nil { + failures = append(failures, arkchannel.ResumeFailure{ + ChannelID: record.Snapshot.Terms.ID, + Err: fmt.Errorf( + "materialized channel has no " + + "backing", + ), + }) + + continue + } + if err := node.ResumeForceCloseChannel( + record.Snapshot.Backing.ChannelPoint, + ); err != nil { + + failures = append(failures, arkchannel.ResumeFailure{ + ChannelID: record.Snapshot.Terms.ID, + Err: fmt.Errorf("resume materialized channel: "+ + "%w", + err), + }) + } + } + if len(failures) > 0 { + return &arkchannel.ResumeFailures{Failures: failures} + } + + return nil +} + +// shouldResumeOnchainArkChannel reports whether backing publication crossed +// the durable handoff but lnd may still need its commitment broadcast marker. +func shouldResumeOnchainArkChannel(snapshot arkchannel.Snapshot) bool { + return snapshot.Phase == arkchannel.PhaseOnChain +} + +// restoreRecoveryWatches arms persisted ancestry before replaying any channel +// action that could activate or publish native lnd state. +func (c *NativeArkChannelController) restoreRecoveryWatches(ctx context.Context, + service *arkchannel.Service) error { + + records, err := service.ListChannels(ctx) + if err != nil { + return err + } + + return c.cfg.Recovery.RestoreWatches(ctx, records) +} + +// newNode composes native lnd state over one authenticated peer sender. +func (c *NativeArkChannelController) newNode(ctx context.Context, + party arkchannel.Party, remoteKey *btcec.PublicKey, + sender lnruntime.PeerEventSender) (*lnruntime.NativeNode, error) { + + transport, err := lnruntime.NewDurablePeerTransport( + lnruntime.DurablePeerTransportConfig{ + Sender: sender, + CorrelationKey: hex.EncodeToString( + c.cfg.IdentityKey.PubKey.SerializeCompressed(), + ), + }, + ) + if err != nil { + return nil, err + } + log := c.cfg.Log + if log == nil { + log = btclog.Disabled + } + logCtx := context.WithoutCancel(ctx) + onChannelFailure := func(channelID lnwire.ChannelID, + scid lnwire.ShortChannelID, + failure htlcswitch.LinkFailureError) { + + log.WarnS(logCtx, "Native Ark channel link failed", + failure, + btclog.Fmt("channel_id", "%x", channelID[:]), + btclog.Fmt("scid", "%v", scid), + ) + } + shouldWatchChannel := func(channelPoint wire.OutPoint) (bool, error) { + record, err := c.coordinator.FindByChannelPoint( + logCtx, channelPoint, + ) + if err != nil { + return false, fmt.Errorf("load Ark channel "+ + "lifecycle: %w", err) + } + + return shouldWatchArkChannel(record.Snapshot.Phase), nil + } + shouldDisableChannelAdds := func(channelPoint wire.OutPoint) (bool, + error) { + + record, err := c.coordinator.FindByChannelPoint( + logCtx, channelPoint, + ) + if err != nil { + return false, fmt.Errorf("load Ark channel close "+ + "lifecycle: %w", err) + } + + return shouldRestoreArkChannelAddsDisabled( + record.Snapshot.Phase, + ), nil + } + recordChannelFullyResolved := func(channelPoint wire.OutPoint) error { + return c.recordFullyResolvedChannel( + logCtx, channelPoint, + ) + } + beforeCommitmentPublish := func(channelPoint wire.OutPoint) error { + return c.materializeBeforeCommitment( + logCtx, channelPoint, + ) + } + + return lnruntime.NewNativeNode(lnruntime.NativeNodeConfig{ + DataDir: c.cfg.ChannelDataDir, Party: party, + Chain: c.cfg.Wallet.BtcWallet, Notifier: c.cfg.ChainNotifier, + WalletController: c.cfg.Wallet.BtcWallet, + KeyRing: c.cfg.Wallet.KeyRing(), Signer: c. + cfg. + Wallet. + BtcWallet, + FeeEstimator: c.cfg.FeeEstimator, NetParams: c.cfg.NetParams, + IdentityKey: c.cfg.IdentityKey, BackingKey: c.keys.backing, + RemoteNodeKey: remoteKey, Transport: transport, + Intents: c.coordinator, OnChannelFailure: onChannelFailure, + ShouldWatchChannel: shouldWatchChannel, + ShouldDisableChannelAdds: shouldDisableChannelAdds, + BeforeCommitmentPublish: beforeCommitmentPublish, + RecordChannelFullyResolved: recordChannelFullyResolved, + }) +} + +// materializeBeforeCommitment blocks lnd's local commitment publication until +// either recovery-ready endpoint has durably published the exact backing. +func (c *NativeArkChannelController) materializeBeforeCommitment( + ctx context.Context, channelPoint wire.OutPoint) error { + + record, err := c.coordinator.FindByChannelPoint(ctx, channelPoint) + if err != nil { + return fmt.Errorf("load channel publication lifecycle: %w", err) + } + if record.Snapshot.Phase == arkchannel.PhaseOnChain { + return nil + } + if c.service == nil { + return fmt.Errorf("Ark channel service is not ready") + } + record, err = c.service.Materialize( + ctx, record.Snapshot.Terms.ID, + ) + if err != nil { + return fmt.Errorf("materialize channel backing: %w", err) + } + if record.Snapshot.Phase != arkchannel.PhaseOnChain { + return fmt.Errorf("channel backing stopped in phase %s", + record.Snapshot.Phase) + } + + return nil +} + +// shouldWatchArkChannel reports whether lnd must own the channel's chain and +// contract lifecycle. An unpublished outpoint remains dormant, while an +// observed publication can be handled without first contacting the peer. +func shouldWatchArkChannel(phase arkchannel.Phase) bool { + switch phase { + case arkchannel.PhaseActivating, arkchannel.PhaseActive, + arkchannel.PhaseMaterializing, arkchannel.PhaseOnChain, + arkchannel.PhaseCoopClosing, + arkchannel.PhaseCoopCloseSigned, + arkchannel.PhaseCoopClosePublished: + return true + + default: + return false + } +} + +// shouldRestoreArkChannelAddsDisabled reports whether a durable cooperative +// close artifact requires a restored lnd link to remain quiesced. +func shouldRestoreArkChannelAddsDisabled(phase arkchannel.Phase) bool { + switch phase { + case arkchannel.PhaseCoopClosing, + arkchannel.PhaseCoopCloseSigned, + arkchannel.PhaseCoopClosePublished: + return true + + default: + return false + } +} + +// recordFullyResolvedChannel advances the Ark FSM only after lnd has resolved +// and swept every output. Chain evidence can recover a peer that never +// received the initiating endpoint's materialization transition. +func (c *NativeArkChannelController) recordFullyResolvedChannel( + ctx context.Context, channelPoint wire.OutPoint) error { + + record, err := c.coordinator.FindByChannelPoint(ctx, channelPoint) + if err != nil { + return err + } + switch record.Snapshot.Phase { + case arkchannel.PhaseActivating, arkchannel.PhaseActive, + arkchannel.PhaseMaterializing, + arkchannel.PhaseCoopClosing, + arkchannel.PhaseCoopCloseSigned: + + record, _, err = c.coordinator.Apply( + ctx, record.Snapshot.Terms.ID, + &arkchannel.BackingObserved{ + TxID: channelPoint.Hash, + }, + ) + if err != nil { + return err + } + + case arkchannel.PhaseOnChain: + case arkchannel.PhaseClosed: + return nil + + default: + return fmt.Errorf("cannot resolve on-chain channel from %s", + record.Snapshot.Phase) + } + + _, _, err = c.coordinator.Apply( + ctx, record.Snapshot.Terms.ID, &arkchannel.ChannelClosed{}, + ) + + return err +} + +// newService binds the endpoint's native lnd and Ark side effects to one FSM. +func (c *NativeArkChannelController) newService(node *lnruntime.NativeNode, + negotiator *lnruntime.ChannelNegotiator, + closer arkchannel.ChannelCooperativeCloser) (*arkchannel.Service, + error) { + + var oor arkchannel.OORTransferController + if c.cfg.FundingOOR != nil { + oor = c.cfg.FundingOOR + } else if c.cfg.OOR != nil { + oor = c.cfg.OOR + } + var materializer arkchannel.ChannelMaterializer + if c.cfg.Materializer != nil { + materializer = c.cfg.Materializer + } + log := c.cfg.Log + if log == nil { + log = btclog.Disabled + } + forceCloser := &loggedArkChannelForceCloser{ + node: node, log: log, + } + executor, err := arkchannel.NewNativeExecutor( + c.party, node.FundingActivator(), negotiator, oor, materializer, + node, forceCloser, closer, + ) + if err != nil { + return nil, err + } + + return arkchannel.NewService(c.coordinator, executor) +} + +// PromoteVTXO prepares and activates one client-funded OOR channel. +func (c *NativeArkChannelController) PromoteVTXO(ctx context.Context, + amount btcutil.Amount) (arkchannel.Record, error) { + + if c.party != arkchannel.PartyClient { + return arkchannel.Record{}, fmt.Errorf("only a client can " + + "promote VTXO liquidity") + } + if amount <= 0 { + return arkchannel.Record{}, fmt.Errorf("channel amount must " + + "be positive") + } + if err := c.ensureClientStarted(ctx); err != nil { + return arkchannel.Record{}, err + } + terms, err := c.newPromotionTerms(ctx, amount) + if err != nil { + return arkchannel.Record{}, err + } + if _, err := c.remote.RegisterPromotion(ctx, terms); err != nil { + return arkchannel.Record{}, err + } + if _, err := c.service.RegisterPromotion(ctx, terms); err != nil { + return arkchannel.Record{}, err + } + if _, err := c.service.StartOORPreparation(ctx, terms.ID); err != nil { + return arkchannel.Record{}, err + } + binding, err := c.cfg.PrepareOOR( + ctx, terms, arkchannel.DefaultBackingFee, + ) + if err != nil { + return arkchannel.Record{}, err + } + if _, err := c.remote.BindPreparedOOR( + ctx, terms.ID, binding, + ); err != nil { + return arkchannel.Record{}, err + } + if _, err := c.service.BindPreparedOOR( + ctx, terms.ID, binding, + ); err != nil { + return arkchannel.Record{}, err + } + + return c.service.GetChannel(ctx, terms.ID) +} + +// newPromotionTerms creates unique protocol identifiers and binds every key +// role to the two endpoint wallets. +func (c *NativeArkChannelController) newPromotionTerms(ctx context.Context, + amount btcutil.Amount) (arkchannel.Terms, error) { + + var id arkchannel.ID + if _, err := rand.Read(id[:]); err != nil { + return arkchannel.Terms{}, err + } + var pending [32]byte + if _, err := rand.Read(pending[:]); err != nil { + return arkchannel.Terms{}, err + } + var txIndexBytes [4]byte + if _, err := rand.Read(txIndexBytes[:3]); err != nil { + return arkchannel.Terms{}, err + } + _, height, err := c.cfg.Wallet.BtcWallet.GetBestBlock() + if err != nil { + return arkchannel.Terms{}, err + } + if height < 0 { + return arkchannel.Terms{}, fmt.Errorf("invalid channel chain " + + "height") + } + txIndex := binary.BigEndian.Uint32(txIndexBytes[:]) & 0x00ffffff + if txIndex == 0 { + txIndex = 1 + } + scid := lnwire.ShortChannelID{ + BlockHeight: uint32(height) + 1, + TxIndex: txIndex, TxPosition: 0, + }.ToUint64() + + return c.newClientFundedTerms( + id, pending, scid, amount, arkchannel.KindPromotion, + lntypes.Hash{}, + ) +} + +// newClientFundedTerms binds deterministic or random protocol identifiers to +// this endpoint's fixed channel and Ark keys. +func (c *NativeArkChannelController) newClientFundedTerms(id arkchannel.ID, + pending [32]byte, scid uint64, amount btcutil.Amount, + kind arkchannel.Kind, paymentHash lntypes.Hash) (arkchannel.Terms, + error) { + + terms := arkchannel.Terms{ + ID: id, Kind: kind, Funder: arkchannel.PartyClient, + PendingChannelID: pending, ReservedSCID: scid, + Capacity: amount, PaymentHash: paymentHash, + VTXO: arkchannel.VTXOTerms{ + ChannelDelay: c.peerInfo.ChannelDelay, + FunderDelay: c.peerInfo.FunderDelay, + MinExitDelay: c.peerInfo.MinimumExitDelay, + }, + } + copy( + terms.ClientNodeKey[:], + c.cfg.IdentityKey.PubKey.SerializeCompressed(), + ) + terms.HubNodeKey = c.peerInfo.HubNodeKey + copy( + terms.VTXO.ClientArkKey[:], + c.keys.ark.PubKey.SerializeCompressed(), + ) + terms.VTXO.HubArkKey = c.peerInfo.HubArkKey + terms.VTXO.ArkOperatorKey = c.peerInfo.ArkOperatorKey + copy( + terms.VTXO.ClientChannelKey[:], + c.keys.backing.PubKey.SerializeCompressed(), + ) + terms.VTXO.HubChannelKey = c.peerInfo.HubChannelKey + copy( + terms.VTXO.FunderKey[:], + c.keys.funder.PubKey.SerializeCompressed(), + ) + + return terms, terms.Validate() +} + +// newReceiveIntentTerms binds one deterministic invoice reservation to the +// hub's Ark funding key and the client's channel endpoint keys. +func (c *NativeArkChannelController) newReceiveIntentTerms( + paymentHash lntypes.Hash, reservedSCID uint64, + capacity btcutil.Amount) (arkchannel.Terms, error) { + + pendingChannelID := arkchannel.ReceiveIntentPendingID(paymentHash) + terms := arkchannel.Terms{ + ID: arkchannel.ReceiveIntentID(paymentHash), + Kind: arkchannel.KindReceiveIntent, + Funder: arkchannel.PartyHub, + PendingChannelID: pendingChannelID, + ReservedSCID: reservedSCID, Capacity: capacity, + PaymentHash: paymentHash, + VTXO: arkchannel.VTXOTerms{ + ChannelDelay: c.peerInfo.ChannelDelay, + FunderDelay: c.peerInfo.FunderDelay, + MinExitDelay: c.peerInfo.MinimumExitDelay, + HubArkKey: c.peerInfo.HubArkKey, + HubChannelKey: c.peerInfo.HubChannelKey, + ArkOperatorKey: c.peerInfo.ArkOperatorKey, + FunderKey: c.peerInfo.HubFunderKey, + }, + } + copy( + terms.ClientNodeKey[:], + c.cfg.IdentityKey.PubKey.SerializeCompressed(), + ) + terms.HubNodeKey = c.peerInfo.HubNodeKey + copy( + terms.VTXO.ClientArkKey[:], + c.keys.ark.PubKey.SerializeCompressed(), + ) + copy( + terms.VTXO.ClientChannelKey[:], + c.keys.backing.PubKey.SerializeCompressed(), + ) + + return terms, terms.Validate() +} + +// SendPayment creates a hub invoice and pays it through native lnd. +func (c *NativeArkChannelController) SendPayment(ctx context.Context, + id arkchannel.ID, amount btcutil.Amount) (lntypes.Hash, error) { + + if c.party != arkchannel.PartyClient { + return lntypes.Hash{}, fmt.Errorf("client payment RPC is not " + + "available on the hub endpoint") + } + if err := c.ensureClientStarted(ctx); err != nil { + return lntypes.Hash{}, err + } + record, err := c.service.GetChannel(ctx, id) + if err != nil { + return lntypes.Hash{}, err + } + hash, err := c.paymentPeer.CreateInvoice(ctx, id, amount) + if err != nil { + return lntypes.Hash{}, err + } + if err := c.node.PayInvoice(ctx, record, hash, amount); err != nil { + return lntypes.Hash{}, err + } + + return hash, nil +} + +// ReceivePayment creates a local invoice and asks the hub to pay it. +func (c *NativeArkChannelController) ReceivePayment(ctx context.Context, + id arkchannel.ID, amount btcutil.Amount) (lntypes.Hash, error) { + + if c.party != arkchannel.PartyClient { + return lntypes.Hash{}, fmt.Errorf("client payment RPC is not " + + "available on the hub endpoint") + } + if err := c.ensureClientStarted(ctx); err != nil { + return lntypes.Hash{}, err + } + if _, err := c.service.GetChannel(ctx, id); err != nil { + return lntypes.Hash{}, err + } + _, hash, err := c.node.AddInvoice(ctx, amount) + if err != nil { + return lntypes.Hash{}, err + } + if err := c.paymentPeer.PayInvoice(ctx, id, hash, amount); err != nil { + return lntypes.Hash{}, err + } + settled, err := c.node.InvoiceSettled(ctx, hash) + if err != nil { + return lntypes.Hash{}, err + } + if !settled { + return lntypes.Hash{}, fmt.Errorf("native client invoice did " + + "not settle") + } + + return hash, nil +} + +// PayLightningInvoice asks the hub to dispatch one public invoice only after +// this endpoint's private same-hash HTLC is held. +func (c *NativeArkChannelController) PayLightningInvoice(ctx context.Context, + paymentRequest string, maxFee btcutil.Amount) (LightningPaymentResult, + error) { + + if c.party != arkchannel.PartyClient { + return LightningPaymentResult{}, fmt.Errorf("public payment " + + "is available only on the client endpoint") + } + if paymentRequest == "" || maxFee < 0 { + return LightningPaymentResult{}, fmt.Errorf("valid payment " + + "request and maximum fee are required") + } + if err := c.ensureClientStarted(ctx); err != nil { + return LightningPaymentResult{}, err + } + preparation, err := c.paymentPeer.PrepareOutgoingPayment( + ctx, paymentRequest, maxFee, + ) + if err != nil { + return LightningPaymentResult{}, err + } + record, err := c.service.GetChannel(ctx, preparation.ChannelID) + if err != nil { + return LightningPaymentResult{}, err + } + if record.Snapshot.Terms.ReservedSCID != preparation.ReservedSCID { + return LightningPaymentResult{}, fmt.Errorf("payment " + + "preparation changed channel SCID") + } + preimage, err := c.node.PayInvoiceResult( + ctx, record, preparation.PaymentHash, preparation.PrivateAmount, + ) + if err != nil { + cancelErr := c.paymentPeer.CancelOutgoingPayment( + ctx, preparation.PaymentHash, err.Error(), + ) + if cancelErr != nil { + return LightningPaymentResult{}, errors.Join( + err, fmt.Errorf("cancel outgoing payment: %w", + cancelErr), + ) + } + + return LightningPaymentResult{}, err + } + if preimage.Hash() != preparation.PaymentHash { + return LightningPaymentResult{}, fmt.Errorf("payment " + + "preimage does not match preparation") + } + + return LightningPaymentResult{ + PaymentHash: preparation.PaymentHash, Preimage: preimage, + PrivateAmount: preparation.PrivateAmount, Fee: preparation.Fee, + ChannelID: preparation.ChannelID, + }, nil +} + +// PrepareIncomingPayment installs the known-preimage native invoice before a +// route hint can be exposed to an external payer. +func (c *NativeArkChannelController) PrepareIncomingPayment(ctx context.Context, + preimage lntypes.Preimage, amount btcutil.Amount) error { + + if c.party != arkchannel.PartyClient { + return fmt.Errorf("incoming payment preparation is client only") + } + if err := c.ensureClientStarted(ctx); err != nil { + return err + } + + return c.AddInvoiceWithPreimage(ctx, preimage, amount) +} + +// RegisterIncomingPayment binds the advertised future SCID to this +// authenticated endpoint after the private invoice is durable. +func (c *NativeArkChannelController) RegisterIncomingPayment( + ctx context.Context, hash lntypes.Hash, amount btcutil.Amount, + reservedSCID uint64) error { + + if c.party != arkchannel.PartyClient { + return fmt.Errorf("incoming payment registration is client " + + "only") + } + if err := c.ensureClientStarted(ctx); err != nil { + return err + } + + capacity, err := c.paymentPeer.RegisterIncomingPayment( + ctx, hash, amount, reservedSCID, + ) + if err != nil { + return err + } + terms, err := c.newReceiveIntentTerms( + hash, reservedSCID, capacity, + ) + if err != nil { + return err + } + if _, err := c.remote.RegisterReceiveIntent(ctx, terms); err != nil { + return err + } + _, err = c.service.RegisterReceiveIntent(ctx, terms) + + return err +} + +// WaitIncomingPayment waits for the known-preimage private invoice to settle. +func (c *NativeArkChannelController) WaitIncomingPayment(ctx context.Context, + hash lntypes.Hash) (arkchannel.ID, error) { + + if c.party != arkchannel.PartyClient { + return arkchannel.ID{}, fmt.Errorf("incoming payment wait is " + + "client only") + } + if err := c.ensureClientStarted(ctx); err != nil { + return arkchannel.ID{}, err + } + + invoiceResult := make(chan error, 1) + go func() { + invoiceResult <- c.WaitInvoiceSettled(ctx, hash) + }() + syncResult := make(chan error, 1) + go func() { + syncResult <- c.syncReceiveIntent(ctx, hash) + }() + + for { + select { + case err := <-invoiceResult: + if err != nil { + return arkchannel.ID{}, err + } + + id := arkchannel.ReceiveIntentID(hash) + record, getErr := c.service.GetChannel(ctx, id) + if getErr != nil { + if c.cfg.Log != nil { + c.cfg.Log.WarnS(ctx, "Receive channel result "+ + "lookup failed", getErr, + btclog.Hex( + "payment_hash", hash[:], + ), + ) + } + + return arkchannel.ID{}, nil + } + if record.Snapshot.Phase != arkchannel.PhaseActive || + record.Snapshot.Terms.Kind != + arkchannel.KindReceiveIntent { + return arkchannel.ID{}, nil + } + + return id, nil + + case err := <-syncResult: + if err != nil && c.cfg.Log != nil { + c.cfg.Log.WarnS( + ctx, + "Receive channel intent stopped", + err, + btclog.Hex("payment_hash", hash[:]), + ) + } + syncResult = nil + + case <-ctx.Done(): + return arkchannel.ID{}, ctx.Err() + } + } +} + +// syncReceiveIntent binds a hub-prepared source locally and lets the common +// funding FSM negotiate, commit, recover, and activate the channel. +func (c *NativeArkChannelController) syncReceiveIntent(ctx context.Context, + hash lntypes.Hash) error { + + id := arkchannel.ReceiveIntentID(hash) + ticker := time.NewTicker(arkChannelControllerPollInterval) + defer ticker.Stop() + for { + remote, err := c.remote.GetFundingChannel(ctx, id) + if err != nil { + return err + } + local, err := c.service.GetChannel(ctx, id) + if err != nil { + return err + } + if remote.Phase == arkchannel.PhaseFailed { + return c.mirrorReceiveIntentFailure( + ctx, local, remote, + ) + } + if local.Snapshot.Phase == arkchannel.PhaseActive { + return nil + } + if remote.Source != nil && local.Snapshot.Source == nil { + _, err := c.service.BindPreparedOOR( + ctx, id, *remote.Source, + ) + if err != nil { + return c.failReceiveIntent(ctx, id, err) + } + + continue + } + if remote.Source != nil && local.Snapshot.Source != nil && + (local.Snapshot.Phase == arkchannel.PhaseRequested || + remote.Phase == arkchannel.PhaseRequested) { + + event := &arkchannel.FundingPeerReady{} + if local.Snapshot.Phase == arkchannel.PhaseRequested { + if _, err := c.service.RecordChannelEvent( + ctx, id, event, + ); err != nil { + return c.failReceiveIntent(ctx, id, err) + } + } + if remote.Phase == arkchannel.PhaseRequested { + if _, err := c.remote.ApplyChannelEvent( + ctx, id, event, + ); err != nil { + return c.failReceiveIntent(ctx, id, err) + } + } + + continue + } + if remote.OORFinalized && !local.Snapshot.RecoveryReady { + if local.Snapshot.Source == nil || + local.Snapshot.Backing == nil { + return fmt.Errorf("finalized receive channel " + + "is missing funding artifacts") + } + recovery, err := c.remote.ExportRecoveryPackage(ctx, id) + if err != nil { + return err + } + if err := c.cfg.Recovery.InstallRecoveryPackage( + ctx, id, local.Snapshot.Terms, + *local.Snapshot.Source, recovery, + ); err != nil { + return err + } + event := &arkchannel.RecoveryPackageInstalled{} + if _, err := c.remote.ApplyChannelEvent( + ctx, id, event, + ); err != nil { + return err + } + if _, err := c.service.Apply( + ctx, id, event, + ); err != nil { + return err + } + + continue + } + + select { + case <-ctx.Done(): + return ctx.Err() + + case <-ticker.C: + } + } +} + +// failReceiveIntent abandons both prepared channel records only while their +// common FSM still proves that the hub OOR can be aborted safely. +func (c *NativeArkChannelController) failReceiveIntent(ctx context.Context, + id arkchannel.ID, cause error) error { + + reason := cause.Error() + if _, err := c.remote.ApplyChannelEvent( + ctx, id, &arkchannel.Fail{ + Reason: reason, + }, + ); err != nil { + return errors.Join(cause, err) + } + _, err := c.service.Apply(ctx, id, &arkchannel.Fail{Reason: reason}) + if err != nil { + return errors.Join(cause, err) + } + + return cause +} + +// mirrorReceiveIntentFailure applies the hub's terminal pre-PONR failure to +// the local channel record so restart recovery has no abandoned reservation. +func (c *NativeArkChannelController) mirrorReceiveIntentFailure( + ctx context.Context, local arkchannel.Record, + remote lnruntime.FundingChannelState) error { + + reason := remote.Failure + if reason == "" { + reason = "hub receive channel failed" + } + if local.Snapshot.Phase == arkchannel.PhaseFailed { + return fmt.Errorf("%w: %s", ErrReceiveChannelFallback, reason) + } + record := local + if local.Snapshot.Phase == arkchannel.PhaseRequested || + local.Snapshot.Phase == arkchannel.PhaseNegotiating { + + var err error + record, err = c.service.Apply( + ctx, local.Snapshot.Terms.ID, &arkchannel.Fail{ + Reason: reason, + }, + ) + if err != nil { + return err + } + } + if remote.OORAborted && record.Snapshot.Source != nil && + (record.Snapshot.Phase == arkchannel.PhaseCancelling || + record.Snapshot.Phase == arkchannel.PhaseBackingReady) { + + _, err := c.service.Apply( + ctx, local.Snapshot.Terms.ID, &arkchannel.OORAborted{ + SessionID: record.Snapshot.Source.OORSessionID, + Reason: reason, + }, + ) + if err != nil { + return err + } + } else if record.Snapshot.Phase != arkchannel.PhaseFailed { + return fmt.Errorf("hub receive channel failed without a " + + "definitive pre-PONR OOR abort") + } + + return fmt.Errorf("%w: %s", ErrReceiveChannelFallback, reason) +} + +// prepareIncomingChannelSource durably orders capital admission before wallet +// selection and binds the exact prepared OOR output to the channel FSM. +func (c *NativeArkChannelController) prepareIncomingChannelSource( + ctx context.Context, record arkchannel.Record) error { + + snapshot := record.Snapshot + if snapshot.Phase != arkchannel.PhaseRequested || + snapshot.Source != nil { + return nil + } + if c.cfg.PrepareOOR == nil { + return fmt.Errorf("hub channel OOR preparer is unavailable") + } + if _, err := c.service.StartOORPreparation( + ctx, snapshot.Terms.ID, + ); err != nil { + return err + } + if err := c.cfg.ReserveReceiveCapital(ctx, snapshot.Terms); err != nil { + if !errors.Is(err, ErrReceiveChannelFallback) { + return err + } + _, failErr := c.service.Apply( + ctx, snapshot.Terms.ID, &arkchannel.Fail{ + Reason: err.Error(), + }, + ) + + return errors.Join(err, failErr) + } + + binding, err := c.cfg.PrepareOOR( + ctx, snapshot.Terms, arkchannel.DefaultBackingFee, + ) + if err == nil { + _, err = c.service.BindPreparedOOR( + ctx, snapshot.Terms.ID, binding, + ) + + return err + } + if errors.Is(err, arkchannel.ErrOORPreparationAmbiguous) { + return fmt.Errorf("reconcile ambiguous receive channel OOR: %w", + err) + } + _, failErr := c.service.Apply( + ctx, snapshot.Terms.ID, &arkchannel.Fail{ + Reason: err.Error(), + }, + ) + + return errors.Join( + fmt.Errorf("%w: %w", ErrReceiveChannelFallback, err), failErr, + ) +} + +// ManifestIncomingChannel binds hub-owned Ark liquidity to a registered +// receive intent and drives native lnd funding after the client records the +// exact prepared source. +func (c *NativeArkChannelController) ManifestIncomingChannel( + ctx context.Context, hash lntypes.Hash, amount, capacity btcutil.Amount, + reservedSCID uint64) (arkchannel.Record, error) { + + if c.party != arkchannel.PartyHub { + return arkchannel.Record{}, fmt.Errorf("receive channel " + + "funding is hub only") + } + id := arkchannel.ReceiveIntentID(hash) + record, err := c.service.GetChannel(ctx, id) + if err != nil { + return arkchannel.Record{}, err + } + terms := record.Snapshot.Terms + if terms.Kind != arkchannel.KindReceiveIntent || + terms.Funder != arkchannel.PartyHub || + terms.PaymentHash != hash || terms.Capacity != capacity || + terms.ReservedSCID != reservedSCID || capacity < amount { + return arkchannel.Record{}, fmt.Errorf("receive intent does " + + "not match intercepted payment") + } + if err := c.prepareIncomingChannelSource(ctx, record); err != nil { + return arkchannel.Record{}, err + } + + ticker := time.NewTicker(arkChannelControllerPollInterval) + defer ticker.Stop() + for { + record, err = c.service.GetChannel(ctx, id) + if err != nil { + return arkchannel.Record{}, err + } + switch record.Snapshot.Phase { + case arkchannel.PhaseNegotiating: + _, err = c.service.ResumeChannelAction(ctx, id) + if err != nil { + return arkchannel.Record{}, err + } + + continue + + case arkchannel.PhaseActive: + return record, nil + + case arkchannel.PhaseFailed: + return arkchannel.Record{}, fmt.Errorf("%w: %s", + ErrReceiveChannelFallback, + record.Snapshot.Failure) + + case arkchannel.PhaseRequested, arkchannel.PhaseBackingReady, + arkchannel.PhaseActivating, arkchannel.PhaseCancelling: + + // The opposite endpoint or a replayable FSM action + // still has work in flight. Poll the durable record + // below. + + case arkchannel.PhaseMaterializing, arkchannel.PhaseOnChain, + arkchannel.PhaseClosed, arkchannel.PhaseCoopClosing, + arkchannel.PhaseCoopCloseSigned, + arkchannel.PhaseCoopClosePublished: + return arkchannel.Record{}, fmt.Errorf("receive "+ + "channel entered unexpected phase %s before "+ + "activation", record.Snapshot.Phase) + + default: + return arkchannel.Record{}, fmt.Errorf("receive "+ + "channel has unknown phase %d", + record.Snapshot.Phase) + } + + select { + case <-ctx.Done(): + return arkchannel.Record{}, ctx.Err() + + case <-ticker.C: + } + } +} + +// AbandonReceiveIntent removes an unused pre-funding reservation. Active +// channels are retained because their liquidity is reusable after this +// particular incoming payment takes another route. +func (c *NativeArkChannelController) AbandonReceiveIntent(ctx context.Context, + hash lntypes.Hash, reason string) error { + + if c.party != arkchannel.PartyHub { + return fmt.Errorf("receive intent abandonment is hub only") + } + if reason == "" { + return fmt.Errorf("receive intent abandonment reason is " + + "required") + } + id := arkchannel.ReceiveIntentID(hash) + record, err := c.service.GetChannel(ctx, id) + if err != nil { + return err + } + if record.Snapshot.Terms.Kind != arkchannel.KindReceiveIntent || + record.Snapshot.Terms.PaymentHash != hash { + return fmt.Errorf("channel is not this payment's receive " + + "intent") + } + switch record.Snapshot.Phase { + case arkchannel.PhaseRequested: + _, err := c.service.Apply( + ctx, id, &arkchannel.Fail{ + Reason: reason, + }, + ) + + return err + + case arkchannel.PhaseFailed, arkchannel.PhaseActive, + arkchannel.PhaseMaterializing, arkchannel.PhaseOnChain, + arkchannel.PhaseClosed, arkchannel.PhaseCoopClosing, + arkchannel.PhaseCoopCloseSigned, + arkchannel.PhaseCoopClosePublished: + return nil + + default: + return fmt.Errorf("cannot abandon receive intent from %s", + record.Snapshot.Phase) + } +} + +// MaterializeAndForceClose asks lnd to force close. Its blocking publication +// barrier materializes the client-funded backing first, while the peer learns +// the lifecycle only from its already armed chain watcher. +func (c *NativeArkChannelController) MaterializeAndForceClose( + ctx context.Context, id arkchannel.ID) (arkchannel.Record, + chainhash.Hash, chainhash.Hash, error) { + + if c.party != arkchannel.PartyClient { + return arkchannel.Record{}, chainhash.Hash{}, chainhash.Hash{}, + fmt.Errorf("only a client can request force close") + } + if err := c.ensureClientStarted(ctx); err != nil { + return arkchannel.Record{}, chainhash.Hash{}, + chainhash.Hash{}, err + } + record, err := c.service.GetChannel(ctx, id) + if err != nil { + return arkchannel.Record{}, chainhash.Hash{}, + chainhash.Hash{}, err + } + if record.Snapshot.Backing == nil { + return arkchannel.Record{}, chainhash.Hash{}, chainhash.Hash{}, + fmt.Errorf("materialized channel backing is missing") + } + backing := record.Snapshot.Backing.Clone() + closeTx, err := c.node.ForceCloseChannel(backing.ChannelPoint) + var closeTxID chainhash.Hash + if err == nil { + if closeTx == nil { + return arkchannel.Record{}, chainhash.Hash{}, + chainhash.Hash{}, fmt.Errorf("lnd returned " + + "no force-close transaction") + } + closeTxID = closeTx.TxHash() + } else { + // Both endpoints watch the unpublished channel point before Ark + // materializes it. Either endpoint may therefore win the + // commitment publication race. Only lnd's durable close summary + // can turn the losing broadcast error into success. + var waitErr error + closeTxID, waitErr = c.node.WaitForceCloseResult( + ctx, backing.ChannelPoint, + ) + if waitErr != nil { + return arkchannel.Record{}, chainhash.Hash{}, + chainhash.Hash{}, fmt.Errorf("force close "+ + "channel: %w; reconcile peer close: %v", + err, waitErr) + } + } + record, err = c.service.GetChannel(ctx, id) + if err != nil { + return arkchannel.Record{}, chainhash.Hash{}, + chainhash.Hash{}, err + } + + return record, backing.ChannelPoint.Hash, closeTxID, nil +} + +// RequestCooperativeClose starts the client-owned 3-of-3 OOR close process. +func (c *NativeArkChannelController) RequestCooperativeClose( + ctx context.Context, id arkchannel.ID) (arkchannel.Record, error) { + + if c.party != arkchannel.PartyClient { + return arkchannel.Record{}, fmt.Errorf("only a client can " + + "request cooperative close") + } + if err := c.ensureClientStarted(ctx); err != nil { + return arkchannel.Record{}, err + } + + return c.clientClose.RequestCooperativeClose(ctx, id) +} + +// GetChannel returns the endpoint's durable Ark channel record. +func (c *NativeArkChannelController) GetChannel(ctx context.Context, + id arkchannel.ID) (arkchannel.Record, error) { + + if c.party == arkchannel.PartyClient { + if err := c.ensureClientStarted(ctx); err != nil { + return arkchannel.Record{}, err + } + } + + return c.service.GetChannel(ctx, id) +} + +// SelectActiveChannel finds an ordinary native channel with enough balance on +// the requested local or remote side. lnd remains authoritative and may still +// reject a racing payment that consumes the same balance. +func (c *NativeArkChannelController) SelectActiveChannel(ctx context.Context, + amount btcutil.Amount, localSends bool) (arkchannel.Record, error) { + + if amount <= 0 { + return arkchannel.Record{}, fmt.Errorf("payment amount must " + + "be positive") + } + if c.party == arkchannel.PartyClient { + if err := c.ensureClientStarted(ctx); err != nil { + return arkchannel.Record{}, err + } + } + c.mu.RLock() + service := c.service + node := c.node + c.mu.RUnlock() + if service == nil || node == nil { + return arkchannel.Record{}, fmt.Errorf("native Ark channel " + + "endpoint is not ready") + } + records, err := service.ListChannels(ctx) + if err != nil { + return arkchannel.Record{}, err + } + for _, record := range records { + if record.Snapshot.Phase != arkchannel.PhaseActive { + continue + } + local, remote, err := node.ChannelBalance(record) + if err != nil { + continue + } + available := remote + if localSends { + available = local + } + if available >= amount { + return record, nil + } + } + + return arkchannel.Record{}, fmt.Errorf("%w for %d sat", + ErrInsufficientArkChannelLiquidity, amount) +} + +// AddHoldInvoice registers the private source for an outgoing bridge. +func (c *NativeArkChannelController) AddHoldInvoice(ctx context.Context, + hash lntypes.Hash, amount btcutil.Amount) error { + + if c.party == arkchannel.PartyClient { + if err := c.ensureClientStarted(ctx); err != nil { + return err + } + } + + return c.node.AddHoldInvoice(ctx, hash, amount) +} + +// AddInvoiceWithPreimage registers the private destination for an incoming +// bridge before its BOLT 11 invoice is exposed to a payer. +func (c *NativeArkChannelController) AddInvoiceWithPreimage(ctx context.Context, + preimage lntypes.Preimage, amount btcutil.Amount) error { + + if c.party == arkchannel.PartyClient { + if err := c.ensureClientStarted(ctx); err != nil { + return err + } + } + _, err := c.node.AddInvoiceWithPreimage( + ctx, amount, preimage, false, + ) + + return err +} + +// WaitInvoiceAccepted waits for the private outgoing source HTLC. +func (c *NativeArkChannelController) WaitInvoiceAccepted(ctx context.Context, + hash lntypes.Hash) error { + + return c.node.WaitInvoiceAccepted(ctx, hash) +} + +// WaitInvoiceSettled waits for an incoming private destination to settle. +func (c *NativeArkChannelController) WaitInvoiceSettled(ctx context.Context, + hash lntypes.Hash) error { + + return c.node.WaitInvoiceSettled(ctx, hash) +} + +// SettleHoldInvoice releases the private outgoing source with the public +// destination preimage. +func (c *NativeArkChannelController) SettleHoldInvoice(ctx context.Context, + preimage lntypes.Preimage) error { + + return c.node.SettleHoldInvoice(ctx, preimage) +} + +// CancelInvoice fails a private source before a preimage is known. +func (c *NativeArkChannelController) CancelInvoice(ctx context.Context, + hash lntypes.Hash) error { + + return c.node.CancelInvoice(ctx, hash) +} + +// PayHash sends or resumes one same-hash payment over a selected private +// channel and returns the destination preimage. +func (c *NativeArkChannelController) PayHash(ctx context.Context, + id arkchannel.ID, hash lntypes.Hash, amount btcutil.Amount) ( + lntypes.Preimage, error) { + + if c.party == arkchannel.PartyClient { + if err := c.ensureClientStarted(ctx); err != nil { + return lntypes.Preimage{}, err + } + } + record, err := c.service.GetChannel(ctx, id) + if err != nil { + return lntypes.Preimage{}, err + } + + return c.node.PayInvoiceResult(ctx, record, hash, amount) +} + +// PeerMessageHandler dispatches authenticated BOLT messages into native lnd. +// +//nolint:ll // The concrete method name and interface type are both significant. +func (c *NativeArkChannelController) PeerMessageHandler() lnruntime.PeerEventHandler { + return func(ctx context.Context, message lnwire.Message) error { + if c.party == arkchannel.PartyClient { + if err := c.ensureClientStarted(ctx); err != nil { + return fmt.Errorf("start native Ark channel "+ + "endpoint: %w", err) + } + } + log := c.cfg.Log + if log == nil { + log = btclog.Disabled + } + log.DebugS(ctx, "Dispatching native Ark channel peer message", + btclog.Fmt("party", "%s", c.party), + btclog.Fmt("message_type", "%s", message.MsgType()), + ) + c.mu.RLock() + node := c.node + fundingWire := c.fundingWire + c.mu.RUnlock() + if node == nil { + return fmt.Errorf("native Ark channel endpoint is " + + "not ready") + } + + if fundingWire != nil && fundingWire.Handles(message) { + return fundingWire.Handle(ctx, message) + } + + return node.PeerMessageHandler()(ctx, message) + } +} + +// FundingPeerService returns the generated funding protocol for a hub +// controller bound to its authenticated client. +func (c *NativeArkChannelController) FundingPeerService(remoteNode [33]byte) ( + arkchannelrpc.ArkChannelFundingPeerServiceMailboxServer, error) { + + c.mu.RLock() + defer c.mu.RUnlock() + if c.party != arkchannel.PartyHub || c.node == nil || c.service == nil { + return nil, fmt.Errorf("hub Ark channel endpoint is not ready") + } + + return lnruntime.NewFundingPeerRPCServer( + lnruntime.FundingPeerRPCServerConfig{ + RemoteNode: remoteNode, Info: c.peerInfo, + Service: c.service, Funding: c.node.FundingEndpoint(), + Node: c.node, Recovery: c.cfg.Recovery, + Bridge: c.paymentBridge, + }, + ) +} + +// CooperativeClosePeerService returns the generated close protocol for a hub +// controller bound to its authenticated client. +func (c *NativeArkChannelController) CooperativeClosePeerService( + remoteNode [33]byte) (arkchannelrpc.ArkChannelPeerServiceMailboxServer, + error) { + + c.mu.RLock() + defer c.mu.RUnlock() + if c.party != arkchannel.PartyHub || c.hubClose == nil { + return nil, fmt.Errorf("hub cooperative close endpoint is " + + "not ready") + } + + return lnruntime.NewCooperativeClosePeerRPCServer( + remoteNode, c.hubClose, + ) +} + +// Stop releases native lnd state before the owning wallet and database stop. +func (c *NativeArkChannelController) Stop() error { + c.mu.Lock() + cancel := c.reaperCancel + c.reaperCancel = nil + c.mu.Unlock() + + if cancel != nil { + cancel() + } + c.reaperWG.Wait() + + c.mu.Lock() + defer c.mu.Unlock() + var err error + if c.fundingWire != nil { + c.fundingWire.Close() + c.fundingWire = nil + } + if c.node != nil { + err = c.node.Stop() + c.node = nil + } + if c.cfg.Recovery != nil { + c.cfg.Recovery.Stop() + } + + return err +} + +// arkChannelCloseDelivery returns the ordinary Ark account key that owns this +// endpoint's replacement VTXO after an in-Ark cooperative close. +type arkChannelCloseDelivery struct { + owner *btcec.PublicKey +} + +// newArkChannelCloseDelivery constructs a fixed OOR owner-key source. +func newArkChannelCloseDelivery( + owner *btcec.PublicKey) *arkChannelCloseDelivery { + + return &arkChannelCloseDelivery{owner: owner} +} + +// CooperativeCloseDelivery returns the compressed replacement VTXO owner key. +func (d *arkChannelCloseDelivery) CooperativeCloseDelivery(_ context.Context, + _ arkchannel.ID) ([]byte, error) { + + if d == nil || d.owner == nil { + return nil, fmt.Errorf("cooperative close OOR owner is " + + "required") + } + + return d.owner.SerializeCompressed(), nil +} + +// ValidateCooperativeCloseDelivery proves the replacement VTXO is assigned to +// this endpoint's ordinary Ark account. +func (d *arkChannelCloseDelivery) ValidateCooperativeCloseDelivery( + ctx context.Context, id arkchannel.ID, owner []byte) error { + + expected, err := d.CooperativeCloseDelivery(ctx, id) + if err != nil { + return err + } + if !bytes.Equal(expected, owner) { + return fmt.Errorf("cooperative close owner is not the " + + "configured Ark account") + } + + return nil +} + +var _ ArkChannelController = (*NativeArkChannelController)(nil) + +var _ lnruntime.CooperativeCloseDeliverySource = (*arkChannelCloseDelivery)(nil) + +//nolint:ll // Keeping the complete delivery contract explicit aids API audits. +var _ lnruntime.CooperativeCloseDeliveryValidator = (*arkChannelCloseDelivery)(nil) diff --git a/waved/native_ark_channel_controller_test.go b/waved/native_ark_channel_controller_test.go new file mode 100644 index 000000000..4896c82b5 --- /dev/null +++ b/waved/native_ark_channel_controller_test.go @@ -0,0 +1,343 @@ +package waved + +import ( + "fmt" + "testing" + + "github.com/btcsuite/btcd/wire/v2" + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/stretchr/testify/require" +) + +type recordingArkChannelBackingRestorer struct { + restored []arkchannel.ID + failID arkchannel.ID +} + +type recordingArkChannelForceCloseResumer struct { + failPoint wire.OutPoint + resumed []wire.OutPoint +} + +// ResumeForceCloseChannel records each independent on-chain reconciliation. +func (r *recordingArkChannelForceCloseResumer) ResumeForceCloseChannel( + channelPoint wire.OutPoint) error { + + r.resumed = append(r.resumed, channelPoint) + if channelPoint == r.failPoint { + return fmt.Errorf("injected force-close resume failure") + } + + return nil +} + +// RestoreBacking records each durable backing passed to native lnd startup. +func (r *recordingArkChannelBackingRestorer) RestoreBacking( + terms arkchannel.Terms, _ arkchannel.Backing) error { + + r.restored = append(r.restored, terms.ID) + if terms.ID == r.failID { + return fmt.Errorf("injected backing restore failure") + } + + return nil +} + +// TestShouldWatchArkChannel verifies restart admission follows durable channel +// ownership instead of admitting every channel in lnd's database. +func TestShouldWatchArkChannel(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + phase arkchannel.Phase + watch bool + }{ + { + name: "requested", + phase: arkchannel.PhaseRequested, + }, + { + name: "negotiating", + phase: arkchannel.PhaseNegotiating, + }, + { + name: "backing ready", + phase: arkchannel.PhaseBackingReady, + }, + { + name: "activating", + phase: arkchannel.PhaseActivating, + watch: true, + }, + { + name: "active", + phase: arkchannel.PhaseActive, + watch: true, + }, + { + name: "materializing", + phase: arkchannel.PhaseMaterializing, + watch: true, + }, + { + name: "on chain", + phase: arkchannel.PhaseOnChain, + watch: true, + }, + { + name: "closed", + phase: arkchannel.PhaseClosed, + }, + { + name: "cancelling", + phase: arkchannel.PhaseCancelling, + }, + { + name: "failed", + phase: arkchannel.PhaseFailed, + }, + { + name: "coop closing", + phase: arkchannel.PhaseCoopClosing, + watch: true, + }, + { + name: "coop close signed", + phase: arkchannel.PhaseCoopCloseSigned, + watch: true, + }, + { + name: "coop close published", + phase: arkchannel.PhaseCoopClosePublished, + watch: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + actual := shouldWatchArkChannel(test.phase) + require.Equal(t, test.watch, actual) + }) + } +} + +// TestShouldRestoreArkChannelAddsDisabled verifies only an in-progress +// cooperative close restores its lnd link in the quiesced state. +func TestShouldRestoreArkChannelAddsDisabled(t *testing.T) { + t.Parallel() + + quiesced := []arkchannel.Phase{ + arkchannel.PhaseCoopClosing, + arkchannel.PhaseCoopCloseSigned, + arkchannel.PhaseCoopClosePublished, + } + for phase := arkchannel.PhaseRequested; phase <= + arkchannel.PhaseCoopClosePublished; phase++ { + + expected := false + for _, closePhase := range quiesced { + if phase == closePhase { + expected = true + break + } + } + require.Equal( + t, expected, shouldRestoreArkChannelAddsDisabled(phase), + phase.String(), + ) + } +} + +// TestRestoreNativeArkChannelBackingRecords verifies every live signed backing +// is registered before lnd startup while unsigned and archived channels are +// skipped. +func TestRestoreNativeArkChannelBackingRecords(t *testing.T) { + t.Parallel() + + firstID := arkchannel.ID{1} + secondID := arkchannel.ID{2} + thirdID := arkchannel.ID{3} + closedID := arkchannel.ID{4} + restorer := &recordingArkChannelBackingRestorer{} + records := []arkchannel.Record{ + { + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: firstID, + }, + Backing: &arkchannel.Backing{ + Transaction: []byte{ + 1, + }, + }, + }, + }, + { + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: arkchannel.ID{ + 9, + }, + }, + }, + }, + { + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: secondID, + }, + Backing: &arkchannel.Backing{ + Transaction: []byte{ + 2, + }, + }, + }, + }, + { + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: thirdID, + }, + Backing: &arkchannel.Backing{ + Transaction: []byte{ + 3, + }, + }, + }, + }, + { + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: closedID, + }, + Phase: arkchannel.PhaseClosed, + Backing: &arkchannel.Backing{ + Transaction: []byte{ + 4, + }, + }, + }, + }, + } + require.NoError( + t, restoreNativeArkChannelBackingRecords( + restorer, records, + ), + ) + require.Equal( + t, []arkchannel.ID{firstID, secondID, thirdID}, + restorer.restored, + ) + + restorer = &recordingArkChannelBackingRestorer{failID: secondID} + err := restoreNativeArkChannelBackingRecords(restorer, records) + var failures *arkchannel.ResumeFailures + require.ErrorAs(t, err, &failures) + require.Len(t, failures.Failures, 1) + require.Equal(t, secondID, failures.Failures[0].ChannelID) + require.ErrorContains( + t, failures.Failures[0].Err, "injected backing restore failure", + ) + require.Equal( + t, []arkchannel.ID{firstID, secondID, thirdID}, + restorer.restored, + ) +} + +// TestResumeOnchainArkChannelRecordsIsolatesFailures verifies one broken lnd +// close record does not suppress reconciliation for another channel. +func TestResumeOnchainArkChannelRecordsIsolatesFailures(t *testing.T) { + t.Parallel() + + firstPoint := wire.OutPoint{Index: 1} + secondPoint := wire.OutPoint{Index: 2} + resumer := &recordingArkChannelForceCloseResumer{ + failPoint: firstPoint, + } + records := []arkchannel.Record{ + { + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: arkchannel.ID{ + 1, + }, + }, + Phase: arkchannel.PhaseOnChain, + Backing: &arkchannel.Backing{ + ChannelPoint: firstPoint, + }, + }, + }, + { + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: arkchannel.ID{ + 9, + }, + }, + Phase: arkchannel.PhaseActive, + }, + }, + { + Snapshot: arkchannel.Snapshot{ + Terms: arkchannel.Terms{ + ID: arkchannel.ID{ + 2, + }, + }, + Phase: arkchannel.PhaseOnChain, + Backing: &arkchannel.Backing{ + ChannelPoint: secondPoint, + }, + }, + }, + } + err := resumeOnchainArkChannelRecords(resumer, records) + var failures *arkchannel.ResumeFailures + require.ErrorAs(t, err, &failures) + require.Len(t, failures.Failures, 1) + require.Equal(t, arkchannel.ID{1}, failures.Failures[0].ChannelID) + require.Equal( + t, []wire.OutPoint{firstPoint, secondPoint}, resumer.resumed, + ) +} + +// TestShouldResumeOnchainArkChannel verifies either recovery-ready endpoint +// re-drives lnd commitment publication after backing materialization. +func TestShouldResumeOnchainArkChannel(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + phase arkchannel.Phase + expected bool + }{ + { + name: "on-chain channel resumes commitment", + phase: arkchannel.PhaseOnChain, expected: true, + }, + { + name: "active source has nothing to resume", + phase: arkchannel.PhaseActive, + }, + { + name: "closed source has nothing to resume", + phase: arkchannel.PhaseClosed, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshot := arkchannel.Snapshot{Phase: test.phase} + require.Equal( + t, test.expected, + shouldResumeOnchainArkChannel(snapshot), + ) + }) + } +} diff --git a/waved/rpc_ark_channel_oor.go b/waved/rpc_ark_channel_oor.go new file mode 100644 index 000000000..220bf8028 --- /dev/null +++ b/waved/rpc_ark_channel_oor.go @@ -0,0 +1,231 @@ +package waved + +import ( + "context" + "errors" + "fmt" + + "github.com/lightninglabs/wavelength/arkchannel" + "github.com/lightninglabs/wavelength/arkchannel/oorbridge" + "github.com/lightninglabs/wavelength/lnruntime" + "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" + "github.com/lightninglabs/wavelength/waverpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// PrepareArkChannelOOR reserves daemon-owned VTXOs and creates the exact +// channel-policy output without releasing any OOR signatures. +func (r *RPCServer) PrepareArkChannelOOR(ctx context.Context, + req *waverpc.PrepareArkChannelOORRequest) ( + *waverpc.PrepareArkChannelOORResponse, error) { + + terms, err := lnruntime.ChannelTermsFromRPC(req.GetTerms()) + if err != nil { + return nil, err + } + if terms.Funder != arkchannel.PartyHub || + terms.Kind != arkchannel.KindReceiveIntent { + return nil, fmt.Errorf("daemon channel OOR must fund a " + + "receive intent") + } + binding, err := r.server.prepareArkChannelOOR( + ctx, terms, arkchannel.DefaultBackingFee, + ) + if err != nil { + if errors.Is(err, arkchannel.ErrOORPreparationAmbiguous) { + return nil, status.Error(codes.Aborted, err.Error()) + } + + return nil, err + } + + return &waverpc.PrepareArkChannelOORResponse{ + Binding: lnruntime.ChannelBindingToRPC(binding), + }, nil +} + +// LookupPreparedArkChannelOOR reconciles one deterministic channel OOR key +// without selecting or locking new wallet inputs. +func (r *RPCServer) LookupPreparedArkChannelOOR(ctx context.Context, + req *waverpc.LookupPreparedArkChannelOORRequest) ( + *waverpc.LookupPreparedArkChannelOORResponse, error) { + + terms, err := lnruntime.ChannelTermsFromRPC(req.GetTerms()) + if err != nil { + return nil, err + } + if terms.Funder != arkchannel.PartyHub || + terms.Kind != arkchannel.KindReceiveIntent { + return nil, fmt.Errorf("daemon channel OOR must fund a " + + "receive intent") + } + lookup, err := r.server.lookupArkChannelOOR( + ctx, terms, arkchannel.DefaultBackingFee, + ) + if err != nil { + return nil, err + } + + response := &waverpc.LookupPreparedArkChannelOORResponse{} + switch lookup.Status { + case oorbridge.PreparationAbsent: + case oorbridge.PreparationPending: + case oorbridge.PreparationPrepared: + response.Binding = lnruntime.ChannelBindingToRPC(lookup.Binding) + + case oorbridge.PreparationAccepted: + default: + return nil, fmt.Errorf("unknown channel OOR preparation "+ + "status %d", lookup.Status) + } + // The RPC enum reserves zero for unspecified while the internal + // statuses are the same contiguous sequence starting at zero. + response.Status = waverpc.ArkChannelOORPreparationStatus( + int32(lookup.Status) + 1, + ) + + return response, nil +} + +// ValidatePreparedArkChannelOOR verifies a daemon-owned prepared session. +func (r *RPCServer) ValidatePreparedArkChannelOOR(ctx context.Context, + req *waverpc.ValidatePreparedArkChannelOORRequest) ( + *waverpc.ValidatePreparedArkChannelOORResponse, error) { + + terms, binding, err := r.channelOORRequest( + req.GetTerms(), req.GetBinding(), + ) + if err != nil { + return nil, err + } + controller, err := oorbridge.New(r.server.actorSystem) + if err != nil { + return nil, err + } + if err := controller.ValidatePreparedOOR( + ctx, terms, binding, + ); err != nil { + return nil, err + } + + return &waverpc.ValidatePreparedArkChannelOORResponse{Valid: true}, nil +} + +// CommitPreparedArkChannelOOR releases a prepared daemon OOR and waits for +// its durable finalization. +func (r *RPCServer) CommitPreparedArkChannelOOR(ctx context.Context, + req *waverpc.CommitPreparedArkChannelOORRequest) ( + *waverpc.CommitPreparedArkChannelOORResponse, error) { + + id, terms, binding, err := r.channelOORControlRequest( + req.GetChannelId(), req.GetTerms(), req.GetBinding(), + ) + if err != nil { + return nil, err + } + controller, err := oorbridge.New(r.server.actorSystem) + if err != nil { + return nil, err + } + result, err := controller.CommitPreparedOORResult( + ctx, id, terms, binding, + ) + if err != nil { + return nil, err + } + if err := result.Validate(); err != nil { + return nil, err + } + + return &waverpc.CommitPreparedArkChannelOORResponse{ + Finalized: result.Finalized, + Aborted: result.Aborted, + Reason: result.Reason, + }, nil +} + +// AbortPreparedArkChannelOOR releases a prepared daemon OOR before PONR. +func (r *RPCServer) AbortPreparedArkChannelOOR(ctx context.Context, + req *waverpc.AbortPreparedArkChannelOORRequest) ( + *waverpc.AbortPreparedArkChannelOORResponse, error) { + + if req.GetReason() == "" { + return nil, fmt.Errorf("channel OOR abort reason is required") + } + id, terms, binding, err := r.channelOORControlRequest( + req.GetChannelId(), req.GetTerms(), req.GetBinding(), + ) + if err != nil { + return nil, err + } + controller, err := oorbridge.New(r.server.actorSystem) + if err != nil { + return nil, err + } + result, err := controller.AbortPreparedOORResult( + ctx, id, terms, binding, req.GetReason(), + ) + if err != nil { + return nil, err + } + if err := result.Validate(); err != nil { + return nil, err + } + + return &waverpc.AbortPreparedArkChannelOORResponse{ + Aborted: result.Aborted, Reason: result.Reason, + Finalized: result.Finalized, + }, nil +} + +// channelOORRequest parses one immutable terms and binding pair. +func (r *RPCServer) channelOORRequest(termsRPC *arkchannelrpc.ChannelTerms, + bindingRPC *arkchannelrpc.ChannelVTXOBinding) (arkchannel.Terms, + arkchannel.VTXOBinding, error) { + + terms, err := lnruntime.ChannelTermsFromRPC(termsRPC) + if err != nil { + return arkchannel.Terms{}, arkchannel.VTXOBinding{}, err + } + binding, err := lnruntime.ChannelBindingFromRPC(bindingRPC) + if err != nil { + return arkchannel.Terms{}, arkchannel.VTXOBinding{}, err + } + if terms.Funder != arkchannel.PartyHub { + return arkchannel.Terms{}, arkchannel.VTXOBinding{}, + fmt.Errorf("daemon does not fund this channel") + } + if err := binding.Validate(terms); err != nil { + return arkchannel.Terms{}, arkchannel.VTXOBinding{}, err + } + + return terms, binding, nil +} + +// channelOORControlRequest additionally binds the request channel ID. +func (r *RPCServer) channelOORControlRequest(rawID []byte, + termsRPC *arkchannelrpc.ChannelTerms, + bindingRPC *arkchannelrpc.ChannelVTXOBinding) (arkchannel.ID, + arkchannel.Terms, arkchannel.VTXOBinding, error) { + + terms, binding, err := r.channelOORRequest(termsRPC, bindingRPC) + if err != nil { + return arkchannel.ID{}, arkchannel.Terms{}, + arkchannel.VTXOBinding{}, err + } + if len(rawID) != len(terms.ID) { + return arkchannel.ID{}, arkchannel.Terms{}, + arkchannel.VTXOBinding{}, fmt.Errorf("channel ID " + + "must be 32 bytes") + } + var id arkchannel.ID + copy(id[:], rawID) + if id != terms.ID { + return arkchannel.ID{}, arkchannel.Terms{}, + arkchannel.VTXOBinding{}, fmt.Errorf("channel ID " + + "changed") + } + + return id, terms, binding, nil +} diff --git a/waved/rpc_ark_channel_recovery.go b/waved/rpc_ark_channel_recovery.go new file mode 100644 index 000000000..db60df637 --- /dev/null +++ b/waved/rpc_ark_channel_recovery.go @@ -0,0 +1,51 @@ +package waved + +import ( + "context" + "fmt" + + "github.com/lightninglabs/wavelength/lnruntime" + "github.com/lightninglabs/wavelength/waverpc" +) + +// ExportOORRecoveryPackage returns the immutable local lineage for one exact +// output created by this daemon. It does not install ownership or watches. +func (r *RPCServer) ExportOORRecoveryPackage(ctx context.Context, + req *waverpc.ExportOORRecoveryPackageRequest) ( + *waverpc.ExportOORRecoveryPackageResponse, error) { + + if r == nil || r.server == nil || r.server.vtxoStore == nil { + return nil, fmt.Errorf("OOR recovery exporter is unavailable") + } + source, err := lnruntime.OORRecoverySourceFromRPC( + req.GetSource(), + ) + if err != nil { + return nil, err + } + packages := r.newLocalOORArtifactStore() + if packages == nil { + return nil, fmt.Errorf("OOR artifact store is unavailable") + } + terms, err := r.server.fetchOperatorTerms(ctx) + if err != nil { + return nil, fmt.Errorf("fetch Ark operator terms: %w", err) + } + exporter := &arkChannelRecoveryArchive{ + vtxos: r.server.vtxoStore, packages: packages, + } + recovery, err := exporter.ExportOORRecoveryPackage( + ctx, source, terms.PubKey, + ) + if err != nil { + return nil, err + } + message, err := lnruntime.ChannelRecoveryToRPC(recovery) + if err != nil { + return nil, err + } + + return &waverpc.ExportOORRecoveryPackageResponse{ + Recovery: message, + }, nil +} diff --git a/waved/rpc_auth.go b/waved/rpc_auth.go index f1c66083c..22573e2d6 100644 --- a/waved/rpc_auth.go +++ b/waved/rpc_auth.go @@ -3,6 +3,7 @@ package waved import ( "fmt" + "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" "github.com/lightninglabs/wavelength/rpc/swapclientrpc" "github.com/lightninglabs/wavelength/rpc/wavewalletrpc" "github.com/lightninglabs/wavelength/waverpc" @@ -54,6 +55,9 @@ const ( // entityActivity covers the unified ledger, transaction history, and // activity inspection. entityActivity = "activity" + + // entityChannel covers the lifecycle of Ark-backed Lightning channels. + entityChannel = "channel" ) // wavedEntities is the full set of logical macaroon entities. The read-only @@ -70,6 +74,7 @@ var wavedEntities = []string{ entityRecovery, entityFees, entityActivity, + entityChannel, } var wavedRPCPermissions = newWavedRPCPermissions() @@ -122,12 +127,20 @@ func newWavedRPCPermissions() map[string][]bakery.Op { ) grant( daemon, entityOOR, "read", "GetIndexedOORSessionByTxid", - "ListOORSessions", "GetOORSession", + "ListOORSessions", "GetOORSession", "ExportOORRecoveryPackage", ) grant( daemon, entityOOR, "write", "SendOOR", "PrepareOOR", "SignOORCustomInput", ) + grant( + daemon, entityChannel, "read", "LookupPreparedArkChannelOOR", + ) + grant( + daemon, entityChannel, "write", "PrepareArkChannelOOR", + "ValidatePreparedArkChannelOOR", "CommitPreparedArkChannelOOR", + "AbortPreparedArkChannelOOR", + ) grant( daemon, entityOnChain, "read", "ListBoardingSweeps", "GetUnrollStatus", @@ -158,6 +171,14 @@ func newWavedRPCPermissions() map[string][]bakery.Op { "EscalateVHTLCRecovery", "CancelVHTLCRecovery", ) + arkChannel := arkchannelrpc.ArkChannelService_ServiceDesc.ServiceName + grant(arkChannel, entityChannel, "read", "GetChannel") + grant( + arkChannel, entityChannel, "write", "PromoteVTXO", + "SendPayment", "ReceivePayment", "PayLightningInvoice", + "MaterializeAndForceClose", "RequestCooperativeClose", + ) + swap := swapclientrpc.SwapClientService_ServiceDesc.ServiceName grant( swap, entitySwap, "read", "QuotePay", "ListSwaps", "GetSwap", diff --git a/waved/rpc_auth_test.go b/waved/rpc_auth_test.go index ffb6d8583..d693e118a 100644 --- a/waved/rpc_auth_test.go +++ b/waved/rpc_auth_test.go @@ -5,6 +5,7 @@ import ( btcrpcserver "github.com/btcsuite/btcwallet/rpc/rpcserver" btcwalletrpc "github.com/btcsuite/btcwallet/rpc/walletrpc" + "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" "github.com/lightninglabs/wavelength/rpc/swapclientrpc" "github.com/lightninglabs/wavelength/rpc/wavewalletrpc" "github.com/lightninglabs/wavelength/waverpc" @@ -53,6 +54,8 @@ func TestWavedRPCPermissionsMapsMutatingMethods(t *testing.T) { waverpc.DaemonService_RefreshVTXOs_FullMethodName, waverpc.DaemonService_SignReceiveAuthMessage_FullMethodName, waverpc.DaemonService_SignOutSwapHtlcAck_FullMethodName, + arkchannelrpc. + ArkChannelService_PayLightningInvoice_FullMethodName, fullDaemonMethod("SubmitForfeitParticipantSignatures"), } { ops, ok := wavedRPCPermissions[fullMethod] diff --git a/waved/rpc_oor_receive.go b/waved/rpc_oor_receive.go index bba553552..8f8967221 100644 --- a/waved/rpc_oor_receive.go +++ b/waved/rpc_oor_receive.go @@ -17,6 +17,7 @@ import ( mailboxrpc "github.com/lightninglabs/wavelength/mailbox/rpc" "github.com/lightninglabs/wavelength/waverpc" fn "github.com/lightningnetwork/lnd/fn/v2" + "github.com/lightningnetwork/lnd/keychain" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -41,8 +42,9 @@ type receiveScriptRegistrationCompleter interface { registrationRPCKey string) error } -// NewReceiveScript allocates and registers a taproot receive script, or returns -// the exact existing allocation for an idempotent retry. +// NewReceiveScript registers a wallet-owned taproot receive script. Callers can +// request either a retry-safe fresh key or the daemon's durable identity key +// for a protocol destination that must survive independent process restarts. func (r *RPCServer) NewReceiveScript(ctx context.Context, req *waverpc.NewReceiveScriptRequest) ( *waverpc.NewReceiveScriptResponse, error) { @@ -60,6 +62,13 @@ func (r *RPCServer) NewReceiveScript(ctx context.Context, label = defaultOORReceiveScriptLabel } + if req.IdempotencyKey != "" && req.GetIdentityKey() { + return nil, status.Error( + codes.InvalidArgument, + "idempotency_key and identity_key cannot be combined", + ) + } + if req.IdempotencyKey != "" { if len(req.IdempotencyKey) > db.MaxOwnedReceiveScriptIdempotencyKeyBytes { @@ -123,13 +132,29 @@ func (r *RPCServer) NewReceiveScript(ctx context.Context, "initialize OOR receive key ops: %v", err) } - expiresAt := r.server.clk.Now().Add( - defaultOORRegistrationTTL, - ) - keyDesc, pkScript, err := CreateOORReceiveScriptWithExpiry( - ctx, r.server.indexer, store, deriveNextKey, signerFactory, - terms.PubKey, terms.VTXOExitDelay, label, expiresAt, - ) + expiresAt := r.server.clk.Now().Add(defaultOORRegistrationTTL) + var keyDesc *keychain.KeyDescriptor + var pkScript []byte + if req.GetIdentityKey() { + identityKey := r.server.clientKeyDesc + if identityKey.PubKey == nil { + return nil, status.Errorf(codes.Internal, "missing "+ + "daemon identity key") + } + + pkScript, err = RegisterOwnedOORReceiveScriptWithExpiry( + ctx, r.server.indexer, store, identityKey, + signerFactory, terms.PubKey, terms.VTXOExitDelay, label, + expiresAt, + ) + keyDesc = &identityKey + } else { + keyDesc, pkScript, err = CreateOORReceiveScriptWithExpiry( + ctx, r.server.indexer, store, deriveNextKey, + signerFactory, terms.PubKey, terms.VTXOExitDelay, label, + expiresAt, + ) + } if err != nil { return nil, status.Errorf(codes.Internal, "unable to create "+ "OOR receive script: %v", err) diff --git a/waved/server.go b/waved/server.go index 35791016f..274b321d5 100644 --- a/waved/server.go +++ b/waved/server.go @@ -27,6 +27,7 @@ import ( btcwalletpkg "github.com/btcsuite/btcwallet/wallet" "github.com/btcsuite/btcwallet/wtxmgr" "github.com/lightninglabs/lndclient" + "github.com/lightninglabs/wavelength/arkchannel/unrollbridge" "github.com/lightninglabs/wavelength/arkrpc" "github.com/lightninglabs/wavelength/baselib/actor" "github.com/lightninglabs/wavelength/btcwbackend" @@ -45,6 +46,7 @@ import ( "github.com/lightninglabs/wavelength/lib/recovery" "github.com/lightninglabs/wavelength/lib/types" "github.com/lightninglabs/wavelength/lndbackend" + "github.com/lightninglabs/wavelength/lnruntime" "github.com/lightninglabs/wavelength/lwwallet" mailboxpb "github.com/lightninglabs/wavelength/mailbox/pb" mailboxrpc "github.com/lightninglabs/wavelength/mailbox/rpc" @@ -52,6 +54,7 @@ import ( "github.com/lightninglabs/wavelength/oor" "github.com/lightninglabs/wavelength/proofkeys" "github.com/lightninglabs/wavelength/round" + "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" "github.com/lightninglabs/wavelength/rpc/oorpb" "github.com/lightninglabs/wavelength/rpc/roundpb" "github.com/lightninglabs/wavelength/rpcauth" @@ -363,11 +366,17 @@ type Server struct { walletRef fn.Option[actor.ActorRef[ wallet.WalletMsg, wallet.WalletResp, ]] - oorRegistry *oor.OORRegistryActor - creditRegistry *credit.Registry - vhtlcRecoveryStore *db.VHTLCRecoveryStoreDB - vhtlcRecovery *coordinator.Service - vhtlcPreimages *unrollpolicy.PreimageResolverRegistry + oorRegistry *oor.OORRegistryActor + creditRegistry *credit.Registry + vhtlcRecoveryStore *db.VHTLCRecoveryStoreDB + arkChannelStore *db.ArkChannelStoreDB + arkChannelMu sync.RWMutex + arkChannelController ArkChannelController + arkChannelMailboxRuntime *serverconn.Runtime + arkChannelPeerIngress *lnruntime.PeerMessageIngress + vhtlcRecovery *coordinator.Service + vhtlcRecoveryTarget *vhtlcRecoveryTargetMaterializer + vhtlcPreimages *unrollpolicy.PreimageResolverRegistry // ledgerStore exposes the client-side ledger DB adapter for // read-only RPC handlers (GetFeeHistory). Writes go through @@ -1281,13 +1290,44 @@ func (s *Server) runInner(ctx context.Context, shutdownFn func()) error { if s.outboxPublisher != nil { s.outboxPublisher.Stop() } + if ingress := s.getArkChannelPeerIngress(); ingress != nil { + //nolint:contextcheck // bounded shutdown + if err := ingress.StopAndWait(shutdownCtx); err != nil { + s.log.WarnS( + ctx, + "Ark channel peer ingress shutdown "+ + "failed", + err, + ) + } + } + + controller := s.getArkChannelController() + if controller != nil { + if err := controller.Stop(); err != nil { + s.log.WarnS( + ctx, + "Ark channel runtime shutdown failed", + err, + ) + } + } + if runtime := s.getArkChannelMailboxRuntime(); runtime != nil { + //nolint:contextcheck // bounded shutdown + if err := runtime.StopAndWait(shutdownCtx); err != nil { + s.log.WarnS( + ctx, + "Ark channel mailbox shutdown failed", + err, + ) + } + } if s.runtime != nil { s.setServerConnected(false) //nolint:contextcheck // bounded shutdown _ = s.runtime.StopAndWait(shutdownCtx) } - if s.actorSystem != nil { //nolint:contextcheck // bounded shutdown err := s.actorSystem.Shutdown(shutdownCtx) @@ -1451,6 +1491,11 @@ func (s *Server) runInner(ctx context.Context, shutdownFn func()) error { waverpc.RegisterDaemonServiceServer( s.grpcServer, s.rpcServer, ) + arkchannelrpc.RegisterArkChannelServiceServer( + s.grpcServer, &arkChannelRPCServer{ + server: s, + }, + ) if cleanup := registerBtcwalletRPC(s.grpcServer, s); cleanup != nil { defer cleanup() } @@ -1474,6 +1519,20 @@ func (s *Server) runInner(ctx context.Context, shutdownFn func()) error { defer cleanup() } } + // The Ark channel runtime borrows the swap registrar's mailbox + // transport. Register this defer after registrar cleanup defers so it + // runs first. + //nolint:contextcheck // Shutdown requires a fresh bounded context. + defer func() { + if runtime := s.getArkChannelMailboxRuntime(); runtime != nil { + shutdownCtx, cancel := context.WithTimeout( + context.Background(), DefaultShutdownTimeout, + ) + defer cancel() + + _ = runtime.StopAndWait(shutdownCtx) + } + }() if authService != nil { if _, err := registeredRPCPermissions( s.grpcServer, @@ -1683,6 +1742,17 @@ func (s *Server) startWalletReadyServices(ctx context.Context, return refreshErr } + closeRegistrationCtx, closeRegistrationCancel := context.WithTimeout( + ctx, operatorTermsRefreshTimeout, + ) + closeRegistrationErr := s.ensureConfiguredArkChannelCloseDelivery( + closeRegistrationCtx, + ) + closeRegistrationCancel() + if closeRegistrationErr != nil { + return closeRegistrationErr + } + if err := s.replayPendingIntents( ctx, s.walletRef.UnsafeFromSome(), ); err != nil { @@ -2691,6 +2761,13 @@ func (s *Server) startWalletDependentActors(ctx context.Context, return err } + // The channel controller is last because it requires the durable + // channel store, swap-server mailbox, and all wallet-owned native + // dependencies. + if err := s.initArkChannelProcess(ctx); err != nil { + return err + } + s.log.InfoS(ctx, "Wallet-dependent actors started") return nil @@ -5765,6 +5842,8 @@ func (s *Server) initUnrollSubsystem(ctx context.Context, s.ueStore = ueStore recoveryStore := dbStore.NewVHTLCRecoveryStore(s.clk) s.vhtlcRecoveryStore = recoveryStore + channelStore := dbStore.NewArkChannelStore(s.clk) + s.arkChannelStore = channelStore preimages := s.vhtlcPreimages vtxoStore := dbStore.NewVTXOStore(s.clk) @@ -5859,9 +5938,12 @@ func (s *Server) initUnrollSubsystem(ctx context.Context, ), Log: fn.Some(s.subLogger("UNRL")), MaxSweepFeeRateSatPerVByte: s.unrollMaxFeeRate(), - ExitSpendPolicyResolver: unrollpolicy.ExitSpendPolicyResolver{ - Jobs: recoveryStore, - Preimage: preimages, + ExitSpendPolicyResolver: unroll.PolicyResolvers{ + unrollpolicy.ExitSpendPolicyResolver{ + Jobs: recoveryStore, + Preimage: preimages, + }, + unrollbridge.Resolver{Channels: channelStore}, }, VTXOExitObserver: exitObserver, }) @@ -5872,22 +5954,25 @@ func (s *Server) initUnrollSubsystem(ctx context.Context, return fmt.Errorf("VTXO manager not initialized for vhtlc " + "recovery") } + recoveryTarget := newVHTLCRecoveryTargetMaterializer( + vtxoStore, oorStore, s.subLogger(VHTLCRecoverySubsystem), + ) recoverySvc, err := coordinator.NewService(coordinator.ServiceConfig{ Store: recoveryStore, Unroll: coordinator.NewActorUnrollRegistry(registry.Ref()), Exiter: managerExitAdmitter{ mgr: s.vtxoMgrRef.UnsafeFromSome(), }, - Log: fn.Some(s.subLogger(VHTLCRecoverySubsystem)), - TargetMaterializer: newVHTLCRecoveryTargetMaterializer( - vtxoStore, oorStore, + Log: fn.Some( s.subLogger(VHTLCRecoverySubsystem), ), + TargetMaterializer: recoveryTarget, }) if err != nil { return err } s.vhtlcRecovery = recoverySvc + s.vhtlcRecoveryTarget = recoveryTarget err = s.initFraudWatcher(ctx, chainSourceRef) if err != nil { diff --git a/waved/vhtlc_recovery_target.go b/waved/vhtlc_recovery_target.go index 42b742965..a48365898 100644 --- a/waved/vhtlc_recovery_target.go +++ b/waved/vhtlc_recovery_target.go @@ -221,6 +221,10 @@ func (m *vhtlcRecoveryTargetMaterializer) buildRecoveryDescriptor( } chainDepth := recoveryChainDepth(roots, 1) + constructionVersion, err := recoveryConstructionVersion(roots) + if err != nil { + return nil, err + } return &vtxo.Descriptor{ Outpoint: target, @@ -233,16 +237,17 @@ func (m *vhtlcRecoveryTargetMaterializer) buildRecoveryDescriptor( }, PubKey: signingKey, }, - OperatorKey: operatorKey, - Ancestry: ancestry, - RoundID: roundID, - CommitmentTxID: commitmentTxID, - BatchExpiry: batchExpiry, - RelativeExpiry: csvDelay, - PolicyTemplate: policyTemplate, - ChainDepth: chainDepth, - CreatedHeight: createdHeight, - Status: vtxo.VTXOStatusSpending, + OperatorKey: operatorKey, + Ancestry: ancestry, + RoundID: roundID, + CommitmentTxID: commitmentTxID, + BatchExpiry: batchExpiry, + RelativeExpiry: csvDelay, + PolicyTemplate: policyTemplate, + ChainDepth: chainDepth, + CreatedHeight: createdHeight, + Status: vtxo.VTXOStatusSpending, + ConstructionVersion: constructionVersion, }, nil } diff --git a/waverpc/daemon.pb.go b/waverpc/daemon.pb.go index 91ae393c6..ddcb110f2 100644 --- a/waverpc/daemon.pb.go +++ b/waverpc/daemon.pb.go @@ -7,6 +7,7 @@ package waverpc import ( + arkchannelrpc "github.com/lightninglabs/wavelength/rpc/arkchannelrpc" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -260,6 +261,61 @@ func (VTXOExpiryStatus) EnumDescriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{2} } +type ArkChannelOORPreparationStatus int32 + +const ( + ArkChannelOORPreparationStatus_ARK_CHANNEL_OOR_PREPARATION_STATUS_UNSPECIFIED ArkChannelOORPreparationStatus = 0 + ArkChannelOORPreparationStatus_ARK_CHANNEL_OOR_PREPARATION_STATUS_ABSENT ArkChannelOORPreparationStatus = 1 + ArkChannelOORPreparationStatus_ARK_CHANNEL_OOR_PREPARATION_STATUS_PENDING ArkChannelOORPreparationStatus = 2 + ArkChannelOORPreparationStatus_ARK_CHANNEL_OOR_PREPARATION_STATUS_PREPARED ArkChannelOORPreparationStatus = 3 + ArkChannelOORPreparationStatus_ARK_CHANNEL_OOR_PREPARATION_STATUS_ACCEPTED ArkChannelOORPreparationStatus = 4 +) + +// Enum value maps for ArkChannelOORPreparationStatus. +var ( + ArkChannelOORPreparationStatus_name = map[int32]string{ + 0: "ARK_CHANNEL_OOR_PREPARATION_STATUS_UNSPECIFIED", + 1: "ARK_CHANNEL_OOR_PREPARATION_STATUS_ABSENT", + 2: "ARK_CHANNEL_OOR_PREPARATION_STATUS_PENDING", + 3: "ARK_CHANNEL_OOR_PREPARATION_STATUS_PREPARED", + 4: "ARK_CHANNEL_OOR_PREPARATION_STATUS_ACCEPTED", + } + ArkChannelOORPreparationStatus_value = map[string]int32{ + "ARK_CHANNEL_OOR_PREPARATION_STATUS_UNSPECIFIED": 0, + "ARK_CHANNEL_OOR_PREPARATION_STATUS_ABSENT": 1, + "ARK_CHANNEL_OOR_PREPARATION_STATUS_PENDING": 2, + "ARK_CHANNEL_OOR_PREPARATION_STATUS_PREPARED": 3, + "ARK_CHANNEL_OOR_PREPARATION_STATUS_ACCEPTED": 4, + } +) + +func (x ArkChannelOORPreparationStatus) Enum() *ArkChannelOORPreparationStatus { + p := new(ArkChannelOORPreparationStatus) + *p = x + return p +} + +func (x ArkChannelOORPreparationStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ArkChannelOORPreparationStatus) Descriptor() protoreflect.EnumDescriptor { + return file_daemon_proto_enumTypes[3].Descriptor() +} + +func (ArkChannelOORPreparationStatus) Type() protoreflect.EnumType { + return &file_daemon_proto_enumTypes[3] +} + +func (x ArkChannelOORPreparationStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ArkChannelOORPreparationStatus.Descriptor instead. +func (ArkChannelOORPreparationStatus) EnumDescriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{3} +} + // ForfeitSigningRoute tells the daemon how to resolve a later // connector-bound participant signature request for a custom VTXO refresh. // @@ -330,11 +386,11 @@ func (x ForfeitSigningRoute) String() string { } func (ForfeitSigningRoute) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[3].Descriptor() + return file_daemon_proto_enumTypes[4].Descriptor() } func (ForfeitSigningRoute) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[3] + return &file_daemon_proto_enumTypes[4] } func (x ForfeitSigningRoute) Number() protoreflect.EnumNumber { @@ -343,7 +399,7 @@ func (x ForfeitSigningRoute) Number() protoreflect.EnumNumber { // Deprecated: Use ForfeitSigningRoute.Descriptor instead. func (ForfeitSigningRoute) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{3} + return file_daemon_proto_rawDescGZIP(), []int{4} } // RoundState represents the lifecycle state of a client's round FSM. @@ -451,11 +507,11 @@ func (x RoundState) String() string { } func (RoundState) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[4].Descriptor() + return file_daemon_proto_enumTypes[5].Descriptor() } func (RoundState) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[4] + return &file_daemon_proto_enumTypes[5] } func (x RoundState) Number() protoreflect.EnumNumber { @@ -464,7 +520,7 @@ func (x RoundState) Number() protoreflect.EnumNumber { // Deprecated: Use RoundState.Descriptor instead. func (RoundState) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{4} + return file_daemon_proto_rawDescGZIP(), []int{5} } type OORSessionDirection int32 @@ -500,11 +556,11 @@ func (x OORSessionDirection) String() string { } func (OORSessionDirection) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[5].Descriptor() + return file_daemon_proto_enumTypes[6].Descriptor() } func (OORSessionDirection) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[5] + return &file_daemon_proto_enumTypes[6] } func (x OORSessionDirection) Number() protoreflect.EnumNumber { @@ -513,7 +569,7 @@ func (x OORSessionDirection) Number() protoreflect.EnumNumber { // Deprecated: Use OORSessionDirection.Descriptor instead. func (OORSessionDirection) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{5} + return file_daemon_proto_rawDescGZIP(), []int{6} } type OORSessionStatus int32 @@ -552,11 +608,11 @@ func (x OORSessionStatus) String() string { } func (OORSessionStatus) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[6].Descriptor() + return file_daemon_proto_enumTypes[7].Descriptor() } func (OORSessionStatus) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[6] + return &file_daemon_proto_enumTypes[7] } func (x OORSessionStatus) Number() protoreflect.EnumNumber { @@ -565,7 +621,7 @@ func (x OORSessionStatus) Number() protoreflect.EnumNumber { // Deprecated: Use OORSessionStatus.Descriptor instead. func (OORSessionStatus) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{6} + return file_daemon_proto_rawDescGZIP(), []int{7} } // UnrollJobStatus represents the high-level phase of an unroll job. @@ -626,11 +682,11 @@ func (x UnrollJobStatus) String() string { } func (UnrollJobStatus) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[7].Descriptor() + return file_daemon_proto_enumTypes[8].Descriptor() } func (UnrollJobStatus) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[7] + return &file_daemon_proto_enumTypes[8] } func (x UnrollJobStatus) Number() protoreflect.EnumNumber { @@ -639,7 +695,7 @@ func (x UnrollJobStatus) Number() protoreflect.EnumNumber { // Deprecated: Use UnrollJobStatus.Descriptor instead. func (UnrollJobStatus) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{7} + return file_daemon_proto_rawDescGZIP(), []int{8} } // VHTLCRecoveryDirection records which side owns a recovery job. @@ -689,11 +745,11 @@ func (x VHTLCRecoveryDirection) String() string { } func (VHTLCRecoveryDirection) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[8].Descriptor() + return file_daemon_proto_enumTypes[9].Descriptor() } func (VHTLCRecoveryDirection) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[8] + return &file_daemon_proto_enumTypes[9] } func (x VHTLCRecoveryDirection) Number() protoreflect.EnumNumber { @@ -702,7 +758,7 @@ func (x VHTLCRecoveryDirection) Number() protoreflect.EnumNumber { // Deprecated: Use VHTLCRecoveryDirection.Descriptor instead. func (VHTLCRecoveryDirection) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{8} + return file_daemon_proto_rawDescGZIP(), []int{9} } // VHTLCRecoveryAction selects the unilateral vHTLC leaf to execute. @@ -743,11 +799,11 @@ func (x VHTLCRecoveryAction) String() string { } func (VHTLCRecoveryAction) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[9].Descriptor() + return file_daemon_proto_enumTypes[10].Descriptor() } func (VHTLCRecoveryAction) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[9] + return &file_daemon_proto_enumTypes[10] } func (x VHTLCRecoveryAction) Number() protoreflect.EnumNumber { @@ -756,7 +812,7 @@ func (x VHTLCRecoveryAction) Number() protoreflect.EnumNumber { // Deprecated: Use VHTLCRecoveryAction.Descriptor instead. func (VHTLCRecoveryAction) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{9} + return file_daemon_proto_rawDescGZIP(), []int{10} } // VHTLCRecoveryState mirrors the durable vhtlc_recovery_jobs state column. The @@ -824,11 +880,11 @@ func (x VHTLCRecoveryState) String() string { } func (VHTLCRecoveryState) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[10].Descriptor() + return file_daemon_proto_enumTypes[11].Descriptor() } func (VHTLCRecoveryState) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[10] + return &file_daemon_proto_enumTypes[11] } func (x VHTLCRecoveryState) Number() protoreflect.EnumNumber { @@ -837,7 +893,7 @@ func (x VHTLCRecoveryState) Number() protoreflect.EnumNumber { // Deprecated: Use VHTLCRecoveryState.Descriptor instead. func (VHTLCRecoveryState) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{10} + return file_daemon_proto_rawDescGZIP(), []int{11} } type GetInfoRequest struct { @@ -2349,8 +2405,12 @@ type NewReceiveScriptRequest struct { // prefix keys with an application or tenant identity when they share one // daemon. IdempotencyKey string `protobuf:"bytes,2,opt,name=idempotency_key,json=idempotencyKey,proto3" json:"idempotency_key,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // identity_key registers the daemon's durable identity key instead of + // deriving a fresh receive key. This is reserved for restart-stable + // protocol destinations such as Ark channel cooperative-close payouts. + IdentityKey bool `protobuf:"varint,3,opt,name=identity_key,json=identityKey,proto3" json:"identity_key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *NewReceiveScriptRequest) Reset() { @@ -2397,6 +2457,13 @@ func (x *NewReceiveScriptRequest) GetIdempotencyKey() string { return "" } +func (x *NewReceiveScriptRequest) GetIdentityKey() bool { + if x != nil { + return x.IdentityKey + } + return false +} + type NewReceiveScriptResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // pk_script_hex is the raw taproot output script encoded as hex. @@ -4105,30 +4172,29 @@ func (x *PrepareOORResponse) GetSessionId() string { return "" } -type SignOORCustomInputRequest struct { +type ExportOORRecoveryPackageRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // custom_input describes the vHTLC/custom VTXO and selected spend path. - CustomInput *CustomOORInput `protobuf:"bytes,1,opt,name=custom_input,json=customInput,proto3" json:"custom_input,omitempty"` - // checkpoint_psbt is the prepared checkpoint PSBT to sign. - CheckpointPsbt []byte `protobuf:"bytes,2,opt,name=checkpoint_psbt,json=checkpointPsbt,proto3" json:"checkpoint_psbt,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // source identifies one exact output in a sender-owned finalized OOR + // package. + Source *arkchannelrpc.OORRecoverySource `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SignOORCustomInputRequest) Reset() { - *x = SignOORCustomInputRequest{} +func (x *ExportOORRecoveryPackageRequest) Reset() { + *x = ExportOORRecoveryPackageRequest{} mi := &file_daemon_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SignOORCustomInputRequest) String() string { +func (x *ExportOORRecoveryPackageRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SignOORCustomInputRequest) ProtoMessage() {} +func (*ExportOORRecoveryPackageRequest) ProtoMessage() {} -func (x *SignOORCustomInputRequest) ProtoReflect() protoreflect.Message { +func (x *ExportOORRecoveryPackageRequest) ProtoReflect() protoreflect.Message { mi := &file_daemon_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4140,47 +4206,40 @@ func (x *SignOORCustomInputRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SignOORCustomInputRequest.ProtoReflect.Descriptor instead. -func (*SignOORCustomInputRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ExportOORRecoveryPackageRequest.ProtoReflect.Descriptor instead. +func (*ExportOORRecoveryPackageRequest) Descriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{44} } -func (x *SignOORCustomInputRequest) GetCustomInput() *CustomOORInput { - if x != nil { - return x.CustomInput - } - return nil -} - -func (x *SignOORCustomInputRequest) GetCheckpointPsbt() []byte { +func (x *ExportOORRecoveryPackageRequest) GetSource() *arkchannelrpc.OORRecoverySource { if x != nil { - return x.CheckpointPsbt + return x.Source } return nil } -type SignOORCustomInputResponse struct { +type ExportOORRecoveryPackageResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - // signature is the daemon identity key's tapscript signature. - Signature *TaprootScriptSignature `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + // recovery contains the complete endpoint-neutral source lineage. + Recovery *arkchannelrpc.ChannelRecoveryPackage `protobuf:"bytes,1,opt,name=recovery,proto3" json:"recovery,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SignOORCustomInputResponse) Reset() { - *x = SignOORCustomInputResponse{} +func (x *ExportOORRecoveryPackageResponse) Reset() { + *x = ExportOORRecoveryPackageResponse{} mi := &file_daemon_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SignOORCustomInputResponse) String() string { +func (x *ExportOORRecoveryPackageResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SignOORCustomInputResponse) ProtoMessage() {} +func (*ExportOORRecoveryPackageResponse) ProtoMessage() {} -func (x *SignOORCustomInputResponse) ProtoReflect() protoreflect.Message { +func (x *ExportOORRecoveryPackageResponse) ProtoReflect() protoreflect.Message { mi := &file_daemon_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4192,61 +4251,39 @@ func (x *SignOORCustomInputResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SignOORCustomInputResponse.ProtoReflect.Descriptor instead. -func (*SignOORCustomInputResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use ExportOORRecoveryPackageResponse.ProtoReflect.Descriptor instead. +func (*ExportOORRecoveryPackageResponse) Descriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{45} } -func (x *SignOORCustomInputResponse) GetSignature() *TaprootScriptSignature { +func (x *ExportOORRecoveryPackageResponse) GetRecovery() *arkchannelrpc.ChannelRecoveryPackage { if x != nil { - return x.Signature + return x.Recovery } return nil } -type SignVTXOForfeitRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - // vtxo_outpoint identifies the VTXO input at forfeit tx input index 0. - VtxoOutpoint string `protobuf:"bytes,1,opt,name=vtxo_outpoint,json=vtxoOutpoint,proto3" json:"vtxo_outpoint,omitempty"` - // vtxo_amount_sat is the value of the VTXO output being spent. - VtxoAmountSat int64 `protobuf:"varint,2,opt,name=vtxo_amount_sat,json=vtxoAmountSat,proto3" json:"vtxo_amount_sat,omitempty"` - // vtxo_pk_script is the taproot output script of the VTXO being spent. - VtxoPkScript []byte `protobuf:"bytes,3,opt,name=vtxo_pk_script,json=vtxoPkScript,proto3" json:"vtxo_pk_script,omitempty"` - // vtxo_policy_template is the semantic policy template that produced the - // VTXO taproot output. - VtxoPolicyTemplate []byte `protobuf:"bytes,4,opt,name=vtxo_policy_template,json=vtxoPolicyTemplate,proto3" json:"vtxo_policy_template,omitempty"` - // spend_path is the encoded tapscript path selected for the VTXO input. - SpendPath []byte `protobuf:"bytes,5,opt,name=spend_path,json=spendPath,proto3" json:"spend_path,omitempty"` - // unsigned_forfeit_tx is the exact serialized forfeit transaction to sign. - UnsignedForfeitTx []byte `protobuf:"bytes,6,opt,name=unsigned_forfeit_tx,json=unsignedForfeitTx,proto3" json:"unsigned_forfeit_tx,omitempty"` - // connector_outpoint identifies the connector input at forfeit tx input - // index 1. - ConnectorOutpoint string `protobuf:"bytes,7,opt,name=connector_outpoint,json=connectorOutpoint,proto3" json:"connector_outpoint,omitempty"` - // connector_amount_sat is the value of the connector output being spent. - ConnectorAmountSat int64 `protobuf:"varint,8,opt,name=connector_amount_sat,json=connectorAmountSat,proto3" json:"connector_amount_sat,omitempty"` - // connector_pk_script is the connector output script being spent. - ConnectorPkScript []byte `protobuf:"bytes,9,opt,name=connector_pk_script,json=connectorPkScript,proto3" json:"connector_pk_script,omitempty"` - // server_forfeit_pk_script is the expected penalty output script at output - // index 0. - ServerForfeitPkScript []byte `protobuf:"bytes,10,opt,name=server_forfeit_pk_script,json=serverForfeitPkScript,proto3" json:"server_forfeit_pk_script,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +type PrepareArkChannelOORRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Terms *arkchannelrpc.ChannelTerms `protobuf:"bytes,1,opt,name=terms,proto3" json:"terms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SignVTXOForfeitRequest) Reset() { - *x = SignVTXOForfeitRequest{} +func (x *PrepareArkChannelOORRequest) Reset() { + *x = PrepareArkChannelOORRequest{} mi := &file_daemon_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SignVTXOForfeitRequest) String() string { +func (x *PrepareArkChannelOORRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SignVTXOForfeitRequest) ProtoMessage() {} +func (*PrepareArkChannelOORRequest) ProtoMessage() {} -func (x *SignVTXOForfeitRequest) ProtoReflect() protoreflect.Message { +func (x *PrepareArkChannelOORRequest) ProtoReflect() protoreflect.Message { mi := &file_daemon_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4258,106 +4295,129 @@ func (x *SignVTXOForfeitRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SignVTXOForfeitRequest.ProtoReflect.Descriptor instead. -func (*SignVTXOForfeitRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use PrepareArkChannelOORRequest.ProtoReflect.Descriptor instead. +func (*PrepareArkChannelOORRequest) Descriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{46} } -func (x *SignVTXOForfeitRequest) GetVtxoOutpoint() string { +func (x *PrepareArkChannelOORRequest) GetTerms() *arkchannelrpc.ChannelTerms { if x != nil { - return x.VtxoOutpoint + return x.Terms } - return "" + return nil } -func (x *SignVTXOForfeitRequest) GetVtxoAmountSat() int64 { - if x != nil { - return x.VtxoAmountSat - } - return 0 +type PrepareArkChannelOORResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Binding *arkchannelrpc.ChannelVTXOBinding `protobuf:"bytes,1,opt,name=binding,proto3" json:"binding,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SignVTXOForfeitRequest) GetVtxoPkScript() []byte { - if x != nil { - return x.VtxoPkScript - } - return nil +func (x *PrepareArkChannelOORResponse) Reset() { + *x = PrepareArkChannelOORResponse{} + mi := &file_daemon_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *SignVTXOForfeitRequest) GetVtxoPolicyTemplate() []byte { - if x != nil { - return x.VtxoPolicyTemplate - } - return nil +func (x *PrepareArkChannelOORResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -func (x *SignVTXOForfeitRequest) GetSpendPath() []byte { +func (*PrepareArkChannelOORResponse) ProtoMessage() {} + +func (x *PrepareArkChannelOORResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[47] if x != nil { - return x.SpendPath + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return nil + return mi.MessageOf(x) } -func (x *SignVTXOForfeitRequest) GetUnsignedForfeitTx() []byte { +// Deprecated: Use PrepareArkChannelOORResponse.ProtoReflect.Descriptor instead. +func (*PrepareArkChannelOORResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{47} +} + +func (x *PrepareArkChannelOORResponse) GetBinding() *arkchannelrpc.ChannelVTXOBinding { if x != nil { - return x.UnsignedForfeitTx + return x.Binding } return nil } -func (x *SignVTXOForfeitRequest) GetConnectorOutpoint() string { - if x != nil { - return x.ConnectorOutpoint - } - return "" +type LookupPreparedArkChannelOORRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Terms *arkchannelrpc.ChannelTerms `protobuf:"bytes,1,opt,name=terms,proto3" json:"terms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SignVTXOForfeitRequest) GetConnectorAmountSat() int64 { - if x != nil { - return x.ConnectorAmountSat - } - return 0 +func (x *LookupPreparedArkChannelOORRequest) Reset() { + *x = LookupPreparedArkChannelOORRequest{} + mi := &file_daemon_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *SignVTXOForfeitRequest) GetConnectorPkScript() []byte { +func (x *LookupPreparedArkChannelOORRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LookupPreparedArkChannelOORRequest) ProtoMessage() {} + +func (x *LookupPreparedArkChannelOORRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[48] if x != nil { - return x.ConnectorPkScript + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return nil + return mi.MessageOf(x) } -func (x *SignVTXOForfeitRequest) GetServerForfeitPkScript() []byte { +// Deprecated: Use LookupPreparedArkChannelOORRequest.ProtoReflect.Descriptor instead. +func (*LookupPreparedArkChannelOORRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{48} +} + +func (x *LookupPreparedArkChannelOORRequest) GetTerms() *arkchannelrpc.ChannelTerms { if x != nil { - return x.ServerForfeitPkScript + return x.Terms } return nil } -type SignVTXOForfeitResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - // pubkey is the daemon identity public key that produced signature. - Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` - // signature is the raw 64-byte Schnorr signature for the VTXO input. - Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` +type LookupPreparedArkChannelOORResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Status ArkChannelOORPreparationStatus `protobuf:"varint,1,opt,name=status,proto3,enum=waverpc.ArkChannelOORPreparationStatus" json:"status,omitempty"` + Binding *arkchannelrpc.ChannelVTXOBinding `protobuf:"bytes,2,opt,name=binding,proto3" json:"binding,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SignVTXOForfeitResponse) Reset() { - *x = SignVTXOForfeitResponse{} - mi := &file_daemon_proto_msgTypes[47] +func (x *LookupPreparedArkChannelOORResponse) Reset() { + *x = LookupPreparedArkChannelOORResponse{} + mi := &file_daemon_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SignVTXOForfeitResponse) String() string { +func (x *LookupPreparedArkChannelOORResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SignVTXOForfeitResponse) ProtoMessage() {} +func (*LookupPreparedArkChannelOORResponse) ProtoMessage() {} -func (x *SignVTXOForfeitResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[47] +func (x *LookupPreparedArkChannelOORResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4368,21 +4428,647 @@ func (x *SignVTXOForfeitResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SignVTXOForfeitResponse.ProtoReflect.Descriptor instead. -func (*SignVTXOForfeitResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{47} +// Deprecated: Use LookupPreparedArkChannelOORResponse.ProtoReflect.Descriptor instead. +func (*LookupPreparedArkChannelOORResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{49} } -func (x *SignVTXOForfeitResponse) GetPubkey() []byte { +func (x *LookupPreparedArkChannelOORResponse) GetStatus() ArkChannelOORPreparationStatus { if x != nil { - return x.Pubkey + return x.Status } - return nil + return ArkChannelOORPreparationStatus_ARK_CHANNEL_OOR_PREPARATION_STATUS_UNSPECIFIED } -func (x *SignVTXOForfeitResponse) GetSignature() []byte { +func (x *LookupPreparedArkChannelOORResponse) GetBinding() *arkchannelrpc.ChannelVTXOBinding { if x != nil { - return x.Signature + return x.Binding + } + return nil +} + +type ValidatePreparedArkChannelOORRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Terms *arkchannelrpc.ChannelTerms `protobuf:"bytes,1,opt,name=terms,proto3" json:"terms,omitempty"` + Binding *arkchannelrpc.ChannelVTXOBinding `protobuf:"bytes,2,opt,name=binding,proto3" json:"binding,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidatePreparedArkChannelOORRequest) Reset() { + *x = ValidatePreparedArkChannelOORRequest{} + mi := &file_daemon_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidatePreparedArkChannelOORRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidatePreparedArkChannelOORRequest) ProtoMessage() {} + +func (x *ValidatePreparedArkChannelOORRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[50] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidatePreparedArkChannelOORRequest.ProtoReflect.Descriptor instead. +func (*ValidatePreparedArkChannelOORRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{50} +} + +func (x *ValidatePreparedArkChannelOORRequest) GetTerms() *arkchannelrpc.ChannelTerms { + if x != nil { + return x.Terms + } + return nil +} + +func (x *ValidatePreparedArkChannelOORRequest) GetBinding() *arkchannelrpc.ChannelVTXOBinding { + if x != nil { + return x.Binding + } + return nil +} + +type ValidatePreparedArkChannelOORResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidatePreparedArkChannelOORResponse) Reset() { + *x = ValidatePreparedArkChannelOORResponse{} + mi := &file_daemon_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidatePreparedArkChannelOORResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidatePreparedArkChannelOORResponse) ProtoMessage() {} + +func (x *ValidatePreparedArkChannelOORResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[51] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidatePreparedArkChannelOORResponse.ProtoReflect.Descriptor instead. +func (*ValidatePreparedArkChannelOORResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{51} +} + +func (x *ValidatePreparedArkChannelOORResponse) GetValid() bool { + if x != nil { + return x.Valid + } + return false +} + +type CommitPreparedArkChannelOORRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ChannelId []byte `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + Terms *arkchannelrpc.ChannelTerms `protobuf:"bytes,2,opt,name=terms,proto3" json:"terms,omitempty"` + Binding *arkchannelrpc.ChannelVTXOBinding `protobuf:"bytes,3,opt,name=binding,proto3" json:"binding,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CommitPreparedArkChannelOORRequest) Reset() { + *x = CommitPreparedArkChannelOORRequest{} + mi := &file_daemon_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommitPreparedArkChannelOORRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommitPreparedArkChannelOORRequest) ProtoMessage() {} + +func (x *CommitPreparedArkChannelOORRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[52] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommitPreparedArkChannelOORRequest.ProtoReflect.Descriptor instead. +func (*CommitPreparedArkChannelOORRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{52} +} + +func (x *CommitPreparedArkChannelOORRequest) GetChannelId() []byte { + if x != nil { + return x.ChannelId + } + return nil +} + +func (x *CommitPreparedArkChannelOORRequest) GetTerms() *arkchannelrpc.ChannelTerms { + if x != nil { + return x.Terms + } + return nil +} + +func (x *CommitPreparedArkChannelOORRequest) GetBinding() *arkchannelrpc.ChannelVTXOBinding { + if x != nil { + return x.Binding + } + return nil +} + +type CommitPreparedArkChannelOORResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Finalized bool `protobuf:"varint,1,opt,name=finalized,proto3" json:"finalized,omitempty"` + Aborted bool `protobuf:"varint,2,opt,name=aborted,proto3" json:"aborted,omitempty"` + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CommitPreparedArkChannelOORResponse) Reset() { + *x = CommitPreparedArkChannelOORResponse{} + mi := &file_daemon_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommitPreparedArkChannelOORResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommitPreparedArkChannelOORResponse) ProtoMessage() {} + +func (x *CommitPreparedArkChannelOORResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[53] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommitPreparedArkChannelOORResponse.ProtoReflect.Descriptor instead. +func (*CommitPreparedArkChannelOORResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{53} +} + +func (x *CommitPreparedArkChannelOORResponse) GetFinalized() bool { + if x != nil { + return x.Finalized + } + return false +} + +func (x *CommitPreparedArkChannelOORResponse) GetAborted() bool { + if x != nil { + return x.Aborted + } + return false +} + +func (x *CommitPreparedArkChannelOORResponse) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type AbortPreparedArkChannelOORRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ChannelId []byte `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + Terms *arkchannelrpc.ChannelTerms `protobuf:"bytes,2,opt,name=terms,proto3" json:"terms,omitempty"` + Binding *arkchannelrpc.ChannelVTXOBinding `protobuf:"bytes,3,opt,name=binding,proto3" json:"binding,omitempty"` + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AbortPreparedArkChannelOORRequest) Reset() { + *x = AbortPreparedArkChannelOORRequest{} + mi := &file_daemon_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AbortPreparedArkChannelOORRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AbortPreparedArkChannelOORRequest) ProtoMessage() {} + +func (x *AbortPreparedArkChannelOORRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[54] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AbortPreparedArkChannelOORRequest.ProtoReflect.Descriptor instead. +func (*AbortPreparedArkChannelOORRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{54} +} + +func (x *AbortPreparedArkChannelOORRequest) GetChannelId() []byte { + if x != nil { + return x.ChannelId + } + return nil +} + +func (x *AbortPreparedArkChannelOORRequest) GetTerms() *arkchannelrpc.ChannelTerms { + if x != nil { + return x.Terms + } + return nil +} + +func (x *AbortPreparedArkChannelOORRequest) GetBinding() *arkchannelrpc.ChannelVTXOBinding { + if x != nil { + return x.Binding + } + return nil +} + +func (x *AbortPreparedArkChannelOORRequest) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type AbortPreparedArkChannelOORResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Aborted bool `protobuf:"varint,1,opt,name=aborted,proto3" json:"aborted,omitempty"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` + Finalized bool `protobuf:"varint,3,opt,name=finalized,proto3" json:"finalized,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AbortPreparedArkChannelOORResponse) Reset() { + *x = AbortPreparedArkChannelOORResponse{} + mi := &file_daemon_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AbortPreparedArkChannelOORResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AbortPreparedArkChannelOORResponse) ProtoMessage() {} + +func (x *AbortPreparedArkChannelOORResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[55] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AbortPreparedArkChannelOORResponse.ProtoReflect.Descriptor instead. +func (*AbortPreparedArkChannelOORResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{55} +} + +func (x *AbortPreparedArkChannelOORResponse) GetAborted() bool { + if x != nil { + return x.Aborted + } + return false +} + +func (x *AbortPreparedArkChannelOORResponse) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *AbortPreparedArkChannelOORResponse) GetFinalized() bool { + if x != nil { + return x.Finalized + } + return false +} + +type SignOORCustomInputRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // custom_input describes the vHTLC/custom VTXO and selected spend path. + CustomInput *CustomOORInput `protobuf:"bytes,1,opt,name=custom_input,json=customInput,proto3" json:"custom_input,omitempty"` + // checkpoint_psbt is the prepared checkpoint PSBT to sign. + CheckpointPsbt []byte `protobuf:"bytes,2,opt,name=checkpoint_psbt,json=checkpointPsbt,proto3" json:"checkpoint_psbt,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SignOORCustomInputRequest) Reset() { + *x = SignOORCustomInputRequest{} + mi := &file_daemon_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignOORCustomInputRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignOORCustomInputRequest) ProtoMessage() {} + +func (x *SignOORCustomInputRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[56] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignOORCustomInputRequest.ProtoReflect.Descriptor instead. +func (*SignOORCustomInputRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{56} +} + +func (x *SignOORCustomInputRequest) GetCustomInput() *CustomOORInput { + if x != nil { + return x.CustomInput + } + return nil +} + +func (x *SignOORCustomInputRequest) GetCheckpointPsbt() []byte { + if x != nil { + return x.CheckpointPsbt + } + return nil +} + +type SignOORCustomInputResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // signature is the daemon identity key's tapscript signature. + Signature *TaprootScriptSignature `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SignOORCustomInputResponse) Reset() { + *x = SignOORCustomInputResponse{} + mi := &file_daemon_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignOORCustomInputResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignOORCustomInputResponse) ProtoMessage() {} + +func (x *SignOORCustomInputResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[57] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignOORCustomInputResponse.ProtoReflect.Descriptor instead. +func (*SignOORCustomInputResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{57} +} + +func (x *SignOORCustomInputResponse) GetSignature() *TaprootScriptSignature { + if x != nil { + return x.Signature + } + return nil +} + +type SignVTXOForfeitRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // vtxo_outpoint identifies the VTXO input at forfeit tx input index 0. + VtxoOutpoint string `protobuf:"bytes,1,opt,name=vtxo_outpoint,json=vtxoOutpoint,proto3" json:"vtxo_outpoint,omitempty"` + // vtxo_amount_sat is the value of the VTXO output being spent. + VtxoAmountSat int64 `protobuf:"varint,2,opt,name=vtxo_amount_sat,json=vtxoAmountSat,proto3" json:"vtxo_amount_sat,omitempty"` + // vtxo_pk_script is the taproot output script of the VTXO being spent. + VtxoPkScript []byte `protobuf:"bytes,3,opt,name=vtxo_pk_script,json=vtxoPkScript,proto3" json:"vtxo_pk_script,omitempty"` + // vtxo_policy_template is the semantic policy template that produced the + // VTXO taproot output. + VtxoPolicyTemplate []byte `protobuf:"bytes,4,opt,name=vtxo_policy_template,json=vtxoPolicyTemplate,proto3" json:"vtxo_policy_template,omitempty"` + // spend_path is the encoded tapscript path selected for the VTXO input. + SpendPath []byte `protobuf:"bytes,5,opt,name=spend_path,json=spendPath,proto3" json:"spend_path,omitempty"` + // unsigned_forfeit_tx is the exact serialized forfeit transaction to sign. + UnsignedForfeitTx []byte `protobuf:"bytes,6,opt,name=unsigned_forfeit_tx,json=unsignedForfeitTx,proto3" json:"unsigned_forfeit_tx,omitempty"` + // connector_outpoint identifies the connector input at forfeit tx input + // index 1. + ConnectorOutpoint string `protobuf:"bytes,7,opt,name=connector_outpoint,json=connectorOutpoint,proto3" json:"connector_outpoint,omitempty"` + // connector_amount_sat is the value of the connector output being spent. + ConnectorAmountSat int64 `protobuf:"varint,8,opt,name=connector_amount_sat,json=connectorAmountSat,proto3" json:"connector_amount_sat,omitempty"` + // connector_pk_script is the connector output script being spent. + ConnectorPkScript []byte `protobuf:"bytes,9,opt,name=connector_pk_script,json=connectorPkScript,proto3" json:"connector_pk_script,omitempty"` + // server_forfeit_pk_script is the expected penalty output script at output + // index 0. + ServerForfeitPkScript []byte `protobuf:"bytes,10,opt,name=server_forfeit_pk_script,json=serverForfeitPkScript,proto3" json:"server_forfeit_pk_script,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SignVTXOForfeitRequest) Reset() { + *x = SignVTXOForfeitRequest{} + mi := &file_daemon_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignVTXOForfeitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignVTXOForfeitRequest) ProtoMessage() {} + +func (x *SignVTXOForfeitRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[58] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignVTXOForfeitRequest.ProtoReflect.Descriptor instead. +func (*SignVTXOForfeitRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{58} +} + +func (x *SignVTXOForfeitRequest) GetVtxoOutpoint() string { + if x != nil { + return x.VtxoOutpoint + } + return "" +} + +func (x *SignVTXOForfeitRequest) GetVtxoAmountSat() int64 { + if x != nil { + return x.VtxoAmountSat + } + return 0 +} + +func (x *SignVTXOForfeitRequest) GetVtxoPkScript() []byte { + if x != nil { + return x.VtxoPkScript + } + return nil +} + +func (x *SignVTXOForfeitRequest) GetVtxoPolicyTemplate() []byte { + if x != nil { + return x.VtxoPolicyTemplate + } + return nil +} + +func (x *SignVTXOForfeitRequest) GetSpendPath() []byte { + if x != nil { + return x.SpendPath + } + return nil +} + +func (x *SignVTXOForfeitRequest) GetUnsignedForfeitTx() []byte { + if x != nil { + return x.UnsignedForfeitTx + } + return nil +} + +func (x *SignVTXOForfeitRequest) GetConnectorOutpoint() string { + if x != nil { + return x.ConnectorOutpoint + } + return "" +} + +func (x *SignVTXOForfeitRequest) GetConnectorAmountSat() int64 { + if x != nil { + return x.ConnectorAmountSat + } + return 0 +} + +func (x *SignVTXOForfeitRequest) GetConnectorPkScript() []byte { + if x != nil { + return x.ConnectorPkScript + } + return nil +} + +func (x *SignVTXOForfeitRequest) GetServerForfeitPkScript() []byte { + if x != nil { + return x.ServerForfeitPkScript + } + return nil +} + +type SignVTXOForfeitResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // pubkey is the daemon identity public key that produced signature. + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` + // signature is the raw 64-byte Schnorr signature for the VTXO input. + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SignVTXOForfeitResponse) Reset() { + *x = SignVTXOForfeitResponse{} + mi := &file_daemon_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SignVTXOForfeitResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignVTXOForfeitResponse) ProtoMessage() {} + +func (x *SignVTXOForfeitResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[59] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignVTXOForfeitResponse.ProtoReflect.Descriptor instead. +func (*SignVTXOForfeitResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{59} +} + +func (x *SignVTXOForfeitResponse) GetPubkey() []byte { + if x != nil { + return x.Pubkey + } + return nil +} + +func (x *SignVTXOForfeitResponse) GetSignature() []byte { + if x != nil { + return x.Signature } return nil } @@ -4408,7 +5094,7 @@ type ForfeitSigningContext struct { func (x *ForfeitSigningContext) Reset() { *x = ForfeitSigningContext{} - mi := &file_daemon_proto_msgTypes[48] + mi := &file_daemon_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4420,7 +5106,7 @@ func (x *ForfeitSigningContext) String() string { func (*ForfeitSigningContext) ProtoMessage() {} func (x *ForfeitSigningContext) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[48] + mi := &file_daemon_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4433,7 +5119,7 @@ func (x *ForfeitSigningContext) ProtoReflect() protoreflect.Message { // Deprecated: Use ForfeitSigningContext.ProtoReflect.Descriptor instead. func (*ForfeitSigningContext) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{48} + return file_daemon_proto_rawDescGZIP(), []int{60} } func (x *ForfeitSigningContext) GetPaymentHash() []byte { @@ -4463,7 +5149,7 @@ type OutpointSelection struct { func (x *OutpointSelection) Reset() { *x = OutpointSelection{} - mi := &file_daemon_proto_msgTypes[49] + mi := &file_daemon_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4475,7 +5161,7 @@ func (x *OutpointSelection) String() string { func (*OutpointSelection) ProtoMessage() {} func (x *OutpointSelection) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[49] + mi := &file_daemon_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4488,7 +5174,7 @@ func (x *OutpointSelection) ProtoReflect() protoreflect.Message { // Deprecated: Use OutpointSelection.ProtoReflect.Descriptor instead. func (*OutpointSelection) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{49} + return file_daemon_proto_rawDescGZIP(), []int{61} } func (x *OutpointSelection) GetOutpoints() []string { @@ -4513,7 +5199,7 @@ type RefreshVTXOsRequest struct { func (x *RefreshVTXOsRequest) Reset() { *x = RefreshVTXOsRequest{} - mi := &file_daemon_proto_msgTypes[50] + mi := &file_daemon_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4525,7 +5211,7 @@ func (x *RefreshVTXOsRequest) String() string { func (*RefreshVTXOsRequest) ProtoMessage() {} func (x *RefreshVTXOsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[50] + mi := &file_daemon_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4538,7 +5224,7 @@ func (x *RefreshVTXOsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshVTXOsRequest.ProtoReflect.Descriptor instead. func (*RefreshVTXOsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{50} + return file_daemon_proto_rawDescGZIP(), []int{62} } func (x *RefreshVTXOsRequest) GetSelection() isRefreshVTXOsRequest_Selection { @@ -4610,7 +5296,7 @@ type RefreshVTXOsResponse struct { func (x *RefreshVTXOsResponse) Reset() { *x = RefreshVTXOsResponse{} - mi := &file_daemon_proto_msgTypes[51] + mi := &file_daemon_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4622,7 +5308,7 @@ func (x *RefreshVTXOsResponse) String() string { func (*RefreshVTXOsResponse) ProtoMessage() {} func (x *RefreshVTXOsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[51] + mi := &file_daemon_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4635,7 +5321,7 @@ func (x *RefreshVTXOsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshVTXOsResponse.ProtoReflect.Descriptor instead. func (*RefreshVTXOsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{51} + return file_daemon_proto_rawDescGZIP(), []int{63} } func (x *RefreshVTXOsResponse) GetQueuedOutpoints() []string { @@ -4701,7 +5387,7 @@ type RefreshFeeEstimate struct { func (x *RefreshFeeEstimate) Reset() { *x = RefreshFeeEstimate{} - mi := &file_daemon_proto_msgTypes[52] + mi := &file_daemon_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4713,7 +5399,7 @@ func (x *RefreshFeeEstimate) String() string { func (*RefreshFeeEstimate) ProtoMessage() {} func (x *RefreshFeeEstimate) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[52] + mi := &file_daemon_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4726,7 +5412,7 @@ func (x *RefreshFeeEstimate) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshFeeEstimate.ProtoReflect.Descriptor instead. func (*RefreshFeeEstimate) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{52} + return file_daemon_proto_rawDescGZIP(), []int{64} } func (x *RefreshFeeEstimate) GetEstimatedTotalFeeSat() int64 { @@ -4794,7 +5480,7 @@ type OutpointFeeEstimate struct { func (x *OutpointFeeEstimate) Reset() { *x = OutpointFeeEstimate{} - mi := &file_daemon_proto_msgTypes[53] + mi := &file_daemon_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4806,7 +5492,7 @@ func (x *OutpointFeeEstimate) String() string { func (*OutpointFeeEstimate) ProtoMessage() {} func (x *OutpointFeeEstimate) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[53] + mi := &file_daemon_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4819,7 +5505,7 @@ func (x *OutpointFeeEstimate) ProtoReflect() protoreflect.Message { // Deprecated: Use OutpointFeeEstimate.ProtoReflect.Descriptor instead. func (*OutpointFeeEstimate) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{53} + return file_daemon_proto_rawDescGZIP(), []int{65} } func (x *OutpointFeeEstimate) GetOutpoint() string { @@ -4919,7 +5605,7 @@ type CustomRefreshVTXOInput struct { func (x *CustomRefreshVTXOInput) Reset() { *x = CustomRefreshVTXOInput{} - mi := &file_daemon_proto_msgTypes[54] + mi := &file_daemon_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4931,7 +5617,7 @@ func (x *CustomRefreshVTXOInput) String() string { func (*CustomRefreshVTXOInput) ProtoMessage() {} func (x *CustomRefreshVTXOInput) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[54] + mi := &file_daemon_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4944,7 +5630,7 @@ func (x *CustomRefreshVTXOInput) ProtoReflect() protoreflect.Message { // Deprecated: Use CustomRefreshVTXOInput.ProtoReflect.Descriptor instead. func (*CustomRefreshVTXOInput) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{54} + return file_daemon_proto_rawDescGZIP(), []int{66} } func (x *CustomRefreshVTXOInput) GetOutpoint() string { @@ -5018,7 +5704,7 @@ type CustomRefreshVTXOOutput struct { func (x *CustomRefreshVTXOOutput) Reset() { *x = CustomRefreshVTXOOutput{} - mi := &file_daemon_proto_msgTypes[55] + mi := &file_daemon_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5030,7 +5716,7 @@ func (x *CustomRefreshVTXOOutput) String() string { func (*CustomRefreshVTXOOutput) ProtoMessage() {} func (x *CustomRefreshVTXOOutput) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[55] + mi := &file_daemon_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5043,7 +5729,7 @@ func (x *CustomRefreshVTXOOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use CustomRefreshVTXOOutput.ProtoReflect.Descriptor instead. func (*CustomRefreshVTXOOutput) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{55} + return file_daemon_proto_rawDescGZIP(), []int{67} } func (x *CustomRefreshVTXOOutput) GetAmountSat() int64 { @@ -5090,7 +5776,7 @@ type RefreshCustomVTXOsRequest struct { func (x *RefreshCustomVTXOsRequest) Reset() { *x = RefreshCustomVTXOsRequest{} - mi := &file_daemon_proto_msgTypes[56] + mi := &file_daemon_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5102,7 +5788,7 @@ func (x *RefreshCustomVTXOsRequest) String() string { func (*RefreshCustomVTXOsRequest) ProtoMessage() {} func (x *RefreshCustomVTXOsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[56] + mi := &file_daemon_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5115,7 +5801,7 @@ func (x *RefreshCustomVTXOsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshCustomVTXOsRequest.ProtoReflect.Descriptor instead. func (*RefreshCustomVTXOsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{56} + return file_daemon_proto_rawDescGZIP(), []int{68} } func (x *RefreshCustomVTXOsRequest) GetInputs() []*CustomRefreshVTXOInput { @@ -5151,7 +5837,7 @@ type RefreshCustomVTXOsResponse struct { func (x *RefreshCustomVTXOsResponse) Reset() { *x = RefreshCustomVTXOsResponse{} - mi := &file_daemon_proto_msgTypes[57] + mi := &file_daemon_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5163,7 +5849,7 @@ func (x *RefreshCustomVTXOsResponse) String() string { func (*RefreshCustomVTXOsResponse) ProtoMessage() {} func (x *RefreshCustomVTXOsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[57] + mi := &file_daemon_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5176,7 +5862,7 @@ func (x *RefreshCustomVTXOsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshCustomVTXOsResponse.ProtoReflect.Descriptor instead. func (*RefreshCustomVTXOsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{57} + return file_daemon_proto_rawDescGZIP(), []int{69} } func (x *RefreshCustomVTXOsResponse) GetQueuedOutpoints() []string { @@ -5245,7 +5931,7 @@ type PendingForfeitParticipantSignatureRequest struct { func (x *PendingForfeitParticipantSignatureRequest) Reset() { *x = PendingForfeitParticipantSignatureRequest{} - mi := &file_daemon_proto_msgTypes[58] + mi := &file_daemon_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5257,7 +5943,7 @@ func (x *PendingForfeitParticipantSignatureRequest) String() string { func (*PendingForfeitParticipantSignatureRequest) ProtoMessage() {} func (x *PendingForfeitParticipantSignatureRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[58] + mi := &file_daemon_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5270,7 +5956,7 @@ func (x *PendingForfeitParticipantSignatureRequest) ProtoReflect() protoreflect. // Deprecated: Use PendingForfeitParticipantSignatureRequest.ProtoReflect.Descriptor instead. func (*PendingForfeitParticipantSignatureRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{58} + return file_daemon_proto_rawDescGZIP(), []int{70} } func (x *PendingForfeitParticipantSignatureRequest) GetRequestId() []byte { @@ -5384,7 +6070,7 @@ type ListPendingForfeitParticipantSignatureRequestsRequest struct { func (x *ListPendingForfeitParticipantSignatureRequestsRequest) Reset() { *x = ListPendingForfeitParticipantSignatureRequestsRequest{} - mi := &file_daemon_proto_msgTypes[59] + mi := &file_daemon_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5396,7 +6082,7 @@ func (x *ListPendingForfeitParticipantSignatureRequestsRequest) String() string func (*ListPendingForfeitParticipantSignatureRequestsRequest) ProtoMessage() {} func (x *ListPendingForfeitParticipantSignatureRequestsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[59] + mi := &file_daemon_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5409,7 +6095,7 @@ func (x *ListPendingForfeitParticipantSignatureRequestsRequest) ProtoReflect() p // Deprecated: Use ListPendingForfeitParticipantSignatureRequestsRequest.ProtoReflect.Descriptor instead. func (*ListPendingForfeitParticipantSignatureRequestsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{59} + return file_daemon_proto_rawDescGZIP(), []int{71} } func (x *ListPendingForfeitParticipantSignatureRequestsRequest) GetAfterSequence() uint64 { @@ -5436,7 +6122,7 @@ type ListPendingForfeitParticipantSignatureRequestsResponse struct { func (x *ListPendingForfeitParticipantSignatureRequestsResponse) Reset() { *x = ListPendingForfeitParticipantSignatureRequestsResponse{} - mi := &file_daemon_proto_msgTypes[60] + mi := &file_daemon_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5448,7 +6134,7 @@ func (x *ListPendingForfeitParticipantSignatureRequestsResponse) String() string func (*ListPendingForfeitParticipantSignatureRequestsResponse) ProtoMessage() {} func (x *ListPendingForfeitParticipantSignatureRequestsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[60] + mi := &file_daemon_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5461,7 +6147,7 @@ func (x *ListPendingForfeitParticipantSignatureRequestsResponse) ProtoReflect() // Deprecated: Use ListPendingForfeitParticipantSignatureRequestsResponse.ProtoReflect.Descriptor instead. func (*ListPendingForfeitParticipantSignatureRequestsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{60} + return file_daemon_proto_rawDescGZIP(), []int{72} } func (x *ListPendingForfeitParticipantSignatureRequestsResponse) GetRequests() []*PendingForfeitParticipantSignatureRequest { @@ -5493,7 +6179,7 @@ type ForfeitParticipantSignature struct { func (x *ForfeitParticipantSignature) Reset() { *x = ForfeitParticipantSignature{} - mi := &file_daemon_proto_msgTypes[61] + mi := &file_daemon_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5505,7 +6191,7 @@ func (x *ForfeitParticipantSignature) String() string { func (*ForfeitParticipantSignature) ProtoMessage() {} func (x *ForfeitParticipantSignature) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[61] + mi := &file_daemon_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5518,7 +6204,7 @@ func (x *ForfeitParticipantSignature) ProtoReflect() protoreflect.Message { // Deprecated: Use ForfeitParticipantSignature.ProtoReflect.Descriptor instead. func (*ForfeitParticipantSignature) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{61} + return file_daemon_proto_rawDescGZIP(), []int{73} } func (x *ForfeitParticipantSignature) GetPubkey() []byte { @@ -5552,7 +6238,7 @@ type SubmitForfeitParticipantSignaturesRequest struct { func (x *SubmitForfeitParticipantSignaturesRequest) Reset() { *x = SubmitForfeitParticipantSignaturesRequest{} - mi := &file_daemon_proto_msgTypes[62] + mi := &file_daemon_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5564,7 +6250,7 @@ func (x *SubmitForfeitParticipantSignaturesRequest) String() string { func (*SubmitForfeitParticipantSignaturesRequest) ProtoMessage() {} func (x *SubmitForfeitParticipantSignaturesRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[62] + mi := &file_daemon_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5577,7 +6263,7 @@ func (x *SubmitForfeitParticipantSignaturesRequest) ProtoReflect() protoreflect. // Deprecated: Use SubmitForfeitParticipantSignaturesRequest.ProtoReflect.Descriptor instead. func (*SubmitForfeitParticipantSignaturesRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{62} + return file_daemon_proto_rawDescGZIP(), []int{74} } func (x *SubmitForfeitParticipantSignaturesRequest) GetRequestId() []byte { @@ -5602,7 +6288,7 @@ type SubmitForfeitParticipantSignaturesResponse struct { func (x *SubmitForfeitParticipantSignaturesResponse) Reset() { *x = SubmitForfeitParticipantSignaturesResponse{} - mi := &file_daemon_proto_msgTypes[63] + mi := &file_daemon_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5614,7 +6300,7 @@ func (x *SubmitForfeitParticipantSignaturesResponse) String() string { func (*SubmitForfeitParticipantSignaturesResponse) ProtoMessage() {} func (x *SubmitForfeitParticipantSignaturesResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[63] + mi := &file_daemon_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5627,7 +6313,7 @@ func (x *SubmitForfeitParticipantSignaturesResponse) ProtoReflect() protoreflect // Deprecated: Use SubmitForfeitParticipantSignaturesResponse.ProtoReflect.Descriptor instead. func (*SubmitForfeitParticipantSignaturesResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{63} + return file_daemon_proto_rawDescGZIP(), []int{75} } // LeaveDestination describes where a single leave output should land. @@ -5647,7 +6333,7 @@ type LeaveDestination struct { func (x *LeaveDestination) Reset() { *x = LeaveDestination{} - mi := &file_daemon_proto_msgTypes[64] + mi := &file_daemon_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5659,7 +6345,7 @@ func (x *LeaveDestination) String() string { func (*LeaveDestination) ProtoMessage() {} func (x *LeaveDestination) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[64] + mi := &file_daemon_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5672,7 +6358,7 @@ func (x *LeaveDestination) ProtoReflect() protoreflect.Message { // Deprecated: Use LeaveDestination.ProtoReflect.Descriptor instead. func (*LeaveDestination) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{64} + return file_daemon_proto_rawDescGZIP(), []int{76} } func (x *LeaveDestination) GetTarget() isLeaveDestination_Target { @@ -5753,7 +6439,7 @@ type LeaveVTXOsRequest struct { func (x *LeaveVTXOsRequest) Reset() { *x = LeaveVTXOsRequest{} - mi := &file_daemon_proto_msgTypes[65] + mi := &file_daemon_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5765,7 +6451,7 @@ func (x *LeaveVTXOsRequest) String() string { func (*LeaveVTXOsRequest) ProtoMessage() {} func (x *LeaveVTXOsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[65] + mi := &file_daemon_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5778,7 +6464,7 @@ func (x *LeaveVTXOsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LeaveVTXOsRequest.ProtoReflect.Descriptor instead. func (*LeaveVTXOsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{65} + return file_daemon_proto_rawDescGZIP(), []int{77} } func (x *LeaveVTXOsRequest) GetSelection() isLeaveVTXOsRequest_Selection { @@ -5861,7 +6547,7 @@ type LeaveVTXOsResponse struct { func (x *LeaveVTXOsResponse) Reset() { *x = LeaveVTXOsResponse{} - mi := &file_daemon_proto_msgTypes[66] + mi := &file_daemon_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5873,7 +6559,7 @@ func (x *LeaveVTXOsResponse) String() string { func (*LeaveVTXOsResponse) ProtoMessage() {} func (x *LeaveVTXOsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[66] + mi := &file_daemon_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5886,7 +6572,7 @@ func (x *LeaveVTXOsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LeaveVTXOsResponse.ProtoReflect.Descriptor instead. func (*LeaveVTXOsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{66} + return file_daemon_proto_rawDescGZIP(), []int{78} } func (x *LeaveVTXOsResponse) GetQueuedOutpoints() []string { @@ -5924,7 +6610,7 @@ type SendOnChainRequest struct { func (x *SendOnChainRequest) Reset() { *x = SendOnChainRequest{} - mi := &file_daemon_proto_msgTypes[67] + mi := &file_daemon_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5936,7 +6622,7 @@ func (x *SendOnChainRequest) String() string { func (*SendOnChainRequest) ProtoMessage() {} func (x *SendOnChainRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[67] + mi := &file_daemon_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5949,7 +6635,7 @@ func (x *SendOnChainRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SendOnChainRequest.ProtoReflect.Descriptor instead. func (*SendOnChainRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{67} + return file_daemon_proto_rawDescGZIP(), []int{79} } func (x *SendOnChainRequest) GetDestination() *LeaveDestination { @@ -6057,7 +6743,7 @@ type SendOnChainResponse struct { func (x *SendOnChainResponse) Reset() { *x = SendOnChainResponse{} - mi := &file_daemon_proto_msgTypes[68] + mi := &file_daemon_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6069,7 +6755,7 @@ func (x *SendOnChainResponse) String() string { func (*SendOnChainResponse) ProtoMessage() {} func (x *SendOnChainResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[68] + mi := &file_daemon_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6082,7 +6768,7 @@ func (x *SendOnChainResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SendOnChainResponse.ProtoReflect.Descriptor instead. func (*SendOnChainResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{68} + return file_daemon_proto_rawDescGZIP(), []int{80} } func (x *SendOnChainResponse) GetActualAmountSat() int64 { @@ -6148,7 +6834,7 @@ type BoardRequest struct { func (x *BoardRequest) Reset() { *x = BoardRequest{} - mi := &file_daemon_proto_msgTypes[69] + mi := &file_daemon_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6160,7 +6846,7 @@ func (x *BoardRequest) String() string { func (*BoardRequest) ProtoMessage() {} func (x *BoardRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[69] + mi := &file_daemon_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6173,7 +6859,7 @@ func (x *BoardRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardRequest.ProtoReflect.Descriptor instead. func (*BoardRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{69} + return file_daemon_proto_rawDescGZIP(), []int{81} } func (x *BoardRequest) GetTargetVtxoCount() uint32 { @@ -6204,7 +6890,7 @@ type BoardResponse struct { func (x *BoardResponse) Reset() { *x = BoardResponse{} - mi := &file_daemon_proto_msgTypes[70] + mi := &file_daemon_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6216,7 +6902,7 @@ func (x *BoardResponse) String() string { func (*BoardResponse) ProtoMessage() {} func (x *BoardResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[70] + mi := &file_daemon_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6229,7 +6915,7 @@ func (x *BoardResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardResponse.ProtoReflect.Descriptor instead. func (*BoardResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{70} + return file_daemon_proto_rawDescGZIP(), []int{82} } func (x *BoardResponse) GetStatus() string { @@ -6254,7 +6940,7 @@ type JoinNextRoundRequest struct { func (x *JoinNextRoundRequest) Reset() { *x = JoinNextRoundRequest{} - mi := &file_daemon_proto_msgTypes[71] + mi := &file_daemon_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6266,7 +6952,7 @@ func (x *JoinNextRoundRequest) String() string { func (*JoinNextRoundRequest) ProtoMessage() {} func (x *JoinNextRoundRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[71] + mi := &file_daemon_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6279,7 +6965,7 @@ func (x *JoinNextRoundRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JoinNextRoundRequest.ProtoReflect.Descriptor instead. func (*JoinNextRoundRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{71} + return file_daemon_proto_rawDescGZIP(), []int{83} } type JoinNextRoundResponse struct { @@ -6294,7 +6980,7 @@ type JoinNextRoundResponse struct { func (x *JoinNextRoundResponse) Reset() { *x = JoinNextRoundResponse{} - mi := &file_daemon_proto_msgTypes[72] + mi := &file_daemon_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6306,7 +6992,7 @@ func (x *JoinNextRoundResponse) String() string { func (*JoinNextRoundResponse) ProtoMessage() {} func (x *JoinNextRoundResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[72] + mi := &file_daemon_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6319,7 +7005,7 @@ func (x *JoinNextRoundResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use JoinNextRoundResponse.ProtoReflect.Descriptor instead. func (*JoinNextRoundResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{72} + return file_daemon_proto_rawDescGZIP(), []int{84} } func (x *JoinNextRoundResponse) GetStatus() string { @@ -6355,7 +7041,7 @@ type SweepBoardingUTXOsRequest struct { func (x *SweepBoardingUTXOsRequest) Reset() { *x = SweepBoardingUTXOsRequest{} - mi := &file_daemon_proto_msgTypes[73] + mi := &file_daemon_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6367,7 +7053,7 @@ func (x *SweepBoardingUTXOsRequest) String() string { func (*SweepBoardingUTXOsRequest) ProtoMessage() {} func (x *SweepBoardingUTXOsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[73] + mi := &file_daemon_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6380,7 +7066,7 @@ func (x *SweepBoardingUTXOsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SweepBoardingUTXOsRequest.ProtoReflect.Descriptor instead. func (*SweepBoardingUTXOsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{73} + return file_daemon_proto_rawDescGZIP(), []int{85} } func (x *SweepBoardingUTXOsRequest) GetOutpoints() []string { @@ -6433,7 +7119,7 @@ type BoardingSweepOutput struct { func (x *BoardingSweepOutput) Reset() { *x = BoardingSweepOutput{} - mi := &file_daemon_proto_msgTypes[74] + mi := &file_daemon_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6445,7 +7131,7 @@ func (x *BoardingSweepOutput) String() string { func (*BoardingSweepOutput) ProtoMessage() {} func (x *BoardingSweepOutput) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[74] + mi := &file_daemon_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6458,7 +7144,7 @@ func (x *BoardingSweepOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardingSweepOutput.ProtoReflect.Descriptor instead. func (*BoardingSweepOutput) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{74} + return file_daemon_proto_rawDescGZIP(), []int{86} } func (x *BoardingSweepOutput) GetOutpoint() string { @@ -6524,7 +7210,7 @@ type SweepBoardingUTXOsResponse struct { func (x *SweepBoardingUTXOsResponse) Reset() { *x = SweepBoardingUTXOsResponse{} - mi := &file_daemon_proto_msgTypes[75] + mi := &file_daemon_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6536,7 +7222,7 @@ func (x *SweepBoardingUTXOsResponse) String() string { func (*SweepBoardingUTXOsResponse) ProtoMessage() {} func (x *SweepBoardingUTXOsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[75] + mi := &file_daemon_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6549,7 +7235,7 @@ func (x *SweepBoardingUTXOsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SweepBoardingUTXOsResponse.ProtoReflect.Descriptor instead. func (*SweepBoardingUTXOsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{75} + return file_daemon_proto_rawDescGZIP(), []int{87} } func (x *SweepBoardingUTXOsResponse) GetStatus() string { @@ -6653,7 +7339,7 @@ type ListBoardingSweepsRequest struct { func (x *ListBoardingSweepsRequest) Reset() { *x = ListBoardingSweepsRequest{} - mi := &file_daemon_proto_msgTypes[76] + mi := &file_daemon_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6665,7 +7351,7 @@ func (x *ListBoardingSweepsRequest) String() string { func (*ListBoardingSweepsRequest) ProtoMessage() {} func (x *ListBoardingSweepsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[76] + mi := &file_daemon_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6678,7 +7364,7 @@ func (x *ListBoardingSweepsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListBoardingSweepsRequest.ProtoReflect.Descriptor instead. func (*ListBoardingSweepsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{76} + return file_daemon_proto_rawDescGZIP(), []int{88} } func (x *ListBoardingSweepsRequest) GetStatus() string { @@ -6721,7 +7407,7 @@ type BoardingSweepInput struct { func (x *BoardingSweepInput) Reset() { *x = BoardingSweepInput{} - mi := &file_daemon_proto_msgTypes[77] + mi := &file_daemon_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6733,7 +7419,7 @@ func (x *BoardingSweepInput) String() string { func (*BoardingSweepInput) ProtoMessage() {} func (x *BoardingSweepInput) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[77] + mi := &file_daemon_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6746,7 +7432,7 @@ func (x *BoardingSweepInput) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardingSweepInput.ProtoReflect.Descriptor instead. func (*BoardingSweepInput) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{77} + return file_daemon_proto_rawDescGZIP(), []int{89} } func (x *BoardingSweepInput) GetOutpoint() string { @@ -6816,7 +7502,7 @@ type BoardingSweep struct { func (x *BoardingSweep) Reset() { *x = BoardingSweep{} - mi := &file_daemon_proto_msgTypes[78] + mi := &file_daemon_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6828,7 +7514,7 @@ func (x *BoardingSweep) String() string { func (*BoardingSweep) ProtoMessage() {} func (x *BoardingSweep) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[78] + mi := &file_daemon_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6841,7 +7527,7 @@ func (x *BoardingSweep) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardingSweep.ProtoReflect.Descriptor instead. func (*BoardingSweep) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{78} + return file_daemon_proto_rawDescGZIP(), []int{90} } func (x *BoardingSweep) GetTxid() string { @@ -6933,7 +7619,7 @@ type ListBoardingSweepsResponse struct { func (x *ListBoardingSweepsResponse) Reset() { *x = ListBoardingSweepsResponse{} - mi := &file_daemon_proto_msgTypes[79] + mi := &file_daemon_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6945,7 +7631,7 @@ func (x *ListBoardingSweepsResponse) String() string { func (*ListBoardingSweepsResponse) ProtoMessage() {} func (x *ListBoardingSweepsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[79] + mi := &file_daemon_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6958,7 +7644,7 @@ func (x *ListBoardingSweepsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListBoardingSweepsResponse.ProtoReflect.Descriptor instead. func (*ListBoardingSweepsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{79} + return file_daemon_proto_rawDescGZIP(), []int{91} } func (x *ListBoardingSweepsResponse) GetSweeps() []*BoardingSweep { @@ -6988,7 +7674,7 @@ type RoundVTXOInfo struct { func (x *RoundVTXOInfo) Reset() { *x = RoundVTXOInfo{} - mi := &file_daemon_proto_msgTypes[80] + mi := &file_daemon_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7000,7 +7686,7 @@ func (x *RoundVTXOInfo) String() string { func (*RoundVTXOInfo) ProtoMessage() {} func (x *RoundVTXOInfo) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[80] + mi := &file_daemon_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7013,7 +7699,7 @@ func (x *RoundVTXOInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use RoundVTXOInfo.ProtoReflect.Descriptor instead. func (*RoundVTXOInfo) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{80} + return file_daemon_proto_rawDescGZIP(), []int{92} } func (x *RoundVTXOInfo) GetOutpoint() string { @@ -7081,7 +7767,7 @@ type RoundInfo struct { func (x *RoundInfo) Reset() { *x = RoundInfo{} - mi := &file_daemon_proto_msgTypes[81] + mi := &file_daemon_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7093,7 +7779,7 @@ func (x *RoundInfo) String() string { func (*RoundInfo) ProtoMessage() {} func (x *RoundInfo) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[81] + mi := &file_daemon_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7106,7 +7792,7 @@ func (x *RoundInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use RoundInfo.ProtoReflect.Descriptor instead. func (*RoundInfo) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{81} + return file_daemon_proto_rawDescGZIP(), []int{93} } func (x *RoundInfo) GetRoundId() string { @@ -7218,7 +7904,7 @@ type ListRoundsRequest struct { func (x *ListRoundsRequest) Reset() { *x = ListRoundsRequest{} - mi := &file_daemon_proto_msgTypes[82] + mi := &file_daemon_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7230,7 +7916,7 @@ func (x *ListRoundsRequest) String() string { func (*ListRoundsRequest) ProtoMessage() {} func (x *ListRoundsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[82] + mi := &file_daemon_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7243,7 +7929,7 @@ func (x *ListRoundsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRoundsRequest.ProtoReflect.Descriptor instead. func (*ListRoundsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{82} + return file_daemon_proto_rawDescGZIP(), []int{94} } func (x *ListRoundsRequest) GetPageSize() int32 { @@ -7298,7 +7984,7 @@ type GetRoundRequest struct { func (x *GetRoundRequest) Reset() { *x = GetRoundRequest{} - mi := &file_daemon_proto_msgTypes[83] + mi := &file_daemon_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7310,7 +7996,7 @@ func (x *GetRoundRequest) String() string { func (*GetRoundRequest) ProtoMessage() {} func (x *GetRoundRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[83] + mi := &file_daemon_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7323,7 +8009,7 @@ func (x *GetRoundRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRoundRequest.ProtoReflect.Descriptor instead. func (*GetRoundRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{83} + return file_daemon_proto_rawDescGZIP(), []int{95} } func (x *GetRoundRequest) GetRoundId() string { @@ -7343,7 +8029,7 @@ type GetRoundResponse struct { func (x *GetRoundResponse) Reset() { *x = GetRoundResponse{} - mi := &file_daemon_proto_msgTypes[84] + mi := &file_daemon_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7355,7 +8041,7 @@ func (x *GetRoundResponse) String() string { func (*GetRoundResponse) ProtoMessage() {} func (x *GetRoundResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[84] + mi := &file_daemon_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7368,7 +8054,7 @@ func (x *GetRoundResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRoundResponse.ProtoReflect.Descriptor instead. func (*GetRoundResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{84} + return file_daemon_proto_rawDescGZIP(), []int{96} } func (x *GetRoundResponse) GetRound() *RoundInfo { @@ -7391,7 +8077,7 @@ type ListRoundsResponse struct { func (x *ListRoundsResponse) Reset() { *x = ListRoundsResponse{} - mi := &file_daemon_proto_msgTypes[85] + mi := &file_daemon_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7403,7 +8089,7 @@ func (x *ListRoundsResponse) String() string { func (*ListRoundsResponse) ProtoMessage() {} func (x *ListRoundsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[85] + mi := &file_daemon_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7416,7 +8102,7 @@ func (x *ListRoundsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRoundsResponse.ProtoReflect.Descriptor instead. func (*ListRoundsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{85} + return file_daemon_proto_rawDescGZIP(), []int{97} } func (x *ListRoundsResponse) GetRounds() []*RoundInfo { @@ -7441,7 +8127,7 @@ type WatchRoundsRequest struct { func (x *WatchRoundsRequest) Reset() { *x = WatchRoundsRequest{} - mi := &file_daemon_proto_msgTypes[86] + mi := &file_daemon_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7453,7 +8139,7 @@ func (x *WatchRoundsRequest) String() string { func (*WatchRoundsRequest) ProtoMessage() {} func (x *WatchRoundsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[86] + mi := &file_daemon_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7466,7 +8152,7 @@ func (x *WatchRoundsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchRoundsRequest.ProtoReflect.Descriptor instead. func (*WatchRoundsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{86} + return file_daemon_proto_rawDescGZIP(), []int{98} } type WatchRoundsResponse struct { @@ -7480,7 +8166,7 @@ type WatchRoundsResponse struct { func (x *WatchRoundsResponse) Reset() { *x = WatchRoundsResponse{} - mi := &file_daemon_proto_msgTypes[87] + mi := &file_daemon_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7492,7 +8178,7 @@ func (x *WatchRoundsResponse) String() string { func (*WatchRoundsResponse) ProtoMessage() {} func (x *WatchRoundsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[87] + mi := &file_daemon_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7505,7 +8191,7 @@ func (x *WatchRoundsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchRoundsResponse.ProtoReflect.Descriptor instead. func (*WatchRoundsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{87} + return file_daemon_proto_rawDescGZIP(), []int{99} } func (x *WatchRoundsResponse) GetRound() *RoundInfo { @@ -7543,7 +8229,7 @@ type OORSessionInfo struct { func (x *OORSessionInfo) Reset() { *x = OORSessionInfo{} - mi := &file_daemon_proto_msgTypes[88] + mi := &file_daemon_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7555,7 +8241,7 @@ func (x *OORSessionInfo) String() string { func (*OORSessionInfo) ProtoMessage() {} func (x *OORSessionInfo) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[88] + mi := &file_daemon_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7568,7 +8254,7 @@ func (x *OORSessionInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use OORSessionInfo.ProtoReflect.Descriptor instead. func (*OORSessionInfo) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{88} + return file_daemon_proto_rawDescGZIP(), []int{100} } func (x *OORSessionInfo) GetSessionId() string { @@ -7652,7 +8338,7 @@ type ListOORSessionsRequest struct { func (x *ListOORSessionsRequest) Reset() { *x = ListOORSessionsRequest{} - mi := &file_daemon_proto_msgTypes[89] + mi := &file_daemon_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7664,7 +8350,7 @@ func (x *ListOORSessionsRequest) String() string { func (*ListOORSessionsRequest) ProtoMessage() {} func (x *ListOORSessionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[89] + mi := &file_daemon_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7677,7 +8363,7 @@ func (x *ListOORSessionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListOORSessionsRequest.ProtoReflect.Descriptor instead. func (*ListOORSessionsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{89} + return file_daemon_proto_rawDescGZIP(), []int{101} } func (x *ListOORSessionsRequest) GetPageSize() int32 { @@ -7721,7 +8407,7 @@ type ListOORSessionsResponse struct { func (x *ListOORSessionsResponse) Reset() { *x = ListOORSessionsResponse{} - mi := &file_daemon_proto_msgTypes[90] + mi := &file_daemon_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7733,7 +8419,7 @@ func (x *ListOORSessionsResponse) String() string { func (*ListOORSessionsResponse) ProtoMessage() {} func (x *ListOORSessionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[90] + mi := &file_daemon_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7746,7 +8432,7 @@ func (x *ListOORSessionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListOORSessionsResponse.ProtoReflect.Descriptor instead. func (*ListOORSessionsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{90} + return file_daemon_proto_rawDescGZIP(), []int{102} } func (x *ListOORSessionsResponse) GetSessions() []*OORSessionInfo { @@ -7773,7 +8459,7 @@ type GetOORSessionRequest struct { func (x *GetOORSessionRequest) Reset() { *x = GetOORSessionRequest{} - mi := &file_daemon_proto_msgTypes[91] + mi := &file_daemon_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7785,7 +8471,7 @@ func (x *GetOORSessionRequest) String() string { func (*GetOORSessionRequest) ProtoMessage() {} func (x *GetOORSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[91] + mi := &file_daemon_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7798,7 +8484,7 @@ func (x *GetOORSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetOORSessionRequest.ProtoReflect.Descriptor instead. func (*GetOORSessionRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{91} + return file_daemon_proto_rawDescGZIP(), []int{103} } func (x *GetOORSessionRequest) GetSessionId() string { @@ -7818,7 +8504,7 @@ type GetOORSessionResponse struct { func (x *GetOORSessionResponse) Reset() { *x = GetOORSessionResponse{} - mi := &file_daemon_proto_msgTypes[92] + mi := &file_daemon_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7830,7 +8516,7 @@ func (x *GetOORSessionResponse) String() string { func (*GetOORSessionResponse) ProtoMessage() {} func (x *GetOORSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[92] + mi := &file_daemon_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7843,7 +8529,7 @@ func (x *GetOORSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetOORSessionResponse.ProtoReflect.Descriptor instead. func (*GetOORSessionResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{92} + return file_daemon_proto_rawDescGZIP(), []int{104} } func (x *GetOORSessionResponse) GetSession() *OORSessionInfo { @@ -7871,7 +8557,7 @@ type EstimateFeeRequest struct { func (x *EstimateFeeRequest) Reset() { *x = EstimateFeeRequest{} - mi := &file_daemon_proto_msgTypes[93] + mi := &file_daemon_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7883,7 +8569,7 @@ func (x *EstimateFeeRequest) String() string { func (*EstimateFeeRequest) ProtoMessage() {} func (x *EstimateFeeRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[93] + mi := &file_daemon_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7896,7 +8582,7 @@ func (x *EstimateFeeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EstimateFeeRequest.ProtoReflect.Descriptor instead. func (*EstimateFeeRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{93} + return file_daemon_proto_rawDescGZIP(), []int{105} } func (x *EstimateFeeRequest) GetAmountSat() int64 { @@ -7950,7 +8636,7 @@ type EstimateFeeResponse struct { func (x *EstimateFeeResponse) Reset() { *x = EstimateFeeResponse{} - mi := &file_daemon_proto_msgTypes[94] + mi := &file_daemon_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7962,7 +8648,7 @@ func (x *EstimateFeeResponse) String() string { func (*EstimateFeeResponse) ProtoMessage() {} func (x *EstimateFeeResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[94] + mi := &file_daemon_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7975,7 +8661,7 @@ func (x *EstimateFeeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EstimateFeeResponse.ProtoReflect.Descriptor instead. func (*EstimateFeeResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{94} + return file_daemon_proto_rawDescGZIP(), []int{106} } func (x *EstimateFeeResponse) GetLiquidityFeeSat() int64 { @@ -8045,7 +8731,7 @@ type GetFeeHistoryRequest struct { func (x *GetFeeHistoryRequest) Reset() { *x = GetFeeHistoryRequest{} - mi := &file_daemon_proto_msgTypes[95] + mi := &file_daemon_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8057,7 +8743,7 @@ func (x *GetFeeHistoryRequest) String() string { func (*GetFeeHistoryRequest) ProtoMessage() {} func (x *GetFeeHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[95] + mi := &file_daemon_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8070,7 +8756,7 @@ func (x *GetFeeHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFeeHistoryRequest.ProtoReflect.Descriptor instead. func (*GetFeeHistoryRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{95} + return file_daemon_proto_rawDescGZIP(), []int{107} } func (x *GetFeeHistoryRequest) GetLimit() uint32 { @@ -8145,7 +8831,7 @@ type FeeHistoryEntry struct { func (x *FeeHistoryEntry) Reset() { *x = FeeHistoryEntry{} - mi := &file_daemon_proto_msgTypes[96] + mi := &file_daemon_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8157,7 +8843,7 @@ func (x *FeeHistoryEntry) String() string { func (*FeeHistoryEntry) ProtoMessage() {} func (x *FeeHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[96] + mi := &file_daemon_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8170,7 +8856,7 @@ func (x *FeeHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use FeeHistoryEntry.ProtoReflect.Descriptor instead. func (*FeeHistoryEntry) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{96} + return file_daemon_proto_rawDescGZIP(), []int{108} } func (x *FeeHistoryEntry) GetEntryId() int64 { @@ -8250,7 +8936,7 @@ type GetFeeHistoryResponse struct { func (x *GetFeeHistoryResponse) Reset() { *x = GetFeeHistoryResponse{} - mi := &file_daemon_proto_msgTypes[97] + mi := &file_daemon_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8262,7 +8948,7 @@ func (x *GetFeeHistoryResponse) String() string { func (*GetFeeHistoryResponse) ProtoMessage() {} func (x *GetFeeHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[97] + mi := &file_daemon_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8275,7 +8961,7 @@ func (x *GetFeeHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFeeHistoryResponse.ProtoReflect.Descriptor instead. func (*GetFeeHistoryResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{97} + return file_daemon_proto_rawDescGZIP(), []int{109} } func (x *GetFeeHistoryResponse) GetEntries() []*FeeHistoryEntry { @@ -8316,7 +9002,7 @@ type ListTransactionsRequest struct { func (x *ListTransactionsRequest) Reset() { *x = ListTransactionsRequest{} - mi := &file_daemon_proto_msgTypes[98] + mi := &file_daemon_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8328,7 +9014,7 @@ func (x *ListTransactionsRequest) String() string { func (*ListTransactionsRequest) ProtoMessage() {} func (x *ListTransactionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[98] + mi := &file_daemon_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8341,7 +9027,7 @@ func (x *ListTransactionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTransactionsRequest.ProtoReflect.Descriptor instead. func (*ListTransactionsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{98} + return file_daemon_proto_rawDescGZIP(), []int{110} } func (x *ListTransactionsRequest) GetFromUnixS() int64 { @@ -8432,7 +9118,7 @@ type TransactionHistoryEntry struct { func (x *TransactionHistoryEntry) Reset() { *x = TransactionHistoryEntry{} - mi := &file_daemon_proto_msgTypes[99] + mi := &file_daemon_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8444,7 +9130,7 @@ func (x *TransactionHistoryEntry) String() string { func (*TransactionHistoryEntry) ProtoMessage() {} func (x *TransactionHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[99] + mi := &file_daemon_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8457,7 +9143,7 @@ func (x *TransactionHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionHistoryEntry.ProtoReflect.Descriptor instead. func (*TransactionHistoryEntry) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{99} + return file_daemon_proto_rawDescGZIP(), []int{111} } func (x *TransactionHistoryEntry) GetSource() string { @@ -8594,7 +9280,7 @@ type ListTransactionsResponse struct { func (x *ListTransactionsResponse) Reset() { *x = ListTransactionsResponse{} - mi := &file_daemon_proto_msgTypes[100] + mi := &file_daemon_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8606,7 +9292,7 @@ func (x *ListTransactionsResponse) String() string { func (*ListTransactionsResponse) ProtoMessage() {} func (x *ListTransactionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[100] + mi := &file_daemon_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8619,7 +9305,7 @@ func (x *ListTransactionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTransactionsResponse.ProtoReflect.Descriptor instead. func (*ListTransactionsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{100} + return file_daemon_proto_rawDescGZIP(), []int{112} } func (x *ListTransactionsResponse) GetTransactions() []*TransactionHistoryEntry { @@ -8654,7 +9340,7 @@ type UnrollRequest struct { func (x *UnrollRequest) Reset() { *x = UnrollRequest{} - mi := &file_daemon_proto_msgTypes[101] + mi := &file_daemon_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8666,7 +9352,7 @@ func (x *UnrollRequest) String() string { func (*UnrollRequest) ProtoMessage() {} func (x *UnrollRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[101] + mi := &file_daemon_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8679,7 +9365,7 @@ func (x *UnrollRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollRequest.ProtoReflect.Descriptor instead. func (*UnrollRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{101} + return file_daemon_proto_rawDescGZIP(), []int{113} } func (x *UnrollRequest) GetOutpoint() string { @@ -8702,7 +9388,7 @@ type UnrollResponse struct { func (x *UnrollResponse) Reset() { *x = UnrollResponse{} - mi := &file_daemon_proto_msgTypes[102] + mi := &file_daemon_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8714,7 +9400,7 @@ func (x *UnrollResponse) String() string { func (*UnrollResponse) ProtoMessage() {} func (x *UnrollResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[102] + mi := &file_daemon_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8727,7 +9413,7 @@ func (x *UnrollResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollResponse.ProtoReflect.Descriptor instead. func (*UnrollResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{102} + return file_daemon_proto_rawDescGZIP(), []int{114} } func (x *UnrollResponse) GetCreated() bool { @@ -8759,7 +9445,7 @@ type GetUnrollStatusRequest struct { func (x *GetUnrollStatusRequest) Reset() { *x = GetUnrollStatusRequest{} - mi := &file_daemon_proto_msgTypes[103] + mi := &file_daemon_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8771,7 +9457,7 @@ func (x *GetUnrollStatusRequest) String() string { func (*GetUnrollStatusRequest) ProtoMessage() {} func (x *GetUnrollStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[103] + mi := &file_daemon_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8784,7 +9470,7 @@ func (x *GetUnrollStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUnrollStatusRequest.ProtoReflect.Descriptor instead. func (*GetUnrollStatusRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{103} + return file_daemon_proto_rawDescGZIP(), []int{115} } func (x *GetUnrollStatusRequest) GetOutpoint() string { @@ -8836,7 +9522,7 @@ type UnrollProgress struct { func (x *UnrollProgress) Reset() { *x = UnrollProgress{} - mi := &file_daemon_proto_msgTypes[104] + mi := &file_daemon_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8848,7 +9534,7 @@ func (x *UnrollProgress) String() string { func (*UnrollProgress) ProtoMessage() {} func (x *UnrollProgress) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[104] + mi := &file_daemon_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8861,7 +9547,7 @@ func (x *UnrollProgress) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollProgress.ProtoReflect.Descriptor instead. func (*UnrollProgress) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{104} + return file_daemon_proto_rawDescGZIP(), []int{116} } func (x *UnrollProgress) GetConfirmedTxs() uint32 { @@ -8946,7 +9632,7 @@ type UnrollCSV struct { func (x *UnrollCSV) Reset() { *x = UnrollCSV{} - mi := &file_daemon_proto_msgTypes[105] + mi := &file_daemon_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8958,7 +9644,7 @@ func (x *UnrollCSV) String() string { func (*UnrollCSV) ProtoMessage() {} func (x *UnrollCSV) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[105] + mi := &file_daemon_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8971,7 +9657,7 @@ func (x *UnrollCSV) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollCSV.ProtoReflect.Descriptor instead. func (*UnrollCSV) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{105} + return file_daemon_proto_rawDescGZIP(), []int{117} } func (x *UnrollCSV) GetTargetConfirmHeight() int32 { @@ -9036,7 +9722,7 @@ type UnrollFees struct { func (x *UnrollFees) Reset() { *x = UnrollFees{} - mi := &file_daemon_proto_msgTypes[106] + mi := &file_daemon_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9048,7 +9734,7 @@ func (x *UnrollFees) String() string { func (*UnrollFees) ProtoMessage() {} func (x *UnrollFees) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[106] + mi := &file_daemon_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9061,7 +9747,7 @@ func (x *UnrollFees) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollFees.ProtoReflect.Descriptor instead. func (*UnrollFees) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{106} + return file_daemon_proto_rawDescGZIP(), []int{118} } func (x *UnrollFees) GetCpfpFeeSat() int64 { @@ -9163,7 +9849,7 @@ type GetUnrollStatusResponse struct { func (x *GetUnrollStatusResponse) Reset() { *x = GetUnrollStatusResponse{} - mi := &file_daemon_proto_msgTypes[107] + mi := &file_daemon_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9175,7 +9861,7 @@ func (x *GetUnrollStatusResponse) String() string { func (*GetUnrollStatusResponse) ProtoMessage() {} func (x *GetUnrollStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[107] + mi := &file_daemon_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9188,7 +9874,7 @@ func (x *GetUnrollStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUnrollStatusResponse.ProtoReflect.Descriptor instead. func (*GetUnrollStatusResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{107} + return file_daemon_proto_rawDescGZIP(), []int{119} } func (x *GetUnrollStatusResponse) GetFound() bool { @@ -9319,7 +10005,7 @@ type ArmVHTLCRecoveryRequest struct { func (x *ArmVHTLCRecoveryRequest) Reset() { *x = ArmVHTLCRecoveryRequest{} - mi := &file_daemon_proto_msgTypes[108] + mi := &file_daemon_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9331,7 +10017,7 @@ func (x *ArmVHTLCRecoveryRequest) String() string { func (*ArmVHTLCRecoveryRequest) ProtoMessage() {} func (x *ArmVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[108] + mi := &file_daemon_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9344,7 +10030,7 @@ func (x *ArmVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ArmVHTLCRecoveryRequest.ProtoReflect.Descriptor instead. func (*ArmVHTLCRecoveryRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{108} + return file_daemon_proto_rawDescGZIP(), []int{120} } func (x *ArmVHTLCRecoveryRequest) GetRequestId() string { @@ -9487,7 +10173,7 @@ type ArmVHTLCRecoveryResponse struct { func (x *ArmVHTLCRecoveryResponse) Reset() { *x = ArmVHTLCRecoveryResponse{} - mi := &file_daemon_proto_msgTypes[109] + mi := &file_daemon_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9499,7 +10185,7 @@ func (x *ArmVHTLCRecoveryResponse) String() string { func (*ArmVHTLCRecoveryResponse) ProtoMessage() {} func (x *ArmVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[109] + mi := &file_daemon_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9512,7 +10198,7 @@ func (x *ArmVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ArmVHTLCRecoveryResponse.ProtoReflect.Descriptor instead. func (*ArmVHTLCRecoveryResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{109} + return file_daemon_proto_rawDescGZIP(), []int{121} } func (x *ArmVHTLCRecoveryResponse) GetRecoveryId() string { @@ -9552,7 +10238,7 @@ type EscalateVHTLCRecoveryRequest struct { func (x *EscalateVHTLCRecoveryRequest) Reset() { *x = EscalateVHTLCRecoveryRequest{} - mi := &file_daemon_proto_msgTypes[110] + mi := &file_daemon_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9564,7 +10250,7 @@ func (x *EscalateVHTLCRecoveryRequest) String() string { func (*EscalateVHTLCRecoveryRequest) ProtoMessage() {} func (x *EscalateVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[110] + mi := &file_daemon_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9577,7 +10263,7 @@ func (x *EscalateVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EscalateVHTLCRecoveryRequest.ProtoReflect.Descriptor instead. func (*EscalateVHTLCRecoveryRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{110} + return file_daemon_proto_rawDescGZIP(), []int{122} } func (x *EscalateVHTLCRecoveryRequest) GetRecoveryId() string { @@ -9611,7 +10297,7 @@ type EscalateVHTLCRecoveryResponse struct { func (x *EscalateVHTLCRecoveryResponse) Reset() { *x = EscalateVHTLCRecoveryResponse{} - mi := &file_daemon_proto_msgTypes[111] + mi := &file_daemon_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9623,7 +10309,7 @@ func (x *EscalateVHTLCRecoveryResponse) String() string { func (*EscalateVHTLCRecoveryResponse) ProtoMessage() {} func (x *EscalateVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[111] + mi := &file_daemon_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9636,7 +10322,7 @@ func (x *EscalateVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EscalateVHTLCRecoveryResponse.ProtoReflect.Descriptor instead. func (*EscalateVHTLCRecoveryResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{111} + return file_daemon_proto_rawDescGZIP(), []int{123} } func (x *EscalateVHTLCRecoveryResponse) GetStatus() *VHTLCRecoveryStatus { @@ -9660,7 +10346,7 @@ type CancelVHTLCRecoveryRequest struct { func (x *CancelVHTLCRecoveryRequest) Reset() { *x = CancelVHTLCRecoveryRequest{} - mi := &file_daemon_proto_msgTypes[112] + mi := &file_daemon_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9672,7 +10358,7 @@ func (x *CancelVHTLCRecoveryRequest) String() string { func (*CancelVHTLCRecoveryRequest) ProtoMessage() {} func (x *CancelVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[112] + mi := &file_daemon_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9685,7 +10371,7 @@ func (x *CancelVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelVHTLCRecoveryRequest.ProtoReflect.Descriptor instead. func (*CancelVHTLCRecoveryRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{112} + return file_daemon_proto_rawDescGZIP(), []int{124} } func (x *CancelVHTLCRecoveryRequest) GetRecoveryId() string { @@ -9719,7 +10405,7 @@ type CancelVHTLCRecoveryResponse struct { func (x *CancelVHTLCRecoveryResponse) Reset() { *x = CancelVHTLCRecoveryResponse{} - mi := &file_daemon_proto_msgTypes[113] + mi := &file_daemon_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9731,7 +10417,7 @@ func (x *CancelVHTLCRecoveryResponse) String() string { func (*CancelVHTLCRecoveryResponse) ProtoMessage() {} func (x *CancelVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[113] + mi := &file_daemon_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9744,7 +10430,7 @@ func (x *CancelVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelVHTLCRecoveryResponse.ProtoReflect.Descriptor instead. func (*CancelVHTLCRecoveryResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{113} + return file_daemon_proto_rawDescGZIP(), []int{125} } func (x *CancelVHTLCRecoveryResponse) GetStatus() *VHTLCRecoveryStatus { @@ -9764,7 +10450,7 @@ type GetVHTLCRecoveryStatusRequest struct { func (x *GetVHTLCRecoveryStatusRequest) Reset() { *x = GetVHTLCRecoveryStatusRequest{} - mi := &file_daemon_proto_msgTypes[114] + mi := &file_daemon_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9776,7 +10462,7 @@ func (x *GetVHTLCRecoveryStatusRequest) String() string { func (*GetVHTLCRecoveryStatusRequest) ProtoMessage() {} func (x *GetVHTLCRecoveryStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[114] + mi := &file_daemon_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9789,7 +10475,7 @@ func (x *GetVHTLCRecoveryStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetVHTLCRecoveryStatusRequest.ProtoReflect.Descriptor instead. func (*GetVHTLCRecoveryStatusRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{114} + return file_daemon_proto_rawDescGZIP(), []int{126} } func (x *GetVHTLCRecoveryStatusRequest) GetRecoveryId() string { @@ -9811,7 +10497,7 @@ type GetVHTLCRecoveryStatusResponse struct { func (x *GetVHTLCRecoveryStatusResponse) Reset() { *x = GetVHTLCRecoveryStatusResponse{} - mi := &file_daemon_proto_msgTypes[115] + mi := &file_daemon_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9823,7 +10509,7 @@ func (x *GetVHTLCRecoveryStatusResponse) String() string { func (*GetVHTLCRecoveryStatusResponse) ProtoMessage() {} func (x *GetVHTLCRecoveryStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[115] + mi := &file_daemon_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9836,7 +10522,7 @@ func (x *GetVHTLCRecoveryStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetVHTLCRecoveryStatusResponse.ProtoReflect.Descriptor instead. func (*GetVHTLCRecoveryStatusResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{115} + return file_daemon_proto_rawDescGZIP(), []int{127} } func (x *GetVHTLCRecoveryStatusResponse) GetFound() bool { @@ -9863,7 +10549,7 @@ type ListVHTLCRecoveriesRequest struct { func (x *ListVHTLCRecoveriesRequest) Reset() { *x = ListVHTLCRecoveriesRequest{} - mi := &file_daemon_proto_msgTypes[116] + mi := &file_daemon_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9875,7 +10561,7 @@ func (x *ListVHTLCRecoveriesRequest) String() string { func (*ListVHTLCRecoveriesRequest) ProtoMessage() {} func (x *ListVHTLCRecoveriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[116] + mi := &file_daemon_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9888,7 +10574,7 @@ func (x *ListVHTLCRecoveriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListVHTLCRecoveriesRequest.ProtoReflect.Descriptor instead. func (*ListVHTLCRecoveriesRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{116} + return file_daemon_proto_rawDescGZIP(), []int{128} } func (x *ListVHTLCRecoveriesRequest) GetIncludeTerminal() bool { @@ -9908,7 +10594,7 @@ type ListVHTLCRecoveriesResponse struct { func (x *ListVHTLCRecoveriesResponse) Reset() { *x = ListVHTLCRecoveriesResponse{} - mi := &file_daemon_proto_msgTypes[117] + mi := &file_daemon_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9920,7 +10606,7 @@ func (x *ListVHTLCRecoveriesResponse) String() string { func (*ListVHTLCRecoveriesResponse) ProtoMessage() {} func (x *ListVHTLCRecoveriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[117] + mi := &file_daemon_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9933,7 +10619,7 @@ func (x *ListVHTLCRecoveriesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListVHTLCRecoveriesResponse.ProtoReflect.Descriptor instead. func (*ListVHTLCRecoveriesResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{117} + return file_daemon_proto_rawDescGZIP(), []int{129} } func (x *ListVHTLCRecoveriesResponse) GetStatuses() []*VHTLCRecoveryStatus { @@ -10008,7 +10694,7 @@ type VHTLCRecoveryStatus struct { func (x *VHTLCRecoveryStatus) Reset() { *x = VHTLCRecoveryStatus{} - mi := &file_daemon_proto_msgTypes[118] + mi := &file_daemon_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10020,7 +10706,7 @@ func (x *VHTLCRecoveryStatus) String() string { func (*VHTLCRecoveryStatus) ProtoMessage() {} func (x *VHTLCRecoveryStatus) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[118] + mi := &file_daemon_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10033,7 +10719,7 @@ func (x *VHTLCRecoveryStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use VHTLCRecoveryStatus.ProtoReflect.Descriptor instead. func (*VHTLCRecoveryStatus) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{118} + return file_daemon_proto_rawDescGZIP(), []int{130} } func (x *VHTLCRecoveryStatus) GetRecoveryId() string { @@ -10225,7 +10911,7 @@ type SignOutSwapHtlcAckRequest struct { func (x *SignOutSwapHtlcAckRequest) Reset() { *x = SignOutSwapHtlcAckRequest{} - mi := &file_daemon_proto_msgTypes[119] + mi := &file_daemon_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10237,7 +10923,7 @@ func (x *SignOutSwapHtlcAckRequest) String() string { func (*SignOutSwapHtlcAckRequest) ProtoMessage() {} func (x *SignOutSwapHtlcAckRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[119] + mi := &file_daemon_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10250,7 +10936,7 @@ func (x *SignOutSwapHtlcAckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SignOutSwapHtlcAckRequest.ProtoReflect.Descriptor instead. func (*SignOutSwapHtlcAckRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{119} + return file_daemon_proto_rawDescGZIP(), []int{131} } func (x *SignOutSwapHtlcAckRequest) GetPaymentHash() []byte { @@ -10284,7 +10970,7 @@ type SignOutSwapHtlcAckResponse struct { func (x *SignOutSwapHtlcAckResponse) Reset() { *x = SignOutSwapHtlcAckResponse{} - mi := &file_daemon_proto_msgTypes[120] + mi := &file_daemon_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10296,7 +10982,7 @@ func (x *SignOutSwapHtlcAckResponse) String() string { func (*SignOutSwapHtlcAckResponse) ProtoMessage() {} func (x *SignOutSwapHtlcAckResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[120] + mi := &file_daemon_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10309,7 +10995,7 @@ func (x *SignOutSwapHtlcAckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SignOutSwapHtlcAckResponse.ProtoReflect.Descriptor instead. func (*SignOutSwapHtlcAckResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{120} + return file_daemon_proto_rawDescGZIP(), []int{132} } func (x *SignOutSwapHtlcAckResponse) GetSignature() []byte { @@ -10337,7 +11023,7 @@ type SignCreditAccountAuthorizationRequest struct { func (x *SignCreditAccountAuthorizationRequest) Reset() { *x = SignCreditAccountAuthorizationRequest{} - mi := &file_daemon_proto_msgTypes[121] + mi := &file_daemon_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10349,7 +11035,7 @@ func (x *SignCreditAccountAuthorizationRequest) String() string { func (*SignCreditAccountAuthorizationRequest) ProtoMessage() {} func (x *SignCreditAccountAuthorizationRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[121] + mi := &file_daemon_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10362,7 +11048,7 @@ func (x *SignCreditAccountAuthorizationRequest) ProtoReflect() protoreflect.Mess // Deprecated: Use SignCreditAccountAuthorizationRequest.ProtoReflect.Descriptor instead. func (*SignCreditAccountAuthorizationRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{121} + return file_daemon_proto_rawDescGZIP(), []int{133} } func (x *SignCreditAccountAuthorizationRequest) GetRequestDigest() []byte { @@ -10403,7 +11089,7 @@ type SignCreditAccountAuthorizationResponse struct { func (x *SignCreditAccountAuthorizationResponse) Reset() { *x = SignCreditAccountAuthorizationResponse{} - mi := &file_daemon_proto_msgTypes[122] + mi := &file_daemon_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10415,7 +11101,7 @@ func (x *SignCreditAccountAuthorizationResponse) String() string { func (*SignCreditAccountAuthorizationResponse) ProtoMessage() {} func (x *SignCreditAccountAuthorizationResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[122] + mi := &file_daemon_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10428,7 +11114,7 @@ func (x *SignCreditAccountAuthorizationResponse) ProtoReflect() protoreflect.Mes // Deprecated: Use SignCreditAccountAuthorizationResponse.ProtoReflect.Descriptor instead. func (*SignCreditAccountAuthorizationResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{122} + return file_daemon_proto_rawDescGZIP(), []int{134} } func (x *SignCreditAccountAuthorizationResponse) GetSignature() []byte { @@ -10442,7 +11128,7 @@ var File_daemon_proto protoreflect.FileDescriptor const file_daemon_proto_rawDesc = "" + "\n" + - "\fdaemon.proto\x12\awaverpc\"\x10\n" + + "\fdaemon.proto\x12\awaverpc\x1a#rpc/arkchannelrpc/ark_channel.proto\"\x10\n" + "\x0eGetInfoRequest\"\xb1\x03\n" + "\x0fGetInfoResponse\x12\x18\n" + "\aversion\x18\x01 \x01(\tR\aversion\x12\x16\n" + @@ -10555,10 +11241,11 @@ const file_daemon_proto_rawDesc = "" + "\x05vtxos\x18\x01 \x03(\v2\r.waverpc.VTXOR\x05vtxos\"\x13\n" + "\x11NewAddressRequest\".\n" + "\x12NewAddressResponse\x12\x18\n" + - "\aaddress\x18\x01 \x01(\tR\aaddress\"X\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\"{\n" + "\x17NewReceiveScriptRequest\x12\x14\n" + "\x05label\x18\x01 \x01(\tR\x05label\x12'\n" + - "\x0fidempotency_key\x18\x02 \x01(\tR\x0eidempotencyKey\"\xe5\x01\n" + + "\x0fidempotency_key\x18\x02 \x01(\tR\x0eidempotencyKey\x12!\n" + + "\fidentity_key\x18\x03 \x01(\bR\videntityKey\"\xe5\x01\n" + "\x18NewReceiveScriptResponse\x12\"\n" + "\rpk_script_hex\x18\x01 \x01(\tR\vpkScriptHex\x12(\n" + "\x10pubkey_xonly_hex\x18\x02 \x01(\tR\x0epubkeyXonlyHex\x12\x1d\n" + @@ -10672,7 +11359,44 @@ const file_daemon_proto_rawDesc = "" + "\x10checkpoint_psbts\x18\x02 \x03(\fR\x0fcheckpointPsbts\x12D\n" + "\rcustom_inputs\x18\x03 \x03(\v2\x1f.waverpc.PreparedOORCustomInputR\fcustomInputs\x12\x1d\n" + "\n" + - "session_id\x18\x04 \x01(\tR\tsessionId\"\x80\x01\n" + + "session_id\x18\x04 \x01(\tR\tsessionId\"[\n" + + "\x1fExportOORRecoveryPackageRequest\x128\n" + + "\x06source\x18\x01 \x01(\v2 .arkchannelrpc.OORRecoverySourceR\x06source\"e\n" + + " ExportOORRecoveryPackageResponse\x12A\n" + + "\brecovery\x18\x01 \x01(\v2%.arkchannelrpc.ChannelRecoveryPackageR\brecovery\"P\n" + + "\x1bPrepareArkChannelOORRequest\x121\n" + + "\x05terms\x18\x01 \x01(\v2\x1b.arkchannelrpc.ChannelTermsR\x05terms\"[\n" + + "\x1cPrepareArkChannelOORResponse\x12;\n" + + "\abinding\x18\x01 \x01(\v2!.arkchannelrpc.ChannelVTXOBindingR\abinding\"W\n" + + "\"LookupPreparedArkChannelOORRequest\x121\n" + + "\x05terms\x18\x01 \x01(\v2\x1b.arkchannelrpc.ChannelTermsR\x05terms\"\xa3\x01\n" + + "#LookupPreparedArkChannelOORResponse\x12?\n" + + "\x06status\x18\x01 \x01(\x0e2'.waverpc.ArkChannelOORPreparationStatusR\x06status\x12;\n" + + "\abinding\x18\x02 \x01(\v2!.arkchannelrpc.ChannelVTXOBindingR\abinding\"\x96\x01\n" + + "$ValidatePreparedArkChannelOORRequest\x121\n" + + "\x05terms\x18\x01 \x01(\v2\x1b.arkchannelrpc.ChannelTermsR\x05terms\x12;\n" + + "\abinding\x18\x02 \x01(\v2!.arkchannelrpc.ChannelVTXOBindingR\abinding\"=\n" + + "%ValidatePreparedArkChannelOORResponse\x12\x14\n" + + "\x05valid\x18\x01 \x01(\bR\x05valid\"\xb3\x01\n" + + "\"CommitPreparedArkChannelOORRequest\x12\x1d\n" + + "\n" + + "channel_id\x18\x01 \x01(\fR\tchannelId\x121\n" + + "\x05terms\x18\x02 \x01(\v2\x1b.arkchannelrpc.ChannelTermsR\x05terms\x12;\n" + + "\abinding\x18\x03 \x01(\v2!.arkchannelrpc.ChannelVTXOBindingR\abinding\"u\n" + + "#CommitPreparedArkChannelOORResponse\x12\x1c\n" + + "\tfinalized\x18\x01 \x01(\bR\tfinalized\x12\x18\n" + + "\aaborted\x18\x02 \x01(\bR\aaborted\x12\x16\n" + + "\x06reason\x18\x03 \x01(\tR\x06reason\"\xca\x01\n" + + "!AbortPreparedArkChannelOORRequest\x12\x1d\n" + + "\n" + + "channel_id\x18\x01 \x01(\fR\tchannelId\x121\n" + + "\x05terms\x18\x02 \x01(\v2\x1b.arkchannelrpc.ChannelTermsR\x05terms\x12;\n" + + "\abinding\x18\x03 \x01(\v2!.arkchannelrpc.ChannelVTXOBindingR\abinding\x12\x16\n" + + "\x06reason\x18\x04 \x01(\tR\x06reason\"t\n" + + "\"AbortPreparedArkChannelOORResponse\x12\x18\n" + + "\aaborted\x18\x01 \x01(\bR\aaborted\x12\x16\n" + + "\x06reason\x18\x02 \x01(\tR\x06reason\x12\x1c\n" + + "\tfinalized\x18\x03 \x01(\bR\tfinalized\"\x80\x01\n" + "\x19SignOORCustomInputRequest\x12:\n" + "\fcustom_input\x18\x01 \x01(\v2\x17.waverpc.CustomOORInputR\vcustomInput\x12'\n" + "\x0fcheckpoint_psbt\x18\x02 \x01(\fR\x0echeckpointPsbt\"[\n" + @@ -11178,7 +11902,13 @@ const file_daemon_proto_rawDesc = "" + "\x17VTXO_EXPIRY_STATUS_SAFE\x10\x01\x12$\n" + " VTXO_EXPIRY_STATUS_NEEDS_REFRESH\x10\x02\x12\x1f\n" + "\x1bVTXO_EXPIRY_STATUS_CRITICAL\x10\x03\x12\x1e\n" + - "\x1aVTXO_EXPIRY_STATUS_EXPIRED\x10\x04*\x8f\x01\n" + + "\x1aVTXO_EXPIRY_STATUS_EXPIRED\x10\x04*\x95\x02\n" + + "\x1eArkChannelOORPreparationStatus\x122\n" + + ".ARK_CHANNEL_OOR_PREPARATION_STATUS_UNSPECIFIED\x10\x00\x12-\n" + + ")ARK_CHANNEL_OOR_PREPARATION_STATUS_ABSENT\x10\x01\x12.\n" + + "*ARK_CHANNEL_OOR_PREPARATION_STATUS_PENDING\x10\x02\x12/\n" + + "+ARK_CHANNEL_OOR_PREPARATION_STATUS_PREPARED\x10\x03\x12/\n" + + "+ARK_CHANNEL_OOR_PREPARATION_STATUS_ACCEPTED\x10\x04*\x8f\x01\n" + "\x13ForfeitSigningRoute\x12%\n" + "!FORFEIT_SIGNING_ROUTE_UNSPECIFIED\x10\x00\x12&\n" + "\"FORFEIT_SIGNING_ROUTE_LOCAL_SIGNER\x10\x01\x12)\n" + @@ -11242,7 +11972,7 @@ const file_daemon_proto_rawDesc = "" + "\x1eVHTLC_RECOVERY_STATE_COMPLETED\x10\t\x12\"\n" + "\x1eVHTLC_RECOVERY_STATE_CANCELLED\x10\n" + "\x12\x1f\n" + - "\x1bVHTLC_RECOVERY_STATE_FAILED\x10\v2\xb5 \n" + + "\x1bVHTLC_RECOVERY_STATE_FAILED\x10\v2\xf6%\n" + "\rDaemonService\x12<\n" + "\aGetInfo\x12\x17.waverpc.GetInfoRequest\x1a\x18.waverpc.GetInfoResponse\x12<\n" + "\aGenSeed\x12\x17.waverpc.GenSeedRequest\x1a\x18.waverpc.GenSeedResponse\x12E\n" + @@ -11261,7 +11991,13 @@ const file_daemon_proto_rawDesc = "" + "\x0fReceiveAuthECDH\x12\x1f.waverpc.ReceiveAuthECDHRequest\x1a .waverpc.ReceiveAuthECDHResponse\x12o\n" + "\x18GetIndexedVTXOByPkScript\x12(.waverpc.GetIndexedVTXOByPkScriptRequest\x1a).waverpc.GetIndexedVTXOByPkScriptResponse\x12Z\n" + "\x11GetVTXOExpiryInfo\x12!.waverpc.GetVTXOExpiryInfoRequest\x1a\".waverpc.GetVTXOExpiryInfoResponse\x12u\n" + - "\x1aGetIndexedOORSessionByTxid\x12*.waverpc.GetIndexedOORSessionByTxidRequest\x1a+.waverpc.GetIndexedOORSessionByTxidResponse\x12?\n" + + "\x1aGetIndexedOORSessionByTxid\x12*.waverpc.GetIndexedOORSessionByTxidRequest\x1a+.waverpc.GetIndexedOORSessionByTxidResponse\x12o\n" + + "\x18ExportOORRecoveryPackage\x12(.waverpc.ExportOORRecoveryPackageRequest\x1a).waverpc.ExportOORRecoveryPackageResponse\x12c\n" + + "\x14PrepareArkChannelOOR\x12$.waverpc.PrepareArkChannelOORRequest\x1a%.waverpc.PrepareArkChannelOORResponse\x12x\n" + + "\x1bLookupPreparedArkChannelOOR\x12+.waverpc.LookupPreparedArkChannelOORRequest\x1a,.waverpc.LookupPreparedArkChannelOORResponse\x12~\n" + + "\x1dValidatePreparedArkChannelOOR\x12-.waverpc.ValidatePreparedArkChannelOORRequest\x1a..waverpc.ValidatePreparedArkChannelOORResponse\x12x\n" + + "\x1bCommitPreparedArkChannelOOR\x12+.waverpc.CommitPreparedArkChannelOORRequest\x1a,.waverpc.CommitPreparedArkChannelOORResponse\x12u\n" + + "\x1aAbortPreparedArkChannelOOR\x12*.waverpc.AbortPreparedArkChannelOORRequest\x1a+.waverpc.AbortPreparedArkChannelOORResponse\x12?\n" + "\bSendVTXO\x12\x18.waverpc.SendVTXORequest\x1a\x19.waverpc.SendVTXOResponse\x12<\n" + "\aSendOOR\x12\x17.waverpc.SendOORRequest\x1a\x18.waverpc.SendOORResponse\x12E\n" + "\n" + @@ -11310,314 +12046,356 @@ func file_daemon_proto_rawDescGZIP() []byte { return file_daemon_proto_rawDescData } -var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 11) -var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 124) +var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 12) +var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 136) var file_daemon_proto_goTypes = []any{ (WalletState)(0), // 0: waverpc.WalletState (VTXOStatus)(0), // 1: waverpc.VTXOStatus (VTXOExpiryStatus)(0), // 2: waverpc.VTXOExpiryStatus - (ForfeitSigningRoute)(0), // 3: waverpc.ForfeitSigningRoute - (RoundState)(0), // 4: waverpc.RoundState - (OORSessionDirection)(0), // 5: waverpc.OORSessionDirection - (OORSessionStatus)(0), // 6: waverpc.OORSessionStatus - (UnrollJobStatus)(0), // 7: waverpc.UnrollJobStatus - (VHTLCRecoveryDirection)(0), // 8: waverpc.VHTLCRecoveryDirection - (VHTLCRecoveryAction)(0), // 9: waverpc.VHTLCRecoveryAction - (VHTLCRecoveryState)(0), // 10: waverpc.VHTLCRecoveryState - (*GetInfoRequest)(nil), // 11: waverpc.GetInfoRequest - (*GetInfoResponse)(nil), // 12: waverpc.GetInfoResponse - (*ServerInfo)(nil), // 13: waverpc.ServerInfo - (*GenSeedRequest)(nil), // 14: waverpc.GenSeedRequest - (*GenSeedResponse)(nil), // 15: waverpc.GenSeedResponse - (*InitWalletRequest)(nil), // 16: waverpc.InitWalletRequest - (*InitWalletResponse)(nil), // 17: waverpc.InitWalletResponse - (*UnlockWalletRequest)(nil), // 18: waverpc.UnlockWalletRequest - (*UnlockWalletResponse)(nil), // 19: waverpc.UnlockWalletResponse - (*GetBalanceRequest)(nil), // 20: waverpc.GetBalanceRequest - (*GetBalanceResponse)(nil), // 21: waverpc.GetBalanceResponse - (*VTXOExpiryInfo)(nil), // 22: waverpc.VTXOExpiryInfo - (*VTXO)(nil), // 23: waverpc.VTXO - (*VTXOSettlement)(nil), // 24: waverpc.VTXOSettlement - (*ListVTXOsRequest)(nil), // 25: waverpc.ListVTXOsRequest - (*ListVTXOsResponse)(nil), // 26: waverpc.ListVTXOsResponse - (*NewAddressRequest)(nil), // 27: waverpc.NewAddressRequest - (*NewAddressResponse)(nil), // 28: waverpc.NewAddressResponse - (*NewReceiveScriptRequest)(nil), // 29: waverpc.NewReceiveScriptRequest - (*NewReceiveScriptResponse)(nil), // 30: waverpc.NewReceiveScriptResponse - (*ReceiveAuthKeyRequest)(nil), // 31: waverpc.ReceiveAuthKeyRequest - (*ReceiveAuthKeyResponse)(nil), // 32: waverpc.ReceiveAuthKeyResponse - (*SignReceiveAuthMessageRequest)(nil), // 33: waverpc.SignReceiveAuthMessageRequest - (*SignReceiveAuthMessageResponse)(nil), // 34: waverpc.SignReceiveAuthMessageResponse - (*SignReceiveAuthMessageCompactRequest)(nil), // 35: waverpc.SignReceiveAuthMessageCompactRequest - (*SignReceiveAuthMessageCompactResponse)(nil), // 36: waverpc.SignReceiveAuthMessageCompactResponse - (*ReceiveAuthECDHRequest)(nil), // 37: waverpc.ReceiveAuthECDHRequest - (*ReceiveAuthECDHResponse)(nil), // 38: waverpc.ReceiveAuthECDHResponse - (*GetIndexedVTXOByPkScriptRequest)(nil), // 39: waverpc.GetIndexedVTXOByPkScriptRequest - (*GetIndexedVTXOByPkScriptResponse)(nil), // 40: waverpc.GetIndexedVTXOByPkScriptResponse - (*GetVTXOExpiryInfoRequest)(nil), // 41: waverpc.GetVTXOExpiryInfoRequest - (*GetVTXOExpiryInfoResponse)(nil), // 42: waverpc.GetVTXOExpiryInfoResponse - (*GetIndexedOORSessionByTxidRequest)(nil), // 43: waverpc.GetIndexedOORSessionByTxidRequest - (*GetIndexedOORSessionByTxidResponse)(nil), // 44: waverpc.GetIndexedOORSessionByTxidResponse - (*Output)(nil), // 45: waverpc.Output - (*SendVTXORequest)(nil), // 46: waverpc.SendVTXORequest - (*SendVTXOResponse)(nil), // 47: waverpc.SendVTXOResponse - (*SendOORRequest)(nil), // 48: waverpc.SendOORRequest - (*CustomOORInput)(nil), // 49: waverpc.CustomOORInput - (*TaprootScriptSignature)(nil), // 50: waverpc.TaprootScriptSignature - (*SendOORResponse)(nil), // 51: waverpc.SendOORResponse - (*PrepareOORRequest)(nil), // 52: waverpc.PrepareOORRequest - (*PreparedOORCustomInput)(nil), // 53: waverpc.PreparedOORCustomInput - (*PrepareOORResponse)(nil), // 54: waverpc.PrepareOORResponse - (*SignOORCustomInputRequest)(nil), // 55: waverpc.SignOORCustomInputRequest - (*SignOORCustomInputResponse)(nil), // 56: waverpc.SignOORCustomInputResponse - (*SignVTXOForfeitRequest)(nil), // 57: waverpc.SignVTXOForfeitRequest - (*SignVTXOForfeitResponse)(nil), // 58: waverpc.SignVTXOForfeitResponse - (*ForfeitSigningContext)(nil), // 59: waverpc.ForfeitSigningContext - (*OutpointSelection)(nil), // 60: waverpc.OutpointSelection - (*RefreshVTXOsRequest)(nil), // 61: waverpc.RefreshVTXOsRequest - (*RefreshVTXOsResponse)(nil), // 62: waverpc.RefreshVTXOsResponse - (*RefreshFeeEstimate)(nil), // 63: waverpc.RefreshFeeEstimate - (*OutpointFeeEstimate)(nil), // 64: waverpc.OutpointFeeEstimate - (*CustomRefreshVTXOInput)(nil), // 65: waverpc.CustomRefreshVTXOInput - (*CustomRefreshVTXOOutput)(nil), // 66: waverpc.CustomRefreshVTXOOutput - (*RefreshCustomVTXOsRequest)(nil), // 67: waverpc.RefreshCustomVTXOsRequest - (*RefreshCustomVTXOsResponse)(nil), // 68: waverpc.RefreshCustomVTXOsResponse - (*PendingForfeitParticipantSignatureRequest)(nil), // 69: waverpc.PendingForfeitParticipantSignatureRequest - (*ListPendingForfeitParticipantSignatureRequestsRequest)(nil), // 70: waverpc.ListPendingForfeitParticipantSignatureRequestsRequest - (*ListPendingForfeitParticipantSignatureRequestsResponse)(nil), // 71: waverpc.ListPendingForfeitParticipantSignatureRequestsResponse - (*ForfeitParticipantSignature)(nil), // 72: waverpc.ForfeitParticipantSignature - (*SubmitForfeitParticipantSignaturesRequest)(nil), // 73: waverpc.SubmitForfeitParticipantSignaturesRequest - (*SubmitForfeitParticipantSignaturesResponse)(nil), // 74: waverpc.SubmitForfeitParticipantSignaturesResponse - (*LeaveDestination)(nil), // 75: waverpc.LeaveDestination - (*LeaveVTXOsRequest)(nil), // 76: waverpc.LeaveVTXOsRequest - (*LeaveVTXOsResponse)(nil), // 77: waverpc.LeaveVTXOsResponse - (*SendOnChainRequest)(nil), // 78: waverpc.SendOnChainRequest - (*SendOnChainResponse)(nil), // 79: waverpc.SendOnChainResponse - (*BoardRequest)(nil), // 80: waverpc.BoardRequest - (*BoardResponse)(nil), // 81: waverpc.BoardResponse - (*JoinNextRoundRequest)(nil), // 82: waverpc.JoinNextRoundRequest - (*JoinNextRoundResponse)(nil), // 83: waverpc.JoinNextRoundResponse - (*SweepBoardingUTXOsRequest)(nil), // 84: waverpc.SweepBoardingUTXOsRequest - (*BoardingSweepOutput)(nil), // 85: waverpc.BoardingSweepOutput - (*SweepBoardingUTXOsResponse)(nil), // 86: waverpc.SweepBoardingUTXOsResponse - (*ListBoardingSweepsRequest)(nil), // 87: waverpc.ListBoardingSweepsRequest - (*BoardingSweepInput)(nil), // 88: waverpc.BoardingSweepInput - (*BoardingSweep)(nil), // 89: waverpc.BoardingSweep - (*ListBoardingSweepsResponse)(nil), // 90: waverpc.ListBoardingSweepsResponse - (*RoundVTXOInfo)(nil), // 91: waverpc.RoundVTXOInfo - (*RoundInfo)(nil), // 92: waverpc.RoundInfo - (*ListRoundsRequest)(nil), // 93: waverpc.ListRoundsRequest - (*GetRoundRequest)(nil), // 94: waverpc.GetRoundRequest - (*GetRoundResponse)(nil), // 95: waverpc.GetRoundResponse - (*ListRoundsResponse)(nil), // 96: waverpc.ListRoundsResponse - (*WatchRoundsRequest)(nil), // 97: waverpc.WatchRoundsRequest - (*WatchRoundsResponse)(nil), // 98: waverpc.WatchRoundsResponse - (*OORSessionInfo)(nil), // 99: waverpc.OORSessionInfo - (*ListOORSessionsRequest)(nil), // 100: waverpc.ListOORSessionsRequest - (*ListOORSessionsResponse)(nil), // 101: waverpc.ListOORSessionsResponse - (*GetOORSessionRequest)(nil), // 102: waverpc.GetOORSessionRequest - (*GetOORSessionResponse)(nil), // 103: waverpc.GetOORSessionResponse - (*EstimateFeeRequest)(nil), // 104: waverpc.EstimateFeeRequest - (*EstimateFeeResponse)(nil), // 105: waverpc.EstimateFeeResponse - (*GetFeeHistoryRequest)(nil), // 106: waverpc.GetFeeHistoryRequest - (*FeeHistoryEntry)(nil), // 107: waverpc.FeeHistoryEntry - (*GetFeeHistoryResponse)(nil), // 108: waverpc.GetFeeHistoryResponse - (*ListTransactionsRequest)(nil), // 109: waverpc.ListTransactionsRequest - (*TransactionHistoryEntry)(nil), // 110: waverpc.TransactionHistoryEntry - (*ListTransactionsResponse)(nil), // 111: waverpc.ListTransactionsResponse - (*UnrollRequest)(nil), // 112: waverpc.UnrollRequest - (*UnrollResponse)(nil), // 113: waverpc.UnrollResponse - (*GetUnrollStatusRequest)(nil), // 114: waverpc.GetUnrollStatusRequest - (*UnrollProgress)(nil), // 115: waverpc.UnrollProgress - (*UnrollCSV)(nil), // 116: waverpc.UnrollCSV - (*UnrollFees)(nil), // 117: waverpc.UnrollFees - (*GetUnrollStatusResponse)(nil), // 118: waverpc.GetUnrollStatusResponse - (*ArmVHTLCRecoveryRequest)(nil), // 119: waverpc.ArmVHTLCRecoveryRequest - (*ArmVHTLCRecoveryResponse)(nil), // 120: waverpc.ArmVHTLCRecoveryResponse - (*EscalateVHTLCRecoveryRequest)(nil), // 121: waverpc.EscalateVHTLCRecoveryRequest - (*EscalateVHTLCRecoveryResponse)(nil), // 122: waverpc.EscalateVHTLCRecoveryResponse - (*CancelVHTLCRecoveryRequest)(nil), // 123: waverpc.CancelVHTLCRecoveryRequest - (*CancelVHTLCRecoveryResponse)(nil), // 124: waverpc.CancelVHTLCRecoveryResponse - (*GetVHTLCRecoveryStatusRequest)(nil), // 125: waverpc.GetVHTLCRecoveryStatusRequest - (*GetVHTLCRecoveryStatusResponse)(nil), // 126: waverpc.GetVHTLCRecoveryStatusResponse - (*ListVHTLCRecoveriesRequest)(nil), // 127: waverpc.ListVHTLCRecoveriesRequest - (*ListVHTLCRecoveriesResponse)(nil), // 128: waverpc.ListVHTLCRecoveriesResponse - (*VHTLCRecoveryStatus)(nil), // 129: waverpc.VHTLCRecoveryStatus - (*SignOutSwapHtlcAckRequest)(nil), // 130: waverpc.SignOutSwapHtlcAckRequest - (*SignOutSwapHtlcAckResponse)(nil), // 131: waverpc.SignOutSwapHtlcAckResponse - (*SignCreditAccountAuthorizationRequest)(nil), // 132: waverpc.SignCreditAccountAuthorizationRequest - (*SignCreditAccountAuthorizationResponse)(nil), // 133: waverpc.SignCreditAccountAuthorizationResponse - nil, // 134: waverpc.LeaveVTXOsRequest.DestinationsEntry + (ArkChannelOORPreparationStatus)(0), // 3: waverpc.ArkChannelOORPreparationStatus + (ForfeitSigningRoute)(0), // 4: waverpc.ForfeitSigningRoute + (RoundState)(0), // 5: waverpc.RoundState + (OORSessionDirection)(0), // 6: waverpc.OORSessionDirection + (OORSessionStatus)(0), // 7: waverpc.OORSessionStatus + (UnrollJobStatus)(0), // 8: waverpc.UnrollJobStatus + (VHTLCRecoveryDirection)(0), // 9: waverpc.VHTLCRecoveryDirection + (VHTLCRecoveryAction)(0), // 10: waverpc.VHTLCRecoveryAction + (VHTLCRecoveryState)(0), // 11: waverpc.VHTLCRecoveryState + (*GetInfoRequest)(nil), // 12: waverpc.GetInfoRequest + (*GetInfoResponse)(nil), // 13: waverpc.GetInfoResponse + (*ServerInfo)(nil), // 14: waverpc.ServerInfo + (*GenSeedRequest)(nil), // 15: waverpc.GenSeedRequest + (*GenSeedResponse)(nil), // 16: waverpc.GenSeedResponse + (*InitWalletRequest)(nil), // 17: waverpc.InitWalletRequest + (*InitWalletResponse)(nil), // 18: waverpc.InitWalletResponse + (*UnlockWalletRequest)(nil), // 19: waverpc.UnlockWalletRequest + (*UnlockWalletResponse)(nil), // 20: waverpc.UnlockWalletResponse + (*GetBalanceRequest)(nil), // 21: waverpc.GetBalanceRequest + (*GetBalanceResponse)(nil), // 22: waverpc.GetBalanceResponse + (*VTXOExpiryInfo)(nil), // 23: waverpc.VTXOExpiryInfo + (*VTXO)(nil), // 24: waverpc.VTXO + (*VTXOSettlement)(nil), // 25: waverpc.VTXOSettlement + (*ListVTXOsRequest)(nil), // 26: waverpc.ListVTXOsRequest + (*ListVTXOsResponse)(nil), // 27: waverpc.ListVTXOsResponse + (*NewAddressRequest)(nil), // 28: waverpc.NewAddressRequest + (*NewAddressResponse)(nil), // 29: waverpc.NewAddressResponse + (*NewReceiveScriptRequest)(nil), // 30: waverpc.NewReceiveScriptRequest + (*NewReceiveScriptResponse)(nil), // 31: waverpc.NewReceiveScriptResponse + (*ReceiveAuthKeyRequest)(nil), // 32: waverpc.ReceiveAuthKeyRequest + (*ReceiveAuthKeyResponse)(nil), // 33: waverpc.ReceiveAuthKeyResponse + (*SignReceiveAuthMessageRequest)(nil), // 34: waverpc.SignReceiveAuthMessageRequest + (*SignReceiveAuthMessageResponse)(nil), // 35: waverpc.SignReceiveAuthMessageResponse + (*SignReceiveAuthMessageCompactRequest)(nil), // 36: waverpc.SignReceiveAuthMessageCompactRequest + (*SignReceiveAuthMessageCompactResponse)(nil), // 37: waverpc.SignReceiveAuthMessageCompactResponse + (*ReceiveAuthECDHRequest)(nil), // 38: waverpc.ReceiveAuthECDHRequest + (*ReceiveAuthECDHResponse)(nil), // 39: waverpc.ReceiveAuthECDHResponse + (*GetIndexedVTXOByPkScriptRequest)(nil), // 40: waverpc.GetIndexedVTXOByPkScriptRequest + (*GetIndexedVTXOByPkScriptResponse)(nil), // 41: waverpc.GetIndexedVTXOByPkScriptResponse + (*GetVTXOExpiryInfoRequest)(nil), // 42: waverpc.GetVTXOExpiryInfoRequest + (*GetVTXOExpiryInfoResponse)(nil), // 43: waverpc.GetVTXOExpiryInfoResponse + (*GetIndexedOORSessionByTxidRequest)(nil), // 44: waverpc.GetIndexedOORSessionByTxidRequest + (*GetIndexedOORSessionByTxidResponse)(nil), // 45: waverpc.GetIndexedOORSessionByTxidResponse + (*Output)(nil), // 46: waverpc.Output + (*SendVTXORequest)(nil), // 47: waverpc.SendVTXORequest + (*SendVTXOResponse)(nil), // 48: waverpc.SendVTXOResponse + (*SendOORRequest)(nil), // 49: waverpc.SendOORRequest + (*CustomOORInput)(nil), // 50: waverpc.CustomOORInput + (*TaprootScriptSignature)(nil), // 51: waverpc.TaprootScriptSignature + (*SendOORResponse)(nil), // 52: waverpc.SendOORResponse + (*PrepareOORRequest)(nil), // 53: waverpc.PrepareOORRequest + (*PreparedOORCustomInput)(nil), // 54: waverpc.PreparedOORCustomInput + (*PrepareOORResponse)(nil), // 55: waverpc.PrepareOORResponse + (*ExportOORRecoveryPackageRequest)(nil), // 56: waverpc.ExportOORRecoveryPackageRequest + (*ExportOORRecoveryPackageResponse)(nil), // 57: waverpc.ExportOORRecoveryPackageResponse + (*PrepareArkChannelOORRequest)(nil), // 58: waverpc.PrepareArkChannelOORRequest + (*PrepareArkChannelOORResponse)(nil), // 59: waverpc.PrepareArkChannelOORResponse + (*LookupPreparedArkChannelOORRequest)(nil), // 60: waverpc.LookupPreparedArkChannelOORRequest + (*LookupPreparedArkChannelOORResponse)(nil), // 61: waverpc.LookupPreparedArkChannelOORResponse + (*ValidatePreparedArkChannelOORRequest)(nil), // 62: waverpc.ValidatePreparedArkChannelOORRequest + (*ValidatePreparedArkChannelOORResponse)(nil), // 63: waverpc.ValidatePreparedArkChannelOORResponse + (*CommitPreparedArkChannelOORRequest)(nil), // 64: waverpc.CommitPreparedArkChannelOORRequest + (*CommitPreparedArkChannelOORResponse)(nil), // 65: waverpc.CommitPreparedArkChannelOORResponse + (*AbortPreparedArkChannelOORRequest)(nil), // 66: waverpc.AbortPreparedArkChannelOORRequest + (*AbortPreparedArkChannelOORResponse)(nil), // 67: waverpc.AbortPreparedArkChannelOORResponse + (*SignOORCustomInputRequest)(nil), // 68: waverpc.SignOORCustomInputRequest + (*SignOORCustomInputResponse)(nil), // 69: waverpc.SignOORCustomInputResponse + (*SignVTXOForfeitRequest)(nil), // 70: waverpc.SignVTXOForfeitRequest + (*SignVTXOForfeitResponse)(nil), // 71: waverpc.SignVTXOForfeitResponse + (*ForfeitSigningContext)(nil), // 72: waverpc.ForfeitSigningContext + (*OutpointSelection)(nil), // 73: waverpc.OutpointSelection + (*RefreshVTXOsRequest)(nil), // 74: waverpc.RefreshVTXOsRequest + (*RefreshVTXOsResponse)(nil), // 75: waverpc.RefreshVTXOsResponse + (*RefreshFeeEstimate)(nil), // 76: waverpc.RefreshFeeEstimate + (*OutpointFeeEstimate)(nil), // 77: waverpc.OutpointFeeEstimate + (*CustomRefreshVTXOInput)(nil), // 78: waverpc.CustomRefreshVTXOInput + (*CustomRefreshVTXOOutput)(nil), // 79: waverpc.CustomRefreshVTXOOutput + (*RefreshCustomVTXOsRequest)(nil), // 80: waverpc.RefreshCustomVTXOsRequest + (*RefreshCustomVTXOsResponse)(nil), // 81: waverpc.RefreshCustomVTXOsResponse + (*PendingForfeitParticipantSignatureRequest)(nil), // 82: waverpc.PendingForfeitParticipantSignatureRequest + (*ListPendingForfeitParticipantSignatureRequestsRequest)(nil), // 83: waverpc.ListPendingForfeitParticipantSignatureRequestsRequest + (*ListPendingForfeitParticipantSignatureRequestsResponse)(nil), // 84: waverpc.ListPendingForfeitParticipantSignatureRequestsResponse + (*ForfeitParticipantSignature)(nil), // 85: waverpc.ForfeitParticipantSignature + (*SubmitForfeitParticipantSignaturesRequest)(nil), // 86: waverpc.SubmitForfeitParticipantSignaturesRequest + (*SubmitForfeitParticipantSignaturesResponse)(nil), // 87: waverpc.SubmitForfeitParticipantSignaturesResponse + (*LeaveDestination)(nil), // 88: waverpc.LeaveDestination + (*LeaveVTXOsRequest)(nil), // 89: waverpc.LeaveVTXOsRequest + (*LeaveVTXOsResponse)(nil), // 90: waverpc.LeaveVTXOsResponse + (*SendOnChainRequest)(nil), // 91: waverpc.SendOnChainRequest + (*SendOnChainResponse)(nil), // 92: waverpc.SendOnChainResponse + (*BoardRequest)(nil), // 93: waverpc.BoardRequest + (*BoardResponse)(nil), // 94: waverpc.BoardResponse + (*JoinNextRoundRequest)(nil), // 95: waverpc.JoinNextRoundRequest + (*JoinNextRoundResponse)(nil), // 96: waverpc.JoinNextRoundResponse + (*SweepBoardingUTXOsRequest)(nil), // 97: waverpc.SweepBoardingUTXOsRequest + (*BoardingSweepOutput)(nil), // 98: waverpc.BoardingSweepOutput + (*SweepBoardingUTXOsResponse)(nil), // 99: waverpc.SweepBoardingUTXOsResponse + (*ListBoardingSweepsRequest)(nil), // 100: waverpc.ListBoardingSweepsRequest + (*BoardingSweepInput)(nil), // 101: waverpc.BoardingSweepInput + (*BoardingSweep)(nil), // 102: waverpc.BoardingSweep + (*ListBoardingSweepsResponse)(nil), // 103: waverpc.ListBoardingSweepsResponse + (*RoundVTXOInfo)(nil), // 104: waverpc.RoundVTXOInfo + (*RoundInfo)(nil), // 105: waverpc.RoundInfo + (*ListRoundsRequest)(nil), // 106: waverpc.ListRoundsRequest + (*GetRoundRequest)(nil), // 107: waverpc.GetRoundRequest + (*GetRoundResponse)(nil), // 108: waverpc.GetRoundResponse + (*ListRoundsResponse)(nil), // 109: waverpc.ListRoundsResponse + (*WatchRoundsRequest)(nil), // 110: waverpc.WatchRoundsRequest + (*WatchRoundsResponse)(nil), // 111: waverpc.WatchRoundsResponse + (*OORSessionInfo)(nil), // 112: waverpc.OORSessionInfo + (*ListOORSessionsRequest)(nil), // 113: waverpc.ListOORSessionsRequest + (*ListOORSessionsResponse)(nil), // 114: waverpc.ListOORSessionsResponse + (*GetOORSessionRequest)(nil), // 115: waverpc.GetOORSessionRequest + (*GetOORSessionResponse)(nil), // 116: waverpc.GetOORSessionResponse + (*EstimateFeeRequest)(nil), // 117: waverpc.EstimateFeeRequest + (*EstimateFeeResponse)(nil), // 118: waverpc.EstimateFeeResponse + (*GetFeeHistoryRequest)(nil), // 119: waverpc.GetFeeHistoryRequest + (*FeeHistoryEntry)(nil), // 120: waverpc.FeeHistoryEntry + (*GetFeeHistoryResponse)(nil), // 121: waverpc.GetFeeHistoryResponse + (*ListTransactionsRequest)(nil), // 122: waverpc.ListTransactionsRequest + (*TransactionHistoryEntry)(nil), // 123: waverpc.TransactionHistoryEntry + (*ListTransactionsResponse)(nil), // 124: waverpc.ListTransactionsResponse + (*UnrollRequest)(nil), // 125: waverpc.UnrollRequest + (*UnrollResponse)(nil), // 126: waverpc.UnrollResponse + (*GetUnrollStatusRequest)(nil), // 127: waverpc.GetUnrollStatusRequest + (*UnrollProgress)(nil), // 128: waverpc.UnrollProgress + (*UnrollCSV)(nil), // 129: waverpc.UnrollCSV + (*UnrollFees)(nil), // 130: waverpc.UnrollFees + (*GetUnrollStatusResponse)(nil), // 131: waverpc.GetUnrollStatusResponse + (*ArmVHTLCRecoveryRequest)(nil), // 132: waverpc.ArmVHTLCRecoveryRequest + (*ArmVHTLCRecoveryResponse)(nil), // 133: waverpc.ArmVHTLCRecoveryResponse + (*EscalateVHTLCRecoveryRequest)(nil), // 134: waverpc.EscalateVHTLCRecoveryRequest + (*EscalateVHTLCRecoveryResponse)(nil), // 135: waverpc.EscalateVHTLCRecoveryResponse + (*CancelVHTLCRecoveryRequest)(nil), // 136: waverpc.CancelVHTLCRecoveryRequest + (*CancelVHTLCRecoveryResponse)(nil), // 137: waverpc.CancelVHTLCRecoveryResponse + (*GetVHTLCRecoveryStatusRequest)(nil), // 138: waverpc.GetVHTLCRecoveryStatusRequest + (*GetVHTLCRecoveryStatusResponse)(nil), // 139: waverpc.GetVHTLCRecoveryStatusResponse + (*ListVHTLCRecoveriesRequest)(nil), // 140: waverpc.ListVHTLCRecoveriesRequest + (*ListVHTLCRecoveriesResponse)(nil), // 141: waverpc.ListVHTLCRecoveriesResponse + (*VHTLCRecoveryStatus)(nil), // 142: waverpc.VHTLCRecoveryStatus + (*SignOutSwapHtlcAckRequest)(nil), // 143: waverpc.SignOutSwapHtlcAckRequest + (*SignOutSwapHtlcAckResponse)(nil), // 144: waverpc.SignOutSwapHtlcAckResponse + (*SignCreditAccountAuthorizationRequest)(nil), // 145: waverpc.SignCreditAccountAuthorizationRequest + (*SignCreditAccountAuthorizationResponse)(nil), // 146: waverpc.SignCreditAccountAuthorizationResponse + nil, // 147: waverpc.LeaveVTXOsRequest.DestinationsEntry + (*arkchannelrpc.OORRecoverySource)(nil), // 148: arkchannelrpc.OORRecoverySource + (*arkchannelrpc.ChannelRecoveryPackage)(nil), // 149: arkchannelrpc.ChannelRecoveryPackage + (*arkchannelrpc.ChannelTerms)(nil), // 150: arkchannelrpc.ChannelTerms + (*arkchannelrpc.ChannelVTXOBinding)(nil), // 151: arkchannelrpc.ChannelVTXOBinding } var file_daemon_proto_depIdxs = []int32{ 0, // 0: waverpc.GetInfoResponse.wallet_state:type_name -> waverpc.WalletState - 13, // 1: waverpc.GetInfoResponse.server_info:type_name -> waverpc.ServerInfo + 14, // 1: waverpc.GetInfoResponse.server_info:type_name -> waverpc.ServerInfo 2, // 2: waverpc.VTXOExpiryInfo.status:type_name -> waverpc.VTXOExpiryStatus 1, // 3: waverpc.VTXO.status:type_name -> waverpc.VTXOStatus - 22, // 4: waverpc.VTXO.expiry_info:type_name -> waverpc.VTXOExpiryInfo - 24, // 5: waverpc.VTXO.settlement:type_name -> waverpc.VTXOSettlement + 23, // 4: waverpc.VTXO.expiry_info:type_name -> waverpc.VTXOExpiryInfo + 25, // 5: waverpc.VTXO.settlement:type_name -> waverpc.VTXOSettlement 1, // 6: waverpc.ListVTXOsRequest.status_filter:type_name -> waverpc.VTXOStatus - 23, // 7: waverpc.ListVTXOsResponse.vtxos:type_name -> waverpc.VTXO + 24, // 7: waverpc.ListVTXOsResponse.vtxos:type_name -> waverpc.VTXO 1, // 8: waverpc.GetIndexedVTXOByPkScriptRequest.status_filter:type_name -> waverpc.VTXOStatus - 23, // 9: waverpc.GetIndexedVTXOByPkScriptResponse.vtxo:type_name -> waverpc.VTXO + 24, // 9: waverpc.GetIndexedVTXOByPkScriptResponse.vtxo:type_name -> waverpc.VTXO 1, // 10: waverpc.GetVTXOExpiryInfoRequest.status_filter:type_name -> waverpc.VTXOStatus - 22, // 11: waverpc.GetVTXOExpiryInfoResponse.expiry_info:type_name -> waverpc.VTXOExpiryInfo - 23, // 12: waverpc.GetVTXOExpiryInfoResponse.vtxo:type_name -> waverpc.VTXO - 45, // 13: waverpc.SendVTXORequest.recipients:type_name -> waverpc.Output - 45, // 14: waverpc.SendOORRequest.recipients:type_name -> waverpc.Output - 49, // 15: waverpc.SendOORRequest.custom_inputs:type_name -> waverpc.CustomOORInput - 50, // 16: waverpc.CustomOORInput.external_signatures:type_name -> waverpc.TaprootScriptSignature - 45, // 17: waverpc.PrepareOORRequest.recipient:type_name -> waverpc.Output - 49, // 18: waverpc.PrepareOORRequest.custom_inputs:type_name -> waverpc.CustomOORInput - 53, // 19: waverpc.PrepareOORResponse.custom_inputs:type_name -> waverpc.PreparedOORCustomInput - 49, // 20: waverpc.SignOORCustomInputRequest.custom_input:type_name -> waverpc.CustomOORInput - 50, // 21: waverpc.SignOORCustomInputResponse.signature:type_name -> waverpc.TaprootScriptSignature - 3, // 22: waverpc.ForfeitSigningContext.signing_route:type_name -> waverpc.ForfeitSigningRoute - 60, // 23: waverpc.RefreshVTXOsRequest.outpoints:type_name -> waverpc.OutpointSelection - 63, // 24: waverpc.RefreshVTXOsResponse.fee_estimate:type_name -> waverpc.RefreshFeeEstimate - 64, // 25: waverpc.RefreshFeeEstimate.outpoints:type_name -> waverpc.OutpointFeeEstimate - 59, // 26: waverpc.CustomRefreshVTXOInput.forfeit_signing_context:type_name -> waverpc.ForfeitSigningContext - 65, // 27: waverpc.RefreshCustomVTXOsRequest.inputs:type_name -> waverpc.CustomRefreshVTXOInput - 66, // 28: waverpc.RefreshCustomVTXOsRequest.outputs:type_name -> waverpc.CustomRefreshVTXOOutput - 3, // 29: waverpc.PendingForfeitParticipantSignatureRequest.signing_route:type_name -> waverpc.ForfeitSigningRoute - 69, // 30: waverpc.ListPendingForfeitParticipantSignatureRequestsResponse.requests:type_name -> waverpc.PendingForfeitParticipantSignatureRequest - 72, // 31: waverpc.SubmitForfeitParticipantSignaturesRequest.signatures:type_name -> waverpc.ForfeitParticipantSignature - 60, // 32: waverpc.LeaveVTXOsRequest.outpoints:type_name -> waverpc.OutpointSelection - 75, // 33: waverpc.LeaveVTXOsRequest.default_destination:type_name -> waverpc.LeaveDestination - 134, // 34: waverpc.LeaveVTXOsRequest.destinations:type_name -> waverpc.LeaveVTXOsRequest.DestinationsEntry - 75, // 35: waverpc.SendOnChainRequest.destination:type_name -> waverpc.LeaveDestination - 85, // 36: waverpc.SweepBoardingUTXOsResponse.sweepable_outputs:type_name -> waverpc.BoardingSweepOutput - 88, // 37: waverpc.BoardingSweep.inputs:type_name -> waverpc.BoardingSweepInput - 89, // 38: waverpc.ListBoardingSweepsResponse.sweeps:type_name -> waverpc.BoardingSweep - 4, // 39: waverpc.RoundInfo.state:type_name -> waverpc.RoundState - 91, // 40: waverpc.RoundInfo.vtxos:type_name -> waverpc.RoundVTXOInfo - 4, // 41: waverpc.ListRoundsRequest.state_filter:type_name -> waverpc.RoundState - 92, // 42: waverpc.GetRoundResponse.round:type_name -> waverpc.RoundInfo - 92, // 43: waverpc.ListRoundsResponse.rounds:type_name -> waverpc.RoundInfo - 92, // 44: waverpc.WatchRoundsResponse.round:type_name -> waverpc.RoundInfo - 5, // 45: waverpc.OORSessionInfo.direction:type_name -> waverpc.OORSessionDirection - 6, // 46: waverpc.OORSessionInfo.status:type_name -> waverpc.OORSessionStatus - 5, // 47: waverpc.ListOORSessionsRequest.direction_filter:type_name -> waverpc.OORSessionDirection - 6, // 48: waverpc.ListOORSessionsRequest.status_filter:type_name -> waverpc.OORSessionStatus - 99, // 49: waverpc.ListOORSessionsResponse.sessions:type_name -> waverpc.OORSessionInfo - 99, // 50: waverpc.GetOORSessionResponse.session:type_name -> waverpc.OORSessionInfo - 107, // 51: waverpc.GetFeeHistoryResponse.entries:type_name -> waverpc.FeeHistoryEntry - 110, // 52: waverpc.ListTransactionsResponse.transactions:type_name -> waverpc.TransactionHistoryEntry - 7, // 53: waverpc.GetUnrollStatusResponse.status:type_name -> waverpc.UnrollJobStatus - 115, // 54: waverpc.GetUnrollStatusResponse.progress:type_name -> waverpc.UnrollProgress - 116, // 55: waverpc.GetUnrollStatusResponse.csv:type_name -> waverpc.UnrollCSV - 117, // 56: waverpc.GetUnrollStatusResponse.fees:type_name -> waverpc.UnrollFees - 8, // 57: waverpc.ArmVHTLCRecoveryRequest.direction:type_name -> waverpc.VHTLCRecoveryDirection - 9, // 58: waverpc.ArmVHTLCRecoveryRequest.action:type_name -> waverpc.VHTLCRecoveryAction - 129, // 59: waverpc.ArmVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus - 129, // 60: waverpc.EscalateVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus - 129, // 61: waverpc.CancelVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus - 129, // 62: waverpc.GetVHTLCRecoveryStatusResponse.status:type_name -> waverpc.VHTLCRecoveryStatus - 129, // 63: waverpc.ListVHTLCRecoveriesResponse.statuses:type_name -> waverpc.VHTLCRecoveryStatus - 8, // 64: waverpc.VHTLCRecoveryStatus.direction:type_name -> waverpc.VHTLCRecoveryDirection - 9, // 65: waverpc.VHTLCRecoveryStatus.action:type_name -> waverpc.VHTLCRecoveryAction - 10, // 66: waverpc.VHTLCRecoveryStatus.state:type_name -> waverpc.VHTLCRecoveryState - 7, // 67: waverpc.VHTLCRecoveryStatus.unroll_status:type_name -> waverpc.UnrollJobStatus - 75, // 68: waverpc.LeaveVTXOsRequest.DestinationsEntry.value:type_name -> waverpc.LeaveDestination - 11, // 69: waverpc.DaemonService.GetInfo:input_type -> waverpc.GetInfoRequest - 14, // 70: waverpc.DaemonService.GenSeed:input_type -> waverpc.GenSeedRequest - 16, // 71: waverpc.DaemonService.InitWallet:input_type -> waverpc.InitWalletRequest - 18, // 72: waverpc.DaemonService.UnlockWallet:input_type -> waverpc.UnlockWalletRequest - 20, // 73: waverpc.DaemonService.GetBalance:input_type -> waverpc.GetBalanceRequest - 25, // 74: waverpc.DaemonService.ListVTXOs:input_type -> waverpc.ListVTXOsRequest - 27, // 75: waverpc.DaemonService.NewAddress:input_type -> waverpc.NewAddressRequest - 29, // 76: waverpc.DaemonService.NewReceiveScript:input_type -> waverpc.NewReceiveScriptRequest - 31, // 77: waverpc.DaemonService.ReceiveAuthKey:input_type -> waverpc.ReceiveAuthKeyRequest - 33, // 78: waverpc.DaemonService.SignReceiveAuthMessage:input_type -> waverpc.SignReceiveAuthMessageRequest - 35, // 79: waverpc.DaemonService.SignReceiveAuthMessageCompact:input_type -> waverpc.SignReceiveAuthMessageCompactRequest - 37, // 80: waverpc.DaemonService.ReceiveAuthECDH:input_type -> waverpc.ReceiveAuthECDHRequest - 39, // 81: waverpc.DaemonService.GetIndexedVTXOByPkScript:input_type -> waverpc.GetIndexedVTXOByPkScriptRequest - 41, // 82: waverpc.DaemonService.GetVTXOExpiryInfo:input_type -> waverpc.GetVTXOExpiryInfoRequest - 43, // 83: waverpc.DaemonService.GetIndexedOORSessionByTxid:input_type -> waverpc.GetIndexedOORSessionByTxidRequest - 46, // 84: waverpc.DaemonService.SendVTXO:input_type -> waverpc.SendVTXORequest - 48, // 85: waverpc.DaemonService.SendOOR:input_type -> waverpc.SendOORRequest - 52, // 86: waverpc.DaemonService.PrepareOOR:input_type -> waverpc.PrepareOORRequest - 55, // 87: waverpc.DaemonService.SignOORCustomInput:input_type -> waverpc.SignOORCustomInputRequest - 57, // 88: waverpc.DaemonService.SignVTXOForfeit:input_type -> waverpc.SignVTXOForfeitRequest - 61, // 89: waverpc.DaemonService.RefreshVTXOs:input_type -> waverpc.RefreshVTXOsRequest - 67, // 90: waverpc.DaemonService.RefreshCustomVTXOs:input_type -> waverpc.RefreshCustomVTXOsRequest - 70, // 91: waverpc.DaemonService.ListPendingForfeitParticipantSignatureRequests:input_type -> waverpc.ListPendingForfeitParticipantSignatureRequestsRequest - 73, // 92: waverpc.DaemonService.SubmitForfeitParticipantSignatures:input_type -> waverpc.SubmitForfeitParticipantSignaturesRequest - 76, // 93: waverpc.DaemonService.LeaveVTXOs:input_type -> waverpc.LeaveVTXOsRequest - 78, // 94: waverpc.DaemonService.SendOnChain:input_type -> waverpc.SendOnChainRequest - 80, // 95: waverpc.DaemonService.Board:input_type -> waverpc.BoardRequest - 82, // 96: waverpc.DaemonService.JoinNextRound:input_type -> waverpc.JoinNextRoundRequest - 84, // 97: waverpc.DaemonService.SweepBoardingUTXOs:input_type -> waverpc.SweepBoardingUTXOsRequest - 87, // 98: waverpc.DaemonService.ListBoardingSweeps:input_type -> waverpc.ListBoardingSweepsRequest - 93, // 99: waverpc.DaemonService.ListRounds:input_type -> waverpc.ListRoundsRequest - 94, // 100: waverpc.DaemonService.GetRound:input_type -> waverpc.GetRoundRequest - 97, // 101: waverpc.DaemonService.WatchRounds:input_type -> waverpc.WatchRoundsRequest - 100, // 102: waverpc.DaemonService.ListOORSessions:input_type -> waverpc.ListOORSessionsRequest - 102, // 103: waverpc.DaemonService.GetOORSession:input_type -> waverpc.GetOORSessionRequest - 104, // 104: waverpc.DaemonService.EstimateFee:input_type -> waverpc.EstimateFeeRequest - 106, // 105: waverpc.DaemonService.GetFeeHistory:input_type -> waverpc.GetFeeHistoryRequest - 109, // 106: waverpc.DaemonService.ListTransactions:input_type -> waverpc.ListTransactionsRequest - 112, // 107: waverpc.DaemonService.Unroll:input_type -> waverpc.UnrollRequest - 114, // 108: waverpc.DaemonService.GetUnrollStatus:input_type -> waverpc.GetUnrollStatusRequest - 119, // 109: waverpc.DaemonService.ArmVHTLCRecovery:input_type -> waverpc.ArmVHTLCRecoveryRequest - 121, // 110: waverpc.DaemonService.EscalateVHTLCRecovery:input_type -> waverpc.EscalateVHTLCRecoveryRequest - 123, // 111: waverpc.DaemonService.CancelVHTLCRecovery:input_type -> waverpc.CancelVHTLCRecoveryRequest - 125, // 112: waverpc.DaemonService.GetVHTLCRecoveryStatus:input_type -> waverpc.GetVHTLCRecoveryStatusRequest - 127, // 113: waverpc.DaemonService.ListVHTLCRecoveries:input_type -> waverpc.ListVHTLCRecoveriesRequest - 130, // 114: waverpc.DaemonService.SignOutSwapHtlcAck:input_type -> waverpc.SignOutSwapHtlcAckRequest - 132, // 115: waverpc.DaemonService.SignCreditAccountAuthorization:input_type -> waverpc.SignCreditAccountAuthorizationRequest - 12, // 116: waverpc.DaemonService.GetInfo:output_type -> waverpc.GetInfoResponse - 15, // 117: waverpc.DaemonService.GenSeed:output_type -> waverpc.GenSeedResponse - 17, // 118: waverpc.DaemonService.InitWallet:output_type -> waverpc.InitWalletResponse - 19, // 119: waverpc.DaemonService.UnlockWallet:output_type -> waverpc.UnlockWalletResponse - 21, // 120: waverpc.DaemonService.GetBalance:output_type -> waverpc.GetBalanceResponse - 26, // 121: waverpc.DaemonService.ListVTXOs:output_type -> waverpc.ListVTXOsResponse - 28, // 122: waverpc.DaemonService.NewAddress:output_type -> waverpc.NewAddressResponse - 30, // 123: waverpc.DaemonService.NewReceiveScript:output_type -> waverpc.NewReceiveScriptResponse - 32, // 124: waverpc.DaemonService.ReceiveAuthKey:output_type -> waverpc.ReceiveAuthKeyResponse - 34, // 125: waverpc.DaemonService.SignReceiveAuthMessage:output_type -> waverpc.SignReceiveAuthMessageResponse - 36, // 126: waverpc.DaemonService.SignReceiveAuthMessageCompact:output_type -> waverpc.SignReceiveAuthMessageCompactResponse - 38, // 127: waverpc.DaemonService.ReceiveAuthECDH:output_type -> waverpc.ReceiveAuthECDHResponse - 40, // 128: waverpc.DaemonService.GetIndexedVTXOByPkScript:output_type -> waverpc.GetIndexedVTXOByPkScriptResponse - 42, // 129: waverpc.DaemonService.GetVTXOExpiryInfo:output_type -> waverpc.GetVTXOExpiryInfoResponse - 44, // 130: waverpc.DaemonService.GetIndexedOORSessionByTxid:output_type -> waverpc.GetIndexedOORSessionByTxidResponse - 47, // 131: waverpc.DaemonService.SendVTXO:output_type -> waverpc.SendVTXOResponse - 51, // 132: waverpc.DaemonService.SendOOR:output_type -> waverpc.SendOORResponse - 54, // 133: waverpc.DaemonService.PrepareOOR:output_type -> waverpc.PrepareOORResponse - 56, // 134: waverpc.DaemonService.SignOORCustomInput:output_type -> waverpc.SignOORCustomInputResponse - 58, // 135: waverpc.DaemonService.SignVTXOForfeit:output_type -> waverpc.SignVTXOForfeitResponse - 62, // 136: waverpc.DaemonService.RefreshVTXOs:output_type -> waverpc.RefreshVTXOsResponse - 68, // 137: waverpc.DaemonService.RefreshCustomVTXOs:output_type -> waverpc.RefreshCustomVTXOsResponse - 71, // 138: waverpc.DaemonService.ListPendingForfeitParticipantSignatureRequests:output_type -> waverpc.ListPendingForfeitParticipantSignatureRequestsResponse - 74, // 139: waverpc.DaemonService.SubmitForfeitParticipantSignatures:output_type -> waverpc.SubmitForfeitParticipantSignaturesResponse - 77, // 140: waverpc.DaemonService.LeaveVTXOs:output_type -> waverpc.LeaveVTXOsResponse - 79, // 141: waverpc.DaemonService.SendOnChain:output_type -> waverpc.SendOnChainResponse - 81, // 142: waverpc.DaemonService.Board:output_type -> waverpc.BoardResponse - 83, // 143: waverpc.DaemonService.JoinNextRound:output_type -> waverpc.JoinNextRoundResponse - 86, // 144: waverpc.DaemonService.SweepBoardingUTXOs:output_type -> waverpc.SweepBoardingUTXOsResponse - 90, // 145: waverpc.DaemonService.ListBoardingSweeps:output_type -> waverpc.ListBoardingSweepsResponse - 96, // 146: waverpc.DaemonService.ListRounds:output_type -> waverpc.ListRoundsResponse - 95, // 147: waverpc.DaemonService.GetRound:output_type -> waverpc.GetRoundResponse - 98, // 148: waverpc.DaemonService.WatchRounds:output_type -> waverpc.WatchRoundsResponse - 101, // 149: waverpc.DaemonService.ListOORSessions:output_type -> waverpc.ListOORSessionsResponse - 103, // 150: waverpc.DaemonService.GetOORSession:output_type -> waverpc.GetOORSessionResponse - 105, // 151: waverpc.DaemonService.EstimateFee:output_type -> waverpc.EstimateFeeResponse - 108, // 152: waverpc.DaemonService.GetFeeHistory:output_type -> waverpc.GetFeeHistoryResponse - 111, // 153: waverpc.DaemonService.ListTransactions:output_type -> waverpc.ListTransactionsResponse - 113, // 154: waverpc.DaemonService.Unroll:output_type -> waverpc.UnrollResponse - 118, // 155: waverpc.DaemonService.GetUnrollStatus:output_type -> waverpc.GetUnrollStatusResponse - 120, // 156: waverpc.DaemonService.ArmVHTLCRecovery:output_type -> waverpc.ArmVHTLCRecoveryResponse - 122, // 157: waverpc.DaemonService.EscalateVHTLCRecovery:output_type -> waverpc.EscalateVHTLCRecoveryResponse - 124, // 158: waverpc.DaemonService.CancelVHTLCRecovery:output_type -> waverpc.CancelVHTLCRecoveryResponse - 126, // 159: waverpc.DaemonService.GetVHTLCRecoveryStatus:output_type -> waverpc.GetVHTLCRecoveryStatusResponse - 128, // 160: waverpc.DaemonService.ListVHTLCRecoveries:output_type -> waverpc.ListVHTLCRecoveriesResponse - 131, // 161: waverpc.DaemonService.SignOutSwapHtlcAck:output_type -> waverpc.SignOutSwapHtlcAckResponse - 133, // 162: waverpc.DaemonService.SignCreditAccountAuthorization:output_type -> waverpc.SignCreditAccountAuthorizationResponse - 116, // [116:163] is the sub-list for method output_type - 69, // [69:116] is the sub-list for method input_type - 69, // [69:69] is the sub-list for extension type_name - 69, // [69:69] is the sub-list for extension extendee - 0, // [0:69] is the sub-list for field type_name + 23, // 11: waverpc.GetVTXOExpiryInfoResponse.expiry_info:type_name -> waverpc.VTXOExpiryInfo + 24, // 12: waverpc.GetVTXOExpiryInfoResponse.vtxo:type_name -> waverpc.VTXO + 46, // 13: waverpc.SendVTXORequest.recipients:type_name -> waverpc.Output + 46, // 14: waverpc.SendOORRequest.recipients:type_name -> waverpc.Output + 50, // 15: waverpc.SendOORRequest.custom_inputs:type_name -> waverpc.CustomOORInput + 51, // 16: waverpc.CustomOORInput.external_signatures:type_name -> waverpc.TaprootScriptSignature + 46, // 17: waverpc.PrepareOORRequest.recipient:type_name -> waverpc.Output + 50, // 18: waverpc.PrepareOORRequest.custom_inputs:type_name -> waverpc.CustomOORInput + 54, // 19: waverpc.PrepareOORResponse.custom_inputs:type_name -> waverpc.PreparedOORCustomInput + 148, // 20: waverpc.ExportOORRecoveryPackageRequest.source:type_name -> arkchannelrpc.OORRecoverySource + 149, // 21: waverpc.ExportOORRecoveryPackageResponse.recovery:type_name -> arkchannelrpc.ChannelRecoveryPackage + 150, // 22: waverpc.PrepareArkChannelOORRequest.terms:type_name -> arkchannelrpc.ChannelTerms + 151, // 23: waverpc.PrepareArkChannelOORResponse.binding:type_name -> arkchannelrpc.ChannelVTXOBinding + 150, // 24: waverpc.LookupPreparedArkChannelOORRequest.terms:type_name -> arkchannelrpc.ChannelTerms + 3, // 25: waverpc.LookupPreparedArkChannelOORResponse.status:type_name -> waverpc.ArkChannelOORPreparationStatus + 151, // 26: waverpc.LookupPreparedArkChannelOORResponse.binding:type_name -> arkchannelrpc.ChannelVTXOBinding + 150, // 27: waverpc.ValidatePreparedArkChannelOORRequest.terms:type_name -> arkchannelrpc.ChannelTerms + 151, // 28: waverpc.ValidatePreparedArkChannelOORRequest.binding:type_name -> arkchannelrpc.ChannelVTXOBinding + 150, // 29: waverpc.CommitPreparedArkChannelOORRequest.terms:type_name -> arkchannelrpc.ChannelTerms + 151, // 30: waverpc.CommitPreparedArkChannelOORRequest.binding:type_name -> arkchannelrpc.ChannelVTXOBinding + 150, // 31: waverpc.AbortPreparedArkChannelOORRequest.terms:type_name -> arkchannelrpc.ChannelTerms + 151, // 32: waverpc.AbortPreparedArkChannelOORRequest.binding:type_name -> arkchannelrpc.ChannelVTXOBinding + 50, // 33: waverpc.SignOORCustomInputRequest.custom_input:type_name -> waverpc.CustomOORInput + 51, // 34: waverpc.SignOORCustomInputResponse.signature:type_name -> waverpc.TaprootScriptSignature + 4, // 35: waverpc.ForfeitSigningContext.signing_route:type_name -> waverpc.ForfeitSigningRoute + 73, // 36: waverpc.RefreshVTXOsRequest.outpoints:type_name -> waverpc.OutpointSelection + 76, // 37: waverpc.RefreshVTXOsResponse.fee_estimate:type_name -> waverpc.RefreshFeeEstimate + 77, // 38: waverpc.RefreshFeeEstimate.outpoints:type_name -> waverpc.OutpointFeeEstimate + 72, // 39: waverpc.CustomRefreshVTXOInput.forfeit_signing_context:type_name -> waverpc.ForfeitSigningContext + 78, // 40: waverpc.RefreshCustomVTXOsRequest.inputs:type_name -> waverpc.CustomRefreshVTXOInput + 79, // 41: waverpc.RefreshCustomVTXOsRequest.outputs:type_name -> waverpc.CustomRefreshVTXOOutput + 4, // 42: waverpc.PendingForfeitParticipantSignatureRequest.signing_route:type_name -> waverpc.ForfeitSigningRoute + 82, // 43: waverpc.ListPendingForfeitParticipantSignatureRequestsResponse.requests:type_name -> waverpc.PendingForfeitParticipantSignatureRequest + 85, // 44: waverpc.SubmitForfeitParticipantSignaturesRequest.signatures:type_name -> waverpc.ForfeitParticipantSignature + 73, // 45: waverpc.LeaveVTXOsRequest.outpoints:type_name -> waverpc.OutpointSelection + 88, // 46: waverpc.LeaveVTXOsRequest.default_destination:type_name -> waverpc.LeaveDestination + 147, // 47: waverpc.LeaveVTXOsRequest.destinations:type_name -> waverpc.LeaveVTXOsRequest.DestinationsEntry + 88, // 48: waverpc.SendOnChainRequest.destination:type_name -> waverpc.LeaveDestination + 98, // 49: waverpc.SweepBoardingUTXOsResponse.sweepable_outputs:type_name -> waverpc.BoardingSweepOutput + 101, // 50: waverpc.BoardingSweep.inputs:type_name -> waverpc.BoardingSweepInput + 102, // 51: waverpc.ListBoardingSweepsResponse.sweeps:type_name -> waverpc.BoardingSweep + 5, // 52: waverpc.RoundInfo.state:type_name -> waverpc.RoundState + 104, // 53: waverpc.RoundInfo.vtxos:type_name -> waverpc.RoundVTXOInfo + 5, // 54: waverpc.ListRoundsRequest.state_filter:type_name -> waverpc.RoundState + 105, // 55: waverpc.GetRoundResponse.round:type_name -> waverpc.RoundInfo + 105, // 56: waverpc.ListRoundsResponse.rounds:type_name -> waverpc.RoundInfo + 105, // 57: waverpc.WatchRoundsResponse.round:type_name -> waverpc.RoundInfo + 6, // 58: waverpc.OORSessionInfo.direction:type_name -> waverpc.OORSessionDirection + 7, // 59: waverpc.OORSessionInfo.status:type_name -> waverpc.OORSessionStatus + 6, // 60: waverpc.ListOORSessionsRequest.direction_filter:type_name -> waverpc.OORSessionDirection + 7, // 61: waverpc.ListOORSessionsRequest.status_filter:type_name -> waverpc.OORSessionStatus + 112, // 62: waverpc.ListOORSessionsResponse.sessions:type_name -> waverpc.OORSessionInfo + 112, // 63: waverpc.GetOORSessionResponse.session:type_name -> waverpc.OORSessionInfo + 120, // 64: waverpc.GetFeeHistoryResponse.entries:type_name -> waverpc.FeeHistoryEntry + 123, // 65: waverpc.ListTransactionsResponse.transactions:type_name -> waverpc.TransactionHistoryEntry + 8, // 66: waverpc.GetUnrollStatusResponse.status:type_name -> waverpc.UnrollJobStatus + 128, // 67: waverpc.GetUnrollStatusResponse.progress:type_name -> waverpc.UnrollProgress + 129, // 68: waverpc.GetUnrollStatusResponse.csv:type_name -> waverpc.UnrollCSV + 130, // 69: waverpc.GetUnrollStatusResponse.fees:type_name -> waverpc.UnrollFees + 9, // 70: waverpc.ArmVHTLCRecoveryRequest.direction:type_name -> waverpc.VHTLCRecoveryDirection + 10, // 71: waverpc.ArmVHTLCRecoveryRequest.action:type_name -> waverpc.VHTLCRecoveryAction + 142, // 72: waverpc.ArmVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus + 142, // 73: waverpc.EscalateVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus + 142, // 74: waverpc.CancelVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus + 142, // 75: waverpc.GetVHTLCRecoveryStatusResponse.status:type_name -> waverpc.VHTLCRecoveryStatus + 142, // 76: waverpc.ListVHTLCRecoveriesResponse.statuses:type_name -> waverpc.VHTLCRecoveryStatus + 9, // 77: waverpc.VHTLCRecoveryStatus.direction:type_name -> waverpc.VHTLCRecoveryDirection + 10, // 78: waverpc.VHTLCRecoveryStatus.action:type_name -> waverpc.VHTLCRecoveryAction + 11, // 79: waverpc.VHTLCRecoveryStatus.state:type_name -> waverpc.VHTLCRecoveryState + 8, // 80: waverpc.VHTLCRecoveryStatus.unroll_status:type_name -> waverpc.UnrollJobStatus + 88, // 81: waverpc.LeaveVTXOsRequest.DestinationsEntry.value:type_name -> waverpc.LeaveDestination + 12, // 82: waverpc.DaemonService.GetInfo:input_type -> waverpc.GetInfoRequest + 15, // 83: waverpc.DaemonService.GenSeed:input_type -> waverpc.GenSeedRequest + 17, // 84: waverpc.DaemonService.InitWallet:input_type -> waverpc.InitWalletRequest + 19, // 85: waverpc.DaemonService.UnlockWallet:input_type -> waverpc.UnlockWalletRequest + 21, // 86: waverpc.DaemonService.GetBalance:input_type -> waverpc.GetBalanceRequest + 26, // 87: waverpc.DaemonService.ListVTXOs:input_type -> waverpc.ListVTXOsRequest + 28, // 88: waverpc.DaemonService.NewAddress:input_type -> waverpc.NewAddressRequest + 30, // 89: waverpc.DaemonService.NewReceiveScript:input_type -> waverpc.NewReceiveScriptRequest + 32, // 90: waverpc.DaemonService.ReceiveAuthKey:input_type -> waverpc.ReceiveAuthKeyRequest + 34, // 91: waverpc.DaemonService.SignReceiveAuthMessage:input_type -> waverpc.SignReceiveAuthMessageRequest + 36, // 92: waverpc.DaemonService.SignReceiveAuthMessageCompact:input_type -> waverpc.SignReceiveAuthMessageCompactRequest + 38, // 93: waverpc.DaemonService.ReceiveAuthECDH:input_type -> waverpc.ReceiveAuthECDHRequest + 40, // 94: waverpc.DaemonService.GetIndexedVTXOByPkScript:input_type -> waverpc.GetIndexedVTXOByPkScriptRequest + 42, // 95: waverpc.DaemonService.GetVTXOExpiryInfo:input_type -> waverpc.GetVTXOExpiryInfoRequest + 44, // 96: waverpc.DaemonService.GetIndexedOORSessionByTxid:input_type -> waverpc.GetIndexedOORSessionByTxidRequest + 56, // 97: waverpc.DaemonService.ExportOORRecoveryPackage:input_type -> waverpc.ExportOORRecoveryPackageRequest + 58, // 98: waverpc.DaemonService.PrepareArkChannelOOR:input_type -> waverpc.PrepareArkChannelOORRequest + 60, // 99: waverpc.DaemonService.LookupPreparedArkChannelOOR:input_type -> waverpc.LookupPreparedArkChannelOORRequest + 62, // 100: waverpc.DaemonService.ValidatePreparedArkChannelOOR:input_type -> waverpc.ValidatePreparedArkChannelOORRequest + 64, // 101: waverpc.DaemonService.CommitPreparedArkChannelOOR:input_type -> waverpc.CommitPreparedArkChannelOORRequest + 66, // 102: waverpc.DaemonService.AbortPreparedArkChannelOOR:input_type -> waverpc.AbortPreparedArkChannelOORRequest + 47, // 103: waverpc.DaemonService.SendVTXO:input_type -> waverpc.SendVTXORequest + 49, // 104: waverpc.DaemonService.SendOOR:input_type -> waverpc.SendOORRequest + 53, // 105: waverpc.DaemonService.PrepareOOR:input_type -> waverpc.PrepareOORRequest + 68, // 106: waverpc.DaemonService.SignOORCustomInput:input_type -> waverpc.SignOORCustomInputRequest + 70, // 107: waverpc.DaemonService.SignVTXOForfeit:input_type -> waverpc.SignVTXOForfeitRequest + 74, // 108: waverpc.DaemonService.RefreshVTXOs:input_type -> waverpc.RefreshVTXOsRequest + 80, // 109: waverpc.DaemonService.RefreshCustomVTXOs:input_type -> waverpc.RefreshCustomVTXOsRequest + 83, // 110: waverpc.DaemonService.ListPendingForfeitParticipantSignatureRequests:input_type -> waverpc.ListPendingForfeitParticipantSignatureRequestsRequest + 86, // 111: waverpc.DaemonService.SubmitForfeitParticipantSignatures:input_type -> waverpc.SubmitForfeitParticipantSignaturesRequest + 89, // 112: waverpc.DaemonService.LeaveVTXOs:input_type -> waverpc.LeaveVTXOsRequest + 91, // 113: waverpc.DaemonService.SendOnChain:input_type -> waverpc.SendOnChainRequest + 93, // 114: waverpc.DaemonService.Board:input_type -> waverpc.BoardRequest + 95, // 115: waverpc.DaemonService.JoinNextRound:input_type -> waverpc.JoinNextRoundRequest + 97, // 116: waverpc.DaemonService.SweepBoardingUTXOs:input_type -> waverpc.SweepBoardingUTXOsRequest + 100, // 117: waverpc.DaemonService.ListBoardingSweeps:input_type -> waverpc.ListBoardingSweepsRequest + 106, // 118: waverpc.DaemonService.ListRounds:input_type -> waverpc.ListRoundsRequest + 107, // 119: waverpc.DaemonService.GetRound:input_type -> waverpc.GetRoundRequest + 110, // 120: waverpc.DaemonService.WatchRounds:input_type -> waverpc.WatchRoundsRequest + 113, // 121: waverpc.DaemonService.ListOORSessions:input_type -> waverpc.ListOORSessionsRequest + 115, // 122: waverpc.DaemonService.GetOORSession:input_type -> waverpc.GetOORSessionRequest + 117, // 123: waverpc.DaemonService.EstimateFee:input_type -> waverpc.EstimateFeeRequest + 119, // 124: waverpc.DaemonService.GetFeeHistory:input_type -> waverpc.GetFeeHistoryRequest + 122, // 125: waverpc.DaemonService.ListTransactions:input_type -> waverpc.ListTransactionsRequest + 125, // 126: waverpc.DaemonService.Unroll:input_type -> waverpc.UnrollRequest + 127, // 127: waverpc.DaemonService.GetUnrollStatus:input_type -> waverpc.GetUnrollStatusRequest + 132, // 128: waverpc.DaemonService.ArmVHTLCRecovery:input_type -> waverpc.ArmVHTLCRecoveryRequest + 134, // 129: waverpc.DaemonService.EscalateVHTLCRecovery:input_type -> waverpc.EscalateVHTLCRecoveryRequest + 136, // 130: waverpc.DaemonService.CancelVHTLCRecovery:input_type -> waverpc.CancelVHTLCRecoveryRequest + 138, // 131: waverpc.DaemonService.GetVHTLCRecoveryStatus:input_type -> waverpc.GetVHTLCRecoveryStatusRequest + 140, // 132: waverpc.DaemonService.ListVHTLCRecoveries:input_type -> waverpc.ListVHTLCRecoveriesRequest + 143, // 133: waverpc.DaemonService.SignOutSwapHtlcAck:input_type -> waverpc.SignOutSwapHtlcAckRequest + 145, // 134: waverpc.DaemonService.SignCreditAccountAuthorization:input_type -> waverpc.SignCreditAccountAuthorizationRequest + 13, // 135: waverpc.DaemonService.GetInfo:output_type -> waverpc.GetInfoResponse + 16, // 136: waverpc.DaemonService.GenSeed:output_type -> waverpc.GenSeedResponse + 18, // 137: waverpc.DaemonService.InitWallet:output_type -> waverpc.InitWalletResponse + 20, // 138: waverpc.DaemonService.UnlockWallet:output_type -> waverpc.UnlockWalletResponse + 22, // 139: waverpc.DaemonService.GetBalance:output_type -> waverpc.GetBalanceResponse + 27, // 140: waverpc.DaemonService.ListVTXOs:output_type -> waverpc.ListVTXOsResponse + 29, // 141: waverpc.DaemonService.NewAddress:output_type -> waverpc.NewAddressResponse + 31, // 142: waverpc.DaemonService.NewReceiveScript:output_type -> waverpc.NewReceiveScriptResponse + 33, // 143: waverpc.DaemonService.ReceiveAuthKey:output_type -> waverpc.ReceiveAuthKeyResponse + 35, // 144: waverpc.DaemonService.SignReceiveAuthMessage:output_type -> waverpc.SignReceiveAuthMessageResponse + 37, // 145: waverpc.DaemonService.SignReceiveAuthMessageCompact:output_type -> waverpc.SignReceiveAuthMessageCompactResponse + 39, // 146: waverpc.DaemonService.ReceiveAuthECDH:output_type -> waverpc.ReceiveAuthECDHResponse + 41, // 147: waverpc.DaemonService.GetIndexedVTXOByPkScript:output_type -> waverpc.GetIndexedVTXOByPkScriptResponse + 43, // 148: waverpc.DaemonService.GetVTXOExpiryInfo:output_type -> waverpc.GetVTXOExpiryInfoResponse + 45, // 149: waverpc.DaemonService.GetIndexedOORSessionByTxid:output_type -> waverpc.GetIndexedOORSessionByTxidResponse + 57, // 150: waverpc.DaemonService.ExportOORRecoveryPackage:output_type -> waverpc.ExportOORRecoveryPackageResponse + 59, // 151: waverpc.DaemonService.PrepareArkChannelOOR:output_type -> waverpc.PrepareArkChannelOORResponse + 61, // 152: waverpc.DaemonService.LookupPreparedArkChannelOOR:output_type -> waverpc.LookupPreparedArkChannelOORResponse + 63, // 153: waverpc.DaemonService.ValidatePreparedArkChannelOOR:output_type -> waverpc.ValidatePreparedArkChannelOORResponse + 65, // 154: waverpc.DaemonService.CommitPreparedArkChannelOOR:output_type -> waverpc.CommitPreparedArkChannelOORResponse + 67, // 155: waverpc.DaemonService.AbortPreparedArkChannelOOR:output_type -> waverpc.AbortPreparedArkChannelOORResponse + 48, // 156: waverpc.DaemonService.SendVTXO:output_type -> waverpc.SendVTXOResponse + 52, // 157: waverpc.DaemonService.SendOOR:output_type -> waverpc.SendOORResponse + 55, // 158: waverpc.DaemonService.PrepareOOR:output_type -> waverpc.PrepareOORResponse + 69, // 159: waverpc.DaemonService.SignOORCustomInput:output_type -> waverpc.SignOORCustomInputResponse + 71, // 160: waverpc.DaemonService.SignVTXOForfeit:output_type -> waverpc.SignVTXOForfeitResponse + 75, // 161: waverpc.DaemonService.RefreshVTXOs:output_type -> waverpc.RefreshVTXOsResponse + 81, // 162: waverpc.DaemonService.RefreshCustomVTXOs:output_type -> waverpc.RefreshCustomVTXOsResponse + 84, // 163: waverpc.DaemonService.ListPendingForfeitParticipantSignatureRequests:output_type -> waverpc.ListPendingForfeitParticipantSignatureRequestsResponse + 87, // 164: waverpc.DaemonService.SubmitForfeitParticipantSignatures:output_type -> waverpc.SubmitForfeitParticipantSignaturesResponse + 90, // 165: waverpc.DaemonService.LeaveVTXOs:output_type -> waverpc.LeaveVTXOsResponse + 92, // 166: waverpc.DaemonService.SendOnChain:output_type -> waverpc.SendOnChainResponse + 94, // 167: waverpc.DaemonService.Board:output_type -> waverpc.BoardResponse + 96, // 168: waverpc.DaemonService.JoinNextRound:output_type -> waverpc.JoinNextRoundResponse + 99, // 169: waverpc.DaemonService.SweepBoardingUTXOs:output_type -> waverpc.SweepBoardingUTXOsResponse + 103, // 170: waverpc.DaemonService.ListBoardingSweeps:output_type -> waverpc.ListBoardingSweepsResponse + 109, // 171: waverpc.DaemonService.ListRounds:output_type -> waverpc.ListRoundsResponse + 108, // 172: waverpc.DaemonService.GetRound:output_type -> waverpc.GetRoundResponse + 111, // 173: waverpc.DaemonService.WatchRounds:output_type -> waverpc.WatchRoundsResponse + 114, // 174: waverpc.DaemonService.ListOORSessions:output_type -> waverpc.ListOORSessionsResponse + 116, // 175: waverpc.DaemonService.GetOORSession:output_type -> waverpc.GetOORSessionResponse + 118, // 176: waverpc.DaemonService.EstimateFee:output_type -> waverpc.EstimateFeeResponse + 121, // 177: waverpc.DaemonService.GetFeeHistory:output_type -> waverpc.GetFeeHistoryResponse + 124, // 178: waverpc.DaemonService.ListTransactions:output_type -> waverpc.ListTransactionsResponse + 126, // 179: waverpc.DaemonService.Unroll:output_type -> waverpc.UnrollResponse + 131, // 180: waverpc.DaemonService.GetUnrollStatus:output_type -> waverpc.GetUnrollStatusResponse + 133, // 181: waverpc.DaemonService.ArmVHTLCRecovery:output_type -> waverpc.ArmVHTLCRecoveryResponse + 135, // 182: waverpc.DaemonService.EscalateVHTLCRecovery:output_type -> waverpc.EscalateVHTLCRecoveryResponse + 137, // 183: waverpc.DaemonService.CancelVHTLCRecovery:output_type -> waverpc.CancelVHTLCRecoveryResponse + 139, // 184: waverpc.DaemonService.GetVHTLCRecoveryStatus:output_type -> waverpc.GetVHTLCRecoveryStatusResponse + 141, // 185: waverpc.DaemonService.ListVHTLCRecoveries:output_type -> waverpc.ListVHTLCRecoveriesResponse + 144, // 186: waverpc.DaemonService.SignOutSwapHtlcAck:output_type -> waverpc.SignOutSwapHtlcAckResponse + 146, // 187: waverpc.DaemonService.SignCreditAccountAuthorization:output_type -> waverpc.SignCreditAccountAuthorizationResponse + 135, // [135:188] is the sub-list for method output_type + 82, // [82:135] is the sub-list for method input_type + 82, // [82:82] is the sub-list for extension type_name + 82, // [82:82] is the sub-list for extension extendee + 0, // [0:82] is the sub-list for field type_name } func init() { file_daemon_proto_init() } @@ -11634,20 +12412,20 @@ func file_daemon_proto_init() { (*Output_Pubkey)(nil), (*Output_PolicyTemplate)(nil), } - file_daemon_proto_msgTypes[50].OneofWrappers = []any{ + file_daemon_proto_msgTypes[62].OneofWrappers = []any{ (*RefreshVTXOsRequest_Outpoints)(nil), (*RefreshVTXOsRequest_All)(nil), } - file_daemon_proto_msgTypes[52].OneofWrappers = []any{} - file_daemon_proto_msgTypes[64].OneofWrappers = []any{ + file_daemon_proto_msgTypes[64].OneofWrappers = []any{} + file_daemon_proto_msgTypes[76].OneofWrappers = []any{ (*LeaveDestination_Address)(nil), (*LeaveDestination_PkScript)(nil), } - file_daemon_proto_msgTypes[65].OneofWrappers = []any{ + file_daemon_proto_msgTypes[77].OneofWrappers = []any{ (*LeaveVTXOsRequest_Outpoints)(nil), (*LeaveVTXOsRequest_All)(nil), } - file_daemon_proto_msgTypes[67].OneofWrappers = []any{ + file_daemon_proto_msgTypes[79].OneofWrappers = []any{ (*SendOnChainRequest_AmountSat)(nil), (*SendOnChainRequest_SweepAll)(nil), } @@ -11656,8 +12434,8 @@ func file_daemon_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_daemon_proto_rawDesc), len(file_daemon_proto_rawDesc)), - NumEnums: 11, - NumMessages: 124, + NumEnums: 12, + NumMessages: 136, NumExtensions: 0, NumServices: 1, }, diff --git a/waverpc/daemon.pb.gw.go b/waverpc/daemon.pb.gw.go index 05e2a312a..97cec55a3 100644 --- a/waverpc/daemon.pb.gw.go +++ b/waverpc/daemon.pb.gw.go @@ -440,6 +440,168 @@ func local_request_DaemonService_GetIndexedOORSessionByTxid_0(ctx context.Contex return msg, metadata, err } +func request_DaemonService_ExportOORRecoveryPackage_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ExportOORRecoveryPackageRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ExportOORRecoveryPackage(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_ExportOORRecoveryPackage_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ExportOORRecoveryPackageRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.ExportOORRecoveryPackage(ctx, &protoReq) + return msg, metadata, err +} + +func request_DaemonService_PrepareArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq PrepareArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.PrepareArkChannelOOR(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_PrepareArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq PrepareArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.PrepareArkChannelOOR(ctx, &protoReq) + return msg, metadata, err +} + +func request_DaemonService_LookupPreparedArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq LookupPreparedArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.LookupPreparedArkChannelOOR(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_LookupPreparedArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq LookupPreparedArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.LookupPreparedArkChannelOOR(ctx, &protoReq) + return msg, metadata, err +} + +func request_DaemonService_ValidatePreparedArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ValidatePreparedArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ValidatePreparedArkChannelOOR(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_ValidatePreparedArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ValidatePreparedArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.ValidatePreparedArkChannelOOR(ctx, &protoReq) + return msg, metadata, err +} + +func request_DaemonService_CommitPreparedArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq CommitPreparedArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.CommitPreparedArkChannelOOR(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_CommitPreparedArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq CommitPreparedArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.CommitPreparedArkChannelOOR(ctx, &protoReq) + return msg, metadata, err +} + +func request_DaemonService_AbortPreparedArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq AbortPreparedArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.AbortPreparedArkChannelOOR(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_AbortPreparedArkChannelOOR_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq AbortPreparedArkChannelOORRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.AbortPreparedArkChannelOOR(ctx, &protoReq) + return msg, metadata, err +} + func request_DaemonService_SendVTXO_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq SendVTXORequest @@ -1606,6 +1768,126 @@ func RegisterDaemonServiceHandlerServer(ctx context.Context, mux *runtime.ServeM } forward_DaemonService_GetIndexedOORSessionByTxid_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_DaemonService_ExportOORRecoveryPackage_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/waverpc.DaemonService/ExportOORRecoveryPackage", runtime.WithHTTPPathPattern("/v1/daemon/export-oor-recovery-package")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_ExportOORRecoveryPackage_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_ExportOORRecoveryPackage_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_PrepareArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/waverpc.DaemonService/PrepareArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/prepare-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_PrepareArkChannelOOR_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_PrepareArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_LookupPreparedArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/waverpc.DaemonService/LookupPreparedArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/lookup-prepared-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_LookupPreparedArkChannelOOR_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_LookupPreparedArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_ValidatePreparedArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/waverpc.DaemonService/ValidatePreparedArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/validate-prepared-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_ValidatePreparedArkChannelOOR_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_ValidatePreparedArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_CommitPreparedArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/waverpc.DaemonService/CommitPreparedArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/commit-prepared-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_CommitPreparedArkChannelOOR_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_CommitPreparedArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_AbortPreparedArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/waverpc.DaemonService/AbortPreparedArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/abort-prepared-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_AbortPreparedArkChannelOOR_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_AbortPreparedArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_DaemonService_SendVTXO_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2528,6 +2810,108 @@ func RegisterDaemonServiceHandlerClient(ctx context.Context, mux *runtime.ServeM } forward_DaemonService_GetIndexedOORSessionByTxid_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_DaemonService_ExportOORRecoveryPackage_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/waverpc.DaemonService/ExportOORRecoveryPackage", runtime.WithHTTPPathPattern("/v1/daemon/export-oor-recovery-package")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_ExportOORRecoveryPackage_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_ExportOORRecoveryPackage_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_PrepareArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/waverpc.DaemonService/PrepareArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/prepare-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_PrepareArkChannelOOR_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_PrepareArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_LookupPreparedArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/waverpc.DaemonService/LookupPreparedArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/lookup-prepared-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_LookupPreparedArkChannelOOR_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_LookupPreparedArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_ValidatePreparedArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/waverpc.DaemonService/ValidatePreparedArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/validate-prepared-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_ValidatePreparedArkChannelOOR_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_ValidatePreparedArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_CommitPreparedArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/waverpc.DaemonService/CommitPreparedArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/commit-prepared-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_CommitPreparedArkChannelOOR_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_CommitPreparedArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_AbortPreparedArkChannelOOR_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/waverpc.DaemonService/AbortPreparedArkChannelOOR", runtime.WithHTTPPathPattern("/v1/daemon/abort-prepared-ark-channel-oor")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_AbortPreparedArkChannelOOR_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_AbortPreparedArkChannelOOR_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_DaemonService_SendVTXO_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -3091,6 +3475,12 @@ var ( pattern_DaemonService_GetIndexedVTXOByPkScript_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "get-indexed-vtxo-by-pk-script"}, "")) pattern_DaemonService_GetVTXOExpiryInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "get-vtxo-expiry-info"}, "")) pattern_DaemonService_GetIndexedOORSessionByTxid_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "get-indexed-oor-session-by-txid"}, "")) + pattern_DaemonService_ExportOORRecoveryPackage_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "export-oor-recovery-package"}, "")) + pattern_DaemonService_PrepareArkChannelOOR_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "prepare-ark-channel-oor"}, "")) + pattern_DaemonService_LookupPreparedArkChannelOOR_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "lookup-prepared-ark-channel-oor"}, "")) + pattern_DaemonService_ValidatePreparedArkChannelOOR_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "validate-prepared-ark-channel-oor"}, "")) + pattern_DaemonService_CommitPreparedArkChannelOOR_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "commit-prepared-ark-channel-oor"}, "")) + pattern_DaemonService_AbortPreparedArkChannelOOR_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "abort-prepared-ark-channel-oor"}, "")) pattern_DaemonService_SendVTXO_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "send-vtxo"}, "")) pattern_DaemonService_SendOOR_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "send-oor"}, "")) pattern_DaemonService_PrepareOOR_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "prepare-oor"}, "")) @@ -3141,6 +3531,12 @@ var ( forward_DaemonService_GetIndexedVTXOByPkScript_0 = runtime.ForwardResponseMessage forward_DaemonService_GetVTXOExpiryInfo_0 = runtime.ForwardResponseMessage forward_DaemonService_GetIndexedOORSessionByTxid_0 = runtime.ForwardResponseMessage + forward_DaemonService_ExportOORRecoveryPackage_0 = runtime.ForwardResponseMessage + forward_DaemonService_PrepareArkChannelOOR_0 = runtime.ForwardResponseMessage + forward_DaemonService_LookupPreparedArkChannelOOR_0 = runtime.ForwardResponseMessage + forward_DaemonService_ValidatePreparedArkChannelOOR_0 = runtime.ForwardResponseMessage + forward_DaemonService_CommitPreparedArkChannelOOR_0 = runtime.ForwardResponseMessage + forward_DaemonService_AbortPreparedArkChannelOOR_0 = runtime.ForwardResponseMessage forward_DaemonService_SendVTXO_0 = runtime.ForwardResponseMessage forward_DaemonService_SendOOR_0 = runtime.ForwardResponseMessage forward_DaemonService_PrepareOOR_0 = runtime.ForwardResponseMessage diff --git a/waverpc/daemon.proto b/waverpc/daemon.proto index c95edb626..594bed14e 100644 --- a/waverpc/daemon.proto +++ b/waverpc/daemon.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package waverpc; +import "rpc/arkchannelrpc/ark_channel.proto"; + option go_package = "github.com/lightninglabs/wavelength/waverpc"; // DaemonService is the client daemon's own gRPC API. External tools such as @@ -79,6 +81,36 @@ service DaemonService { rpc GetIndexedOORSessionByTxid (GetIndexedOORSessionByTxidRequest) returns (GetIndexedOORSessionByTxidResponse); + // ExportOORRecoveryPackage returns the immutable local OOR package and + // round ancestry for one exact output. The caller must already know the + // output tuple; the daemon verifies it against its finalized artifacts. + rpc ExportOORRecoveryPackage (ExportOORRecoveryPackageRequest) + returns (ExportOORRecoveryPackageResponse); + + // PrepareArkChannelOOR reserves daemon-owned liquidity and builds the + // exact channel-policy output without releasing OOR signatures. + rpc PrepareArkChannelOOR (PrepareArkChannelOORRequest) + returns (PrepareArkChannelOORResponse); + + // LookupPreparedArkChannelOOR reconciles the deterministic channel OOR + // key without selecting or locking new wallet inputs. + rpc LookupPreparedArkChannelOOR (LookupPreparedArkChannelOORRequest) + returns (LookupPreparedArkChannelOORResponse); + + // ValidatePreparedArkChannelOOR verifies that a binding still names the + // exact prepared daemon OOR session. + rpc ValidatePreparedArkChannelOOR (ValidatePreparedArkChannelOORRequest) + returns (ValidatePreparedArkChannelOORResponse); + + // CommitPreparedArkChannelOOR releases the prepared OOR only after both + // lnd endpoints have persisted the fully signed channel backing. + rpc CommitPreparedArkChannelOOR (CommitPreparedArkChannelOORRequest) + returns (CommitPreparedArkChannelOORResponse); + + // AbortPreparedArkChannelOOR releases a pre-signing channel reservation. + rpc AbortPreparedArkChannelOOR (AbortPreparedArkChannelOORRequest) + returns (AbortPreparedArkChannelOORResponse); + // SendVTXO initiates an in-round transfer by submitting a refresh // request to the round coordinator. The transfer completes when the // next round commits. @@ -794,6 +826,11 @@ message NewReceiveScriptRequest { // prefix keys with an application or tenant identity when they share one // daemon. string idempotency_key = 2; + + // identity_key registers the daemon's durable identity key instead of + // deriving a fresh receive key. This is reserved for restart-stable + // protocol destinations such as Ark channel cooperative-close payouts. + bool identity_key = 3; } message NewReceiveScriptResponse { @@ -1145,6 +1182,76 @@ message PrepareOORResponse { string session_id = 4; } +message ExportOORRecoveryPackageRequest { + // source identifies one exact output in a sender-owned finalized OOR + // package. + arkchannelrpc.OORRecoverySource source = 1; +} + +message ExportOORRecoveryPackageResponse { + // recovery contains the complete endpoint-neutral source lineage. + arkchannelrpc.ChannelRecoveryPackage recovery = 1; +} + +message PrepareArkChannelOORRequest { + arkchannelrpc.ChannelTerms terms = 1; +} + +message PrepareArkChannelOORResponse { + arkchannelrpc.ChannelVTXOBinding binding = 1; +} + +enum ArkChannelOORPreparationStatus { + ARK_CHANNEL_OOR_PREPARATION_STATUS_UNSPECIFIED = 0; + ARK_CHANNEL_OOR_PREPARATION_STATUS_ABSENT = 1; + ARK_CHANNEL_OOR_PREPARATION_STATUS_PENDING = 2; + ARK_CHANNEL_OOR_PREPARATION_STATUS_PREPARED = 3; + ARK_CHANNEL_OOR_PREPARATION_STATUS_ACCEPTED = 4; +} + +message LookupPreparedArkChannelOORRequest { + arkchannelrpc.ChannelTerms terms = 1; +} + +message LookupPreparedArkChannelOORResponse { + ArkChannelOORPreparationStatus status = 1; + arkchannelrpc.ChannelVTXOBinding binding = 2; +} + +message ValidatePreparedArkChannelOORRequest { + arkchannelrpc.ChannelTerms terms = 1; + arkchannelrpc.ChannelVTXOBinding binding = 2; +} + +message ValidatePreparedArkChannelOORResponse { + bool valid = 1; +} + +message CommitPreparedArkChannelOORRequest { + bytes channel_id = 1; + arkchannelrpc.ChannelTerms terms = 2; + arkchannelrpc.ChannelVTXOBinding binding = 3; +} + +message CommitPreparedArkChannelOORResponse { + bool finalized = 1; + bool aborted = 2; + string reason = 3; +} + +message AbortPreparedArkChannelOORRequest { + bytes channel_id = 1; + arkchannelrpc.ChannelTerms terms = 2; + arkchannelrpc.ChannelVTXOBinding binding = 3; + string reason = 4; +} + +message AbortPreparedArkChannelOORResponse { + bool aborted = 1; + string reason = 2; + bool finalized = 3; +} + message SignOORCustomInputRequest { // custom_input describes the vHTLC/custom VTXO and selected spend path. CustomOORInput custom_input = 1; diff --git a/waverpc/daemon.yaml b/waverpc/daemon.yaml index 19014d99e..e1b5cb408 100644 --- a/waverpc/daemon.yaml +++ b/waverpc/daemon.yaml @@ -54,6 +54,24 @@ http: - selector: waverpc.DaemonService.GetIndexedOORSessionByTxid post: /v1/daemon/get-indexed-oor-session-by-txid body: "*" + - selector: waverpc.DaemonService.ExportOORRecoveryPackage + post: /v1/daemon/export-oor-recovery-package + body: "*" + - selector: waverpc.DaemonService.PrepareArkChannelOOR + post: /v1/daemon/prepare-ark-channel-oor + body: "*" + - selector: waverpc.DaemonService.LookupPreparedArkChannelOOR + post: /v1/daemon/lookup-prepared-ark-channel-oor + body: "*" + - selector: waverpc.DaemonService.ValidatePreparedArkChannelOOR + post: /v1/daemon/validate-prepared-ark-channel-oor + body: "*" + - selector: waverpc.DaemonService.CommitPreparedArkChannelOOR + post: /v1/daemon/commit-prepared-ark-channel-oor + body: "*" + - selector: waverpc.DaemonService.AbortPreparedArkChannelOOR + post: /v1/daemon/abort-prepared-ark-channel-oor + body: "*" - selector: waverpc.DaemonService.SendVTXO post: /v1/daemon/send-vtxo body: "*" diff --git a/waverpc/daemon_grpc.pb.go b/waverpc/daemon_grpc.pb.go index 918672a7f..685359033 100644 --- a/waverpc/daemon_grpc.pb.go +++ b/waverpc/daemon_grpc.pb.go @@ -34,6 +34,12 @@ const ( DaemonService_GetIndexedVTXOByPkScript_FullMethodName = "/waverpc.DaemonService/GetIndexedVTXOByPkScript" DaemonService_GetVTXOExpiryInfo_FullMethodName = "/waverpc.DaemonService/GetVTXOExpiryInfo" DaemonService_GetIndexedOORSessionByTxid_FullMethodName = "/waverpc.DaemonService/GetIndexedOORSessionByTxid" + DaemonService_ExportOORRecoveryPackage_FullMethodName = "/waverpc.DaemonService/ExportOORRecoveryPackage" + DaemonService_PrepareArkChannelOOR_FullMethodName = "/waverpc.DaemonService/PrepareArkChannelOOR" + DaemonService_LookupPreparedArkChannelOOR_FullMethodName = "/waverpc.DaemonService/LookupPreparedArkChannelOOR" + DaemonService_ValidatePreparedArkChannelOOR_FullMethodName = "/waverpc.DaemonService/ValidatePreparedArkChannelOOR" + DaemonService_CommitPreparedArkChannelOOR_FullMethodName = "/waverpc.DaemonService/CommitPreparedArkChannelOOR" + DaemonService_AbortPreparedArkChannelOOR_FullMethodName = "/waverpc.DaemonService/AbortPreparedArkChannelOOR" DaemonService_SendVTXO_FullMethodName = "/waverpc.DaemonService/SendVTXO" DaemonService_SendOOR_FullMethodName = "/waverpc.DaemonService/SendOOR" DaemonService_PrepareOOR_FullMethodName = "/waverpc.DaemonService/PrepareOOR" @@ -125,6 +131,24 @@ type DaemonServiceClient interface { // GetIndexedOORSessionByTxid queries the authoritative indexer for one // OOR session using a spent script proof and deterministic session txid. GetIndexedOORSessionByTxid(ctx context.Context, in *GetIndexedOORSessionByTxidRequest, opts ...grpc.CallOption) (*GetIndexedOORSessionByTxidResponse, error) + // ExportOORRecoveryPackage returns the immutable local OOR package and + // round ancestry for one exact output. The caller must already know the + // output tuple; the daemon verifies it against its finalized artifacts. + ExportOORRecoveryPackage(ctx context.Context, in *ExportOORRecoveryPackageRequest, opts ...grpc.CallOption) (*ExportOORRecoveryPackageResponse, error) + // PrepareArkChannelOOR reserves daemon-owned liquidity and builds the + // exact channel-policy output without releasing OOR signatures. + PrepareArkChannelOOR(ctx context.Context, in *PrepareArkChannelOORRequest, opts ...grpc.CallOption) (*PrepareArkChannelOORResponse, error) + // LookupPreparedArkChannelOOR reconciles the deterministic channel OOR + // key without selecting or locking new wallet inputs. + LookupPreparedArkChannelOOR(ctx context.Context, in *LookupPreparedArkChannelOORRequest, opts ...grpc.CallOption) (*LookupPreparedArkChannelOORResponse, error) + // ValidatePreparedArkChannelOOR verifies that a binding still names the + // exact prepared daemon OOR session. + ValidatePreparedArkChannelOOR(ctx context.Context, in *ValidatePreparedArkChannelOORRequest, opts ...grpc.CallOption) (*ValidatePreparedArkChannelOORResponse, error) + // CommitPreparedArkChannelOOR releases the prepared OOR only after both + // lnd endpoints have persisted the fully signed channel backing. + CommitPreparedArkChannelOOR(ctx context.Context, in *CommitPreparedArkChannelOORRequest, opts ...grpc.CallOption) (*CommitPreparedArkChannelOORResponse, error) + // AbortPreparedArkChannelOOR releases a pre-signing channel reservation. + AbortPreparedArkChannelOOR(ctx context.Context, in *AbortPreparedArkChannelOORRequest, opts ...grpc.CallOption) (*AbortPreparedArkChannelOORResponse, error) // SendVTXO initiates an in-round transfer by submitting a refresh // request to the round coordinator. The transfer completes when the // next round commits. @@ -426,6 +450,66 @@ func (c *daemonServiceClient) GetIndexedOORSessionByTxid(ctx context.Context, in return out, nil } +func (c *daemonServiceClient) ExportOORRecoveryPackage(ctx context.Context, in *ExportOORRecoveryPackageRequest, opts ...grpc.CallOption) (*ExportOORRecoveryPackageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ExportOORRecoveryPackageResponse) + err := c.cc.Invoke(ctx, DaemonService_ExportOORRecoveryPackage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *daemonServiceClient) PrepareArkChannelOOR(ctx context.Context, in *PrepareArkChannelOORRequest, opts ...grpc.CallOption) (*PrepareArkChannelOORResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PrepareArkChannelOORResponse) + err := c.cc.Invoke(ctx, DaemonService_PrepareArkChannelOOR_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *daemonServiceClient) LookupPreparedArkChannelOOR(ctx context.Context, in *LookupPreparedArkChannelOORRequest, opts ...grpc.CallOption) (*LookupPreparedArkChannelOORResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(LookupPreparedArkChannelOORResponse) + err := c.cc.Invoke(ctx, DaemonService_LookupPreparedArkChannelOOR_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *daemonServiceClient) ValidatePreparedArkChannelOOR(ctx context.Context, in *ValidatePreparedArkChannelOORRequest, opts ...grpc.CallOption) (*ValidatePreparedArkChannelOORResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ValidatePreparedArkChannelOORResponse) + err := c.cc.Invoke(ctx, DaemonService_ValidatePreparedArkChannelOOR_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *daemonServiceClient) CommitPreparedArkChannelOOR(ctx context.Context, in *CommitPreparedArkChannelOORRequest, opts ...grpc.CallOption) (*CommitPreparedArkChannelOORResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CommitPreparedArkChannelOORResponse) + err := c.cc.Invoke(ctx, DaemonService_CommitPreparedArkChannelOOR_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *daemonServiceClient) AbortPreparedArkChannelOOR(ctx context.Context, in *AbortPreparedArkChannelOORRequest, opts ...grpc.CallOption) (*AbortPreparedArkChannelOORResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AbortPreparedArkChannelOORResponse) + err := c.cc.Invoke(ctx, DaemonService_AbortPreparedArkChannelOOR_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *daemonServiceClient) SendVTXO(ctx context.Context, in *SendVTXORequest, opts ...grpc.CallOption) (*SendVTXOResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(SendVTXOResponse) @@ -812,6 +896,24 @@ type DaemonServiceServer interface { // GetIndexedOORSessionByTxid queries the authoritative indexer for one // OOR session using a spent script proof and deterministic session txid. GetIndexedOORSessionByTxid(context.Context, *GetIndexedOORSessionByTxidRequest) (*GetIndexedOORSessionByTxidResponse, error) + // ExportOORRecoveryPackage returns the immutable local OOR package and + // round ancestry for one exact output. The caller must already know the + // output tuple; the daemon verifies it against its finalized artifacts. + ExportOORRecoveryPackage(context.Context, *ExportOORRecoveryPackageRequest) (*ExportOORRecoveryPackageResponse, error) + // PrepareArkChannelOOR reserves daemon-owned liquidity and builds the + // exact channel-policy output without releasing OOR signatures. + PrepareArkChannelOOR(context.Context, *PrepareArkChannelOORRequest) (*PrepareArkChannelOORResponse, error) + // LookupPreparedArkChannelOOR reconciles the deterministic channel OOR + // key without selecting or locking new wallet inputs. + LookupPreparedArkChannelOOR(context.Context, *LookupPreparedArkChannelOORRequest) (*LookupPreparedArkChannelOORResponse, error) + // ValidatePreparedArkChannelOOR verifies that a binding still names the + // exact prepared daemon OOR session. + ValidatePreparedArkChannelOOR(context.Context, *ValidatePreparedArkChannelOORRequest) (*ValidatePreparedArkChannelOORResponse, error) + // CommitPreparedArkChannelOOR releases the prepared OOR only after both + // lnd endpoints have persisted the fully signed channel backing. + CommitPreparedArkChannelOOR(context.Context, *CommitPreparedArkChannelOORRequest) (*CommitPreparedArkChannelOORResponse, error) + // AbortPreparedArkChannelOOR releases a pre-signing channel reservation. + AbortPreparedArkChannelOOR(context.Context, *AbortPreparedArkChannelOORRequest) (*AbortPreparedArkChannelOORResponse, error) // SendVTXO initiates an in-round transfer by submitting a refresh // request to the round coordinator. The transfer completes when the // next round commits. @@ -1008,6 +1110,24 @@ func (UnimplementedDaemonServiceServer) GetVTXOExpiryInfo(context.Context, *GetV func (UnimplementedDaemonServiceServer) GetIndexedOORSessionByTxid(context.Context, *GetIndexedOORSessionByTxidRequest) (*GetIndexedOORSessionByTxidResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetIndexedOORSessionByTxid not implemented") } +func (UnimplementedDaemonServiceServer) ExportOORRecoveryPackage(context.Context, *ExportOORRecoveryPackageRequest) (*ExportOORRecoveryPackageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ExportOORRecoveryPackage not implemented") +} +func (UnimplementedDaemonServiceServer) PrepareArkChannelOOR(context.Context, *PrepareArkChannelOORRequest) (*PrepareArkChannelOORResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PrepareArkChannelOOR not implemented") +} +func (UnimplementedDaemonServiceServer) LookupPreparedArkChannelOOR(context.Context, *LookupPreparedArkChannelOORRequest) (*LookupPreparedArkChannelOORResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LookupPreparedArkChannelOOR not implemented") +} +func (UnimplementedDaemonServiceServer) ValidatePreparedArkChannelOOR(context.Context, *ValidatePreparedArkChannelOORRequest) (*ValidatePreparedArkChannelOORResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValidatePreparedArkChannelOOR not implemented") +} +func (UnimplementedDaemonServiceServer) CommitPreparedArkChannelOOR(context.Context, *CommitPreparedArkChannelOORRequest) (*CommitPreparedArkChannelOORResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CommitPreparedArkChannelOOR not implemented") +} +func (UnimplementedDaemonServiceServer) AbortPreparedArkChannelOOR(context.Context, *AbortPreparedArkChannelOORRequest) (*AbortPreparedArkChannelOORResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AbortPreparedArkChannelOOR not implemented") +} func (UnimplementedDaemonServiceServer) SendVTXO(context.Context, *SendVTXORequest) (*SendVTXOResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SendVTXO not implemented") } @@ -1395,6 +1515,114 @@ func _DaemonService_GetIndexedOORSessionByTxid_Handler(srv interface{}, ctx cont return interceptor(ctx, in, info, handler) } +func _DaemonService_ExportOORRecoveryPackage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExportOORRecoveryPackageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).ExportOORRecoveryPackage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_ExportOORRecoveryPackage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).ExportOORRecoveryPackage(ctx, req.(*ExportOORRecoveryPackageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DaemonService_PrepareArkChannelOOR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PrepareArkChannelOORRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).PrepareArkChannelOOR(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_PrepareArkChannelOOR_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).PrepareArkChannelOOR(ctx, req.(*PrepareArkChannelOORRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DaemonService_LookupPreparedArkChannelOOR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupPreparedArkChannelOORRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).LookupPreparedArkChannelOOR(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_LookupPreparedArkChannelOOR_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).LookupPreparedArkChannelOOR(ctx, req.(*LookupPreparedArkChannelOORRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DaemonService_ValidatePreparedArkChannelOOR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidatePreparedArkChannelOORRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).ValidatePreparedArkChannelOOR(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_ValidatePreparedArkChannelOOR_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).ValidatePreparedArkChannelOOR(ctx, req.(*ValidatePreparedArkChannelOORRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DaemonService_CommitPreparedArkChannelOOR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CommitPreparedArkChannelOORRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).CommitPreparedArkChannelOOR(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_CommitPreparedArkChannelOOR_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).CommitPreparedArkChannelOOR(ctx, req.(*CommitPreparedArkChannelOORRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DaemonService_AbortPreparedArkChannelOOR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AbortPreparedArkChannelOORRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).AbortPreparedArkChannelOOR(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_AbortPreparedArkChannelOOR_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).AbortPreparedArkChannelOOR(ctx, req.(*AbortPreparedArkChannelOORRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _DaemonService_SendVTXO_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SendVTXORequest) if err := dec(in); err != nil { @@ -2031,6 +2259,30 @@ var DaemonService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetIndexedOORSessionByTxid", Handler: _DaemonService_GetIndexedOORSessionByTxid_Handler, }, + { + MethodName: "ExportOORRecoveryPackage", + Handler: _DaemonService_ExportOORRecoveryPackage_Handler, + }, + { + MethodName: "PrepareArkChannelOOR", + Handler: _DaemonService_PrepareArkChannelOOR_Handler, + }, + { + MethodName: "LookupPreparedArkChannelOOR", + Handler: _DaemonService_LookupPreparedArkChannelOOR_Handler, + }, + { + MethodName: "ValidatePreparedArkChannelOOR", + Handler: _DaemonService_ValidatePreparedArkChannelOOR_Handler, + }, + { + MethodName: "CommitPreparedArkChannelOOR", + Handler: _DaemonService_CommitPreparedArkChannelOOR_Handler, + }, + { + MethodName: "AbortPreparedArkChannelOOR", + Handler: _DaemonService_AbortPreparedArkChannelOOR_Handler, + }, { MethodName: "SendVTXO", Handler: _DaemonService_SendVTXO_Handler, diff --git a/waverpc/daemon_mailboxrpc.pb.go b/waverpc/daemon_mailboxrpc.pb.go index f719f04a9..e3cd4fc4c 100644 --- a/waverpc/daemon_mailboxrpc.pb.go +++ b/waverpc/daemon_mailboxrpc.pb.go @@ -54,6 +54,18 @@ type DaemonServiceMailboxServer interface { GetVTXOExpiryInfo(ctx context.Context, req *GetVTXOExpiryInfoRequest) (*GetVTXOExpiryInfoResponse, error) // GetIndexedOORSessionByTxid handles GetIndexedOORSessionByTxid. GetIndexedOORSessionByTxid(ctx context.Context, req *GetIndexedOORSessionByTxidRequest) (*GetIndexedOORSessionByTxidResponse, error) + // ExportOORRecoveryPackage handles ExportOORRecoveryPackage. + ExportOORRecoveryPackage(ctx context.Context, req *ExportOORRecoveryPackageRequest) (*ExportOORRecoveryPackageResponse, error) + // PrepareArkChannelOOR handles PrepareArkChannelOOR. + PrepareArkChannelOOR(ctx context.Context, req *PrepareArkChannelOORRequest) (*PrepareArkChannelOORResponse, error) + // LookupPreparedArkChannelOOR handles LookupPreparedArkChannelOOR. + LookupPreparedArkChannelOOR(ctx context.Context, req *LookupPreparedArkChannelOORRequest) (*LookupPreparedArkChannelOORResponse, error) + // ValidatePreparedArkChannelOOR handles ValidatePreparedArkChannelOOR. + ValidatePreparedArkChannelOOR(ctx context.Context, req *ValidatePreparedArkChannelOORRequest) (*ValidatePreparedArkChannelOORResponse, error) + // CommitPreparedArkChannelOOR handles CommitPreparedArkChannelOOR. + CommitPreparedArkChannelOOR(ctx context.Context, req *CommitPreparedArkChannelOORRequest) (*CommitPreparedArkChannelOORResponse, error) + // AbortPreparedArkChannelOOR handles AbortPreparedArkChannelOOR. + AbortPreparedArkChannelOOR(ctx context.Context, req *AbortPreparedArkChannelOORRequest) (*AbortPreparedArkChannelOORResponse, error) // SendVTXO handles SendVTXO. SendVTXO(ctx context.Context, req *SendVTXORequest) (*SendVTXOResponse, error) // SendOOR handles SendOOR. @@ -272,6 +284,66 @@ func RegisterDaemonServiceMailboxServer(r rpc.Router, impl DaemonServiceMailboxS return impl.GetIndexedOORSessionByTxid(ctx, req) }) + r.Handle("waverpc.DaemonService", "ExportOORRecoveryPackage", func() proto.Message { + return &ExportOORRecoveryPackageRequest{} + }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { + req, ok := msg.(*ExportOORRecoveryPackageRequest) + if !ok { + return nil, fmt.Errorf("unexpected request type: %T", msg) + } + + return impl.ExportOORRecoveryPackage(ctx, req) + }) + r.Handle("waverpc.DaemonService", "PrepareArkChannelOOR", func() proto.Message { + return &PrepareArkChannelOORRequest{} + }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { + req, ok := msg.(*PrepareArkChannelOORRequest) + if !ok { + return nil, fmt.Errorf("unexpected request type: %T", msg) + } + + return impl.PrepareArkChannelOOR(ctx, req) + }) + r.Handle("waverpc.DaemonService", "LookupPreparedArkChannelOOR", func() proto.Message { + return &LookupPreparedArkChannelOORRequest{} + }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { + req, ok := msg.(*LookupPreparedArkChannelOORRequest) + if !ok { + return nil, fmt.Errorf("unexpected request type: %T", msg) + } + + return impl.LookupPreparedArkChannelOOR(ctx, req) + }) + r.Handle("waverpc.DaemonService", "ValidatePreparedArkChannelOOR", func() proto.Message { + return &ValidatePreparedArkChannelOORRequest{} + }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { + req, ok := msg.(*ValidatePreparedArkChannelOORRequest) + if !ok { + return nil, fmt.Errorf("unexpected request type: %T", msg) + } + + return impl.ValidatePreparedArkChannelOOR(ctx, req) + }) + r.Handle("waverpc.DaemonService", "CommitPreparedArkChannelOOR", func() proto.Message { + return &CommitPreparedArkChannelOORRequest{} + }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { + req, ok := msg.(*CommitPreparedArkChannelOORRequest) + if !ok { + return nil, fmt.Errorf("unexpected request type: %T", msg) + } + + return impl.CommitPreparedArkChannelOOR(ctx, req) + }) + r.Handle("waverpc.DaemonService", "AbortPreparedArkChannelOOR", func() proto.Message { + return &AbortPreparedArkChannelOORRequest{} + }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { + req, ok := msg.(*AbortPreparedArkChannelOORRequest) + if !ok { + return nil, fmt.Errorf("unexpected request type: %T", msg) + } + + return impl.AbortPreparedArkChannelOOR(ctx, req) + }) r.Handle("waverpc.DaemonService", "SendVTXO", func() proto.Message { return &SendVTXORequest{} }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { @@ -939,6 +1011,144 @@ func (c *DaemonServiceMailboxClient) GetIndexedOORSessionByTxid(ctx context.Cont return resp, nil } +// ExportOORRecoveryPackage calls the ExportOORRecoveryPackage RPC. +func (c *DaemonServiceMailboxClient) ExportOORRecoveryPackage(ctx context.Context, req *ExportOORRecoveryPackageRequest, opts ...rpc.RPCOptions) (*ExportOORRecoveryPackageResponse, error) { + var opt rpc.RPCOptions + if len(opts) > 0 { + opt = opts[0] + } + + result, err := c.C.SendRPC(ctx, rpc.ServiceMethod{ + Service: "waverpc.DaemonService", + Method: "ExportOORRecoveryPackage", + }, req, opt) + if err != nil { + return nil, err + } + + resp := new(ExportOORRecoveryPackageResponse) + if err := c.C.AwaitRPC(ctx, result.CorrelationID, resp); err != nil { + return nil, err + } + + return resp, nil +} + +// PrepareArkChannelOOR calls the PrepareArkChannelOOR RPC. +func (c *DaemonServiceMailboxClient) PrepareArkChannelOOR(ctx context.Context, req *PrepareArkChannelOORRequest, opts ...rpc.RPCOptions) (*PrepareArkChannelOORResponse, error) { + var opt rpc.RPCOptions + if len(opts) > 0 { + opt = opts[0] + } + + result, err := c.C.SendRPC(ctx, rpc.ServiceMethod{ + Service: "waverpc.DaemonService", + Method: "PrepareArkChannelOOR", + }, req, opt) + if err != nil { + return nil, err + } + + resp := new(PrepareArkChannelOORResponse) + if err := c.C.AwaitRPC(ctx, result.CorrelationID, resp); err != nil { + return nil, err + } + + return resp, nil +} + +// LookupPreparedArkChannelOOR calls the LookupPreparedArkChannelOOR RPC. +func (c *DaemonServiceMailboxClient) LookupPreparedArkChannelOOR(ctx context.Context, req *LookupPreparedArkChannelOORRequest, opts ...rpc.RPCOptions) (*LookupPreparedArkChannelOORResponse, error) { + var opt rpc.RPCOptions + if len(opts) > 0 { + opt = opts[0] + } + + result, err := c.C.SendRPC(ctx, rpc.ServiceMethod{ + Service: "waverpc.DaemonService", + Method: "LookupPreparedArkChannelOOR", + }, req, opt) + if err != nil { + return nil, err + } + + resp := new(LookupPreparedArkChannelOORResponse) + if err := c.C.AwaitRPC(ctx, result.CorrelationID, resp); err != nil { + return nil, err + } + + return resp, nil +} + +// ValidatePreparedArkChannelOOR calls the ValidatePreparedArkChannelOOR RPC. +func (c *DaemonServiceMailboxClient) ValidatePreparedArkChannelOOR(ctx context.Context, req *ValidatePreparedArkChannelOORRequest, opts ...rpc.RPCOptions) (*ValidatePreparedArkChannelOORResponse, error) { + var opt rpc.RPCOptions + if len(opts) > 0 { + opt = opts[0] + } + + result, err := c.C.SendRPC(ctx, rpc.ServiceMethod{ + Service: "waverpc.DaemonService", + Method: "ValidatePreparedArkChannelOOR", + }, req, opt) + if err != nil { + return nil, err + } + + resp := new(ValidatePreparedArkChannelOORResponse) + if err := c.C.AwaitRPC(ctx, result.CorrelationID, resp); err != nil { + return nil, err + } + + return resp, nil +} + +// CommitPreparedArkChannelOOR calls the CommitPreparedArkChannelOOR RPC. +func (c *DaemonServiceMailboxClient) CommitPreparedArkChannelOOR(ctx context.Context, req *CommitPreparedArkChannelOORRequest, opts ...rpc.RPCOptions) (*CommitPreparedArkChannelOORResponse, error) { + var opt rpc.RPCOptions + if len(opts) > 0 { + opt = opts[0] + } + + result, err := c.C.SendRPC(ctx, rpc.ServiceMethod{ + Service: "waverpc.DaemonService", + Method: "CommitPreparedArkChannelOOR", + }, req, opt) + if err != nil { + return nil, err + } + + resp := new(CommitPreparedArkChannelOORResponse) + if err := c.C.AwaitRPC(ctx, result.CorrelationID, resp); err != nil { + return nil, err + } + + return resp, nil +} + +// AbortPreparedArkChannelOOR calls the AbortPreparedArkChannelOOR RPC. +func (c *DaemonServiceMailboxClient) AbortPreparedArkChannelOOR(ctx context.Context, req *AbortPreparedArkChannelOORRequest, opts ...rpc.RPCOptions) (*AbortPreparedArkChannelOORResponse, error) { + var opt rpc.RPCOptions + if len(opts) > 0 { + opt = opts[0] + } + + result, err := c.C.SendRPC(ctx, rpc.ServiceMethod{ + Service: "waverpc.DaemonService", + Method: "AbortPreparedArkChannelOOR", + }, req, opt) + if err != nil { + return nil, err + } + + resp := new(AbortPreparedArkChannelOORResponse) + if err := c.C.AwaitRPC(ctx, result.CorrelationID, resp); err != nil { + return nil, err + } + + return resp, nil +} + // SendVTXO calls the SendVTXO RPC. func (c *DaemonServiceMailboxClient) SendVTXO(ctx context.Context, req *SendVTXORequest, opts ...rpc.RPCOptions) (*SendVTXOResponse, error) { var opt rpc.RPCOptions